Bug 792207 - Part 4: Add Azure recording code. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Mon, 24 Sep 2012 15:02:50 +0000
changeset 108022 ed2e2da7d09890078d98b08d64b57c21de4b56a6
parent 108021 68876e7d17ead33803e918541794d829d40d9f18
child 108023 ee2e60a3093430208d734ad3851c1236be5532e0
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersjrmuizel
bugs792207
milestone18.0a1
Bug 792207 - Part 4: Add Azure recording code. r=jrmuizel
gfx/2d/2D.h
gfx/2d/DrawEventRecorder.cpp
gfx/2d/DrawEventRecorder.h
gfx/2d/DrawEventRecorder.h.rej
gfx/2d/DrawTargetRecording.cpp
gfx/2d/DrawTargetRecording.h
gfx/2d/Makefile.in
gfx/2d/PathRecording.cpp
gfx/2d/PathRecording.h
gfx/2d/RecordedEvent.cpp
gfx/2d/RecordedEvent.h
gfx/2d/RecordingTypes.h
gfx/2d/Types.h
gfx/2d/gfx2d.vcxproj
gfx/thebes/gfxPlatform.h
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -828,16 +828,22 @@ protected:
   Matrix mTransform;
   IntRect mOpaqueRect;
   bool mTransformDirty : 1;
   bool mPermitSubpixelAA : 1;
 
   SurfaceFormat mFormat;
 };
 
+class DrawEventRecorder : public RefCounted<DrawEventRecorder>
+{
+public:
+  virtual ~DrawEventRecorder() { }
+};
+
 class GFX2D_API Factory
 {
 public:
   static bool HasSSE2();
 
   static TemporaryRef<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize);
 
   static TemporaryRef<DrawTarget>
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DrawEventRecorder.cpp
@@ -0,0 +1,54 @@
+/* -*- 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 "DrawEventRecorder.h"
+#include "PathRecording.h"
+
+namespace mozilla {
+namespace gfx {
+
+using namespace std;
+
+const uint32_t kMagicInt = 0xc001feed;
+
+DrawEventRecorderPrivate::DrawEventRecorderPrivate(std::ostream *aStream)
+  : mOutputStream(aStream)
+{
+}
+
+void
+DrawEventRecorderPrivate::RecordEvent(const RecordedEvent &aEvent)
+{
+  WriteElement(*mOutputStream, aEvent.mType);
+
+  aEvent.RecordToStream(*mOutputStream);
+
+  Flush();
+}
+
+DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename)
+  : DrawEventRecorderPrivate(NULL) 
+  , mOutputFile(aFilename, ofstream::binary)
+{
+  mOutputStream = &mOutputFile;
+
+  WriteElement(*mOutputStream, kMagicInt);
+  WriteElement(*mOutputStream, kMajorRevision);
+  WriteElement(*mOutputStream, kMinorRevision);
+}
+
+DrawEventRecorderFile::~DrawEventRecorderFile()
+{
+  mOutputFile.close();
+}
+
+void
+DrawEventRecorderFile::Flush()
+{
+  mOutputFile.flush();
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DrawEventRecorder.h
@@ -0,0 +1,79 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_DRAWEVENTRECORDER_H_
+#define MOZILLA_GFX_DRAWEVENTRECORDER_H_
+
+#include "2D.h"
+#include "RecordedEvent.h"
+#include <ostream>
+#include <fstream>
+
+#if defined(_MSC_VER)
+#include <hash_set>
+#else
+#include <set>
+#endif
+
+namespace mozilla {
+namespace gfx {
+
+class PathRecording;
+
+class DrawEventRecorderPrivate : public DrawEventRecorder
+{
+public:
+  DrawEventRecorderPrivate(std::ostream *aStream);
+  virtual ~DrawEventRecorderPrivate() { }
+
+  void RecordEvent(const RecordedEvent &aEvent);
+  void WritePath(const PathRecording *aPath);
+
+  void AddStoredPath(const ReferencePtr aPath) {
+    mStoredPaths.insert(aPath);
+  }
+
+  void RemoveStoredPath(const ReferencePtr aPath) {
+    mStoredPaths.erase(aPath);
+  }
+
+  bool HasStoredPath(const ReferencePtr aPath) {
+    if (mStoredPaths.find(aPath) != mStoredPaths.end()) {
+      return true;
+    }
+    return false;
+  }
+
+protected:
+  std::ostream *mOutputStream;
+
+  virtual void Flush() = 0;
+
+#if defined(_MSC_VER)
+  typedef stdext::hash_set<const void*> ObjectSet;
+#else
+  typedef std::set<const void*> ObjectSet;
+#endif
+
+  ObjectSet mStoredPaths;
+  ObjectSet mStoredScaledFonts;
+};
+
+class DrawEventRecorderFile : public DrawEventRecorderPrivate
+{
+public:
+  DrawEventRecorderFile(const char *aFilename);
+  ~DrawEventRecorderFile();
+
+private:
+  virtual void Flush();
+
+  std::ofstream mOutputFile;
+};
+
+}
+}
+
+#endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DrawEventRecorder.h.rej
@@ -0,0 +1,61 @@
+--- DrawEventRecorder.h
++++ DrawEventRecorder.h
+@@ -6,34 +6,20 @@
+ #ifndef MOZILLA_GFX_DRAWEVENTRECORDER_H_
+ #define MOZILLA_GFX_DRAWEVENTRECORDER_H_
+ 
+ #include "2D.h"
+ #include "RecordedEvent.h"
+ #include <ostream>
+ #include <fstream>
+ 
+-#if defined(_MSC_VER) || defined(MOZ_WIDGET_ANDROID)
++#if defined(_MSC_VER)
+ #include <hash_set>
+ #else
+-#include <ext/hash_set>
+-#endif
+-
+-#ifndef _MSC_VER
+-#ifndef MOZ_WIDGET_ANDROID
+-namespace __gnu_cxx {
+-#endif
+-template<>
+-struct hash<void *> {
+-  size_t operator()(const void * __x) const {
+-    return reinterpret_cast<size_t>(__x); }
+-};
+-#ifndef MOZ_WIDGET_ANDROID
+-}
+-#endif
++#include <unordered_set>
+ #endif
+ 
+ namespace mozilla {
+ namespace gfx {
+ 
+ class PathRecording;
+ 
+ class DrawEventRecorderPrivate : public DrawEventRecorder
+@@ -62,20 +48,18 @@ public:
+ 
+ protected:
+   std::ostream *mOutputStream;
+ 
+   virtual void Flush() = 0;
+ 
+ #if defined(_MSC_VER)
+   typedef stdext::hash_set<const void*> ObjectSet;
+-#elif defined(MOZ_WIDGET_ANDROID)
+-  typedef hash_set<const void*> ObjectSet;
+ #else
+-  typedef __gnu_cxx::hash_set<const void*, __gnu_cxx::hash<void*> > ObjectSet;
++  typedef std::unordered_set<const void*> ObjectSet;
+ #endif
+ 
+   ObjectSet mStoredPaths;
+   ObjectSet mStoredScaledFonts;
+ };
+ 
+ class DrawEventRecorderFile : public DrawEventRecorderPrivate
+ {
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -0,0 +1,468 @@
+/* -*- 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 "DrawTargetRecording.h"
+#include "PathRecording.h"
+#include <stdio.h>
+
+#include "Logging.h"
+#include "Tools.h"
+
+namespace mozilla {
+namespace gfx {
+
+class SourceSurfaceRecording : public SourceSurface
+{
+public:
+  SourceSurfaceRecording(SourceSurface *aFinalSurface, DrawEventRecorderPrivate *aRecorder)
+    : mFinalSurface(aFinalSurface), mRecorder(aRecorder)
+  {
+  }
+
+  ~SourceSurfaceRecording()
+  {
+    mRecorder->RecordEvent(RecordedSourceSurfaceDestruction(this));
+  }
+
+  virtual SurfaceType GetType() const { return SURFACE_RECORDING; }
+  virtual IntSize GetSize() const { return mFinalSurface->GetSize(); }
+  virtual SurfaceFormat GetFormat() const { return mFinalSurface->GetFormat(); }
+  virtual TemporaryRef<DataSourceSurface> GetDataSurface() { return mFinalSurface->GetDataSurface(); }
+
+  RefPtr<SourceSurface> mFinalSurface;
+  RefPtr<DrawEventRecorderPrivate> mRecorder;
+};
+
+class GradientStopsRecording : public GradientStops
+{
+public:
+  GradientStopsRecording(GradientStops *aFinalGradientStops, DrawEventRecorderPrivate *aRecorder)
+    : mFinalGradientStops(aFinalGradientStops), mRecorder(aRecorder)
+  {
+  }
+
+  ~GradientStopsRecording()
+  {
+    mRecorder->RecordEvent(RecordedGradientStopsDestruction(this));
+  }
+
+  virtual BackendType GetBackendType() const { return BACKEND_RECORDING; }
+
+  RefPtr<GradientStops> mFinalGradientStops;
+  RefPtr<DrawEventRecorderPrivate> mRecorder;
+};
+
+static SourceSurface *
+GetSourceSurface(SourceSurface *aSurface)
+{
+  if (aSurface->GetType() != SURFACE_RECORDING) {
+    return aSurface;
+  }
+
+  return static_cast<SourceSurfaceRecording*>(aSurface)->mFinalSurface;
+}
+
+static GradientStops *
+GetGradientStops(GradientStops *aStops)
+{
+  if (aStops->GetBackendType() != BACKEND_RECORDING) {
+    return aStops;
+  }
+
+  return static_cast<GradientStopsRecording*>(aStops)->mFinalGradientStops;
+}
+
+struct AdjustedPattern
+{
+  AdjustedPattern(const Pattern &aPattern)
+    : mPattern(NULL)
+  {
+    mOrigPattern = const_cast<Pattern*>(&aPattern);
+  }
+
+  ~AdjustedPattern() {
+    if (mPattern) {
+      mPattern->~Pattern();
+    }
+  }
+
+  operator Pattern*()
+  {
+    switch(mOrigPattern->GetType()) {
+    case PATTERN_COLOR:
+      return mOrigPattern;
+    case PATTERN_SURFACE:
+      {
+        SurfacePattern *surfPat = static_cast<SurfacePattern*>(mOrigPattern);
+        mPattern =
+          new (mSurfPat) SurfacePattern(GetSourceSurface(surfPat->mSurface),
+                                        surfPat->mExtendMode, surfPat->mMatrix,
+                                        surfPat->mFilter);
+        return mPattern;
+      }
+    case PATTERN_LINEAR_GRADIENT:
+      {
+        LinearGradientPattern *linGradPat = static_cast<LinearGradientPattern*>(mOrigPattern);
+        mPattern =
+          new (mLinGradPat) LinearGradientPattern(linGradPat->mBegin, linGradPat->mEnd,
+                                                  GetGradientStops(linGradPat->mStops),
+                                                  linGradPat->mMatrix);
+        return mPattern;
+      }
+    case PATTERN_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)
+  : mRecorder(static_cast<DrawEventRecorderPrivate*>(aRecorder))
+  , mFinalDT(aDT)
+{
+  mRecorder->RecordEvent(RecordedDrawTargetCreation(this, mFinalDT->GetType(), 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)
+{
+  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)
+{
+  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)
+{
+  mRecorder->RecordEvent(RecordedStrokeLine(this, aBegin, aEnd, aPattern, aStrokeOptions, aOptions));
+  mFinalDT->StrokeLine(aBegin, aEnd, *AdjustedPattern(aPattern), aStrokeOptions, aOptions);
+}
+
+Path*
+DrawTargetRecording::GetPathForPathRecording(const Path *aPath) const
+{
+  if (aPath->GetBackendType() != BACKEND_RECORDING) {
+    return NULL;
+  }
+
+  return static_cast<const PathRecording*>(aPath)->mPath;
+}
+
+void
+DrawTargetRecording::Fill(const Path *aPath,
+                          const Pattern &aPattern,
+                          const DrawOptions &aOptions)
+{
+  EnsureStored(aPath);
+
+  mRecorder->RecordEvent(RecordedFill(this, const_cast<Path*>(aPath), aPattern, aOptions));
+  mFinalDT->Fill(GetPathForPathRecording(aPath), *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)
+{
+  if (!aFont->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))) {
+    mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, aFont));
+    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, aPattern, aOptions, aRenderingOptions);
+}
+
+void
+DrawTargetRecording::Mask(const Pattern &aSource,
+                          const Pattern &aMask,
+                          const DrawOptions &aOptions)
+{
+  mRecorder->RecordEvent(RecordedMask(this, aSource, aMask, aOptions));
+  mFinalDT->Mask(*AdjustedPattern(aSource), *AdjustedPattern(aMask), aOptions);
+}
+
+void
+DrawTargetRecording::Stroke(const Path *aPath,
+                            const Pattern &aPattern,
+                            const StrokeOptions &aStrokeOptions,
+                            const DrawOptions &aOptions)
+{
+  EnsureStored(aPath);
+
+  mRecorder->RecordEvent(RecordedStroke(this, const_cast<Path*>(aPath), aPattern, aStrokeOptions, aOptions));
+  mFinalDT->Stroke(GetPathForPathRecording(aPath), *AdjustedPattern(aPattern), aStrokeOptions, aOptions);
+}
+
+TemporaryRef<SourceSurface>
+DrawTargetRecording::Snapshot()
+{
+  RefPtr<SourceSurface> surf = mFinalDT->Snapshot();
+
+  RefPtr<SourceSurface> retSurf = new SourceSurfaceRecording(surf, mRecorder);
+
+  mRecorder->RecordEvent(RecordedSnapshot(retSurf, this));
+
+  return retSurf;
+}
+
+void
+DrawTargetRecording::DrawSurface(SourceSurface *aSurface,
+                                 const Rect &aDest,
+                                 const Rect &aSource,
+                                 const DrawSurfaceOptions &aSurfOptions,
+                                 const DrawOptions &aOptions)
+{
+  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)
+{
+  mRecorder->RecordEvent(RecordedDrawSurfaceWithShadow(this, aSurface, aDest, aColor, aOffset, aSigma, aOp));
+  mFinalDT->DrawSurfaceWithShadow(GetSourceSurface(aSurface), aDest, aColor, aOffset, aSigma, aOp);
+}
+
+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)
+{
+  mRecorder->RecordEvent(RecordedCopySurface(this, aSurface, aSourceRect, aDestination));
+  mFinalDT->CopySurface(GetSourceSurface(aSurface), aSourceRect, aDestination);
+}
+
+void
+DrawTargetRecording::PushClip(const Path *aPath)
+{
+  EnsureStored(aPath);
+
+  mRecorder->RecordEvent(RecordedPushClip(this, const_cast<Path*>(aPath)));
+  mFinalDT->PushClip(GetPathForPathRecording(aPath));
+}
+
+void
+DrawTargetRecording::PushClipRect(const Rect &aRect)
+{
+  mRecorder->RecordEvent(RecordedPushClipRect(this, aRect));
+  mFinalDT->PushClipRect(aRect);
+}
+
+void
+DrawTargetRecording::PopClip()
+{
+  mRecorder->RecordEvent(RecordedPopClip(this));
+  mFinalDT->PopClip();
+}
+
+TemporaryRef<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;
+}
+
+TemporaryRef<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();
+  }
+
+  if (!dataSurf) {
+    gfxWarning() << "Recording failed to record SourceSurface created from OptimizeSourceSurface";
+    // Insert a bogus source surface.
+    uint8_t *sourceData = new uint8_t[surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat())];
+    memset(sourceData, 0, surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat()));
+    mRecorder->RecordEvent(
+      RecordedSourceSurfaceCreation(retSurf, sourceData,
+                                    surf->GetSize().width * BytesPerPixel(surf->GetFormat()),
+                                    surf->GetSize(), surf->GetFormat()));
+    delete [] sourceData;
+  } else {
+    mRecorder->RecordEvent(
+      RecordedSourceSurfaceCreation(retSurf, dataSurf->GetData(), dataSurf->Stride(),
+                                    dataSurf->GetSize(), dataSurf->GetFormat()));
+  }
+
+  return retSurf;
+}
+
+TemporaryRef<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();
+
+  if (!dataSurf) {
+    gfxWarning() << "Recording failed to record SourceSurface created from OptimizeSourceSurface";
+    // Insert a bogus source surface.
+    uint8_t *sourceData = new uint8_t[surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat())];
+    memset(sourceData, 0, surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat()));
+    mRecorder->RecordEvent(
+      RecordedSourceSurfaceCreation(retSurf, sourceData,
+                                    surf->GetSize().width * BytesPerPixel(surf->GetFormat()),
+                                    surf->GetSize(), surf->GetFormat()));
+    delete [] sourceData;
+  } else {
+    mRecorder->RecordEvent(
+      RecordedSourceSurfaceCreation(retSurf, dataSurf->GetData(), dataSurf->Stride(),
+                                    dataSurf->GetSize(), dataSurf->GetFormat()));
+  }
+
+  return retSurf;
+}
+
+TemporaryRef<DrawTarget>
+DrawTargetRecording::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
+{
+  RefPtr<DrawTarget> dt = mFinalDT->CreateSimilarDrawTarget(aSize, aFormat);
+
+  RefPtr<DrawTarget> retDT = new DrawTargetRecording(mRecorder.get(), dt);
+
+  return retDT;
+}
+
+TemporaryRef<PathBuilder>
+DrawTargetRecording::CreatePathBuilder(FillRule aFillRule) const
+{
+  RefPtr<PathBuilder> builder = mFinalDT->CreatePathBuilder(aFillRule);
+  return new PathBuilderRecording(builder, aFillRule);
+}
+
+TemporaryRef<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;
+}
+
+void
+DrawTargetRecording::SetTransform(const Matrix &aTransform)
+{
+  mRecorder->RecordEvent(RecordedSetTransform(this, aTransform));
+  DrawTarget::SetTransform(aTransform);
+  mFinalDT->SetTransform(aTransform);
+}
+
+void
+DrawTargetRecording::EnsureStored(const Path *aPath)
+{
+  if (!mRecorder->HasStoredPath(aPath)) {
+    if (aPath->GetBackendType() != BACKEND_RECORDING) {
+      gfxWarning() << "Cannot record this fill path properly!";
+    } else {
+      PathRecording *recPath = const_cast<PathRecording*>(static_cast<const PathRecording*>(aPath));
+      mRecorder->RecordEvent(RecordedPathCreation(recPath));
+      mRecorder->AddStoredPath(aPath);
+      recPath->mStoredRecorders.push_back(mRecorder);
+    }
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DrawTargetRecording.h
@@ -0,0 +1,273 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_DRAWTARGETRECORDING_H_
+#define MOZILLA_GFX_DRAWTARGETRECORDING_H_
+
+#include "2D.h"
+#include "DrawEventRecorder.h"
+
+namespace mozilla {
+namespace gfx {
+
+class DrawTargetRecording : public DrawTarget
+{
+public:
+  DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT);
+  ~DrawTargetRecording();
+
+  virtual BackendType GetType() const { return mFinalDT->GetType(); }
+
+  virtual TemporaryRef<SourceSurface> Snapshot();
+
+  virtual IntSize GetSize() { return mFinalDT->GetSize(); }
+
+  /* Ensure that the DrawTarget backend has flushed all drawing operations to
+   * this draw target. This must be called before using the backing surface of
+   * this draw target outside of GFX 2D code.
+   */
+  virtual void Flush() { mFinalDT->Flush(); }
+
+  /*
+   * Draw a surface to the draw target. Possibly doing partial drawing or
+   * applying scaling. No sampling happens outside the source.
+   *
+   * aSurface Source surface to draw
+   * aDest Destination rectangle that this drawing operation should draw to
+   * aSource Source rectangle in aSurface coordinates, this area of aSurface
+   *         will be stretched to the size of aDest.
+   * aOptions General draw options that are applied to the operation
+   * aSurfOptions DrawSurface options that are applied
+   */
+  virtual void DrawSurface(SourceSurface *aSurface,
+                           const Rect &aDest,
+                           const Rect &aSource,
+                           const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
+                           const DrawOptions &aOptions = DrawOptions());
+
+  /*
+   * Blend a surface to the draw target with a shadow. The shadow is drawn as a
+   * gaussian blur using a specified sigma. The shadow is clipped to the size
+   * of the input surface, so the input surface should contain a transparent
+   * border the size of the approximate coverage of the blur (3 * aSigma).
+   * NOTE: This function works in device space!
+   *
+   * aSurface Source surface to draw.
+   * aDest Destination point that this drawing operation should draw to.
+   * aColor Color of the drawn shadow
+   * aOffset Offset of the shadow
+   * aSigma Sigma used for the guassian filter kernel
+   * aOperator Composition operator used
+   */
+  virtual void DrawSurfaceWithShadow(SourceSurface *aSurface,
+                                     const Point &aDest,
+                                     const Color &aColor,
+                                     const Point &aOffset,
+                                     Float aSigma,
+                                     CompositionOp aOperator);
+
+  /* 
+   * Clear a rectangle on the draw target to transparent black. This will
+   * respect the clipping region and transform.
+   *
+   * aRect Rectangle to clear
+   */
+  virtual void ClearRect(const Rect &aRect);
+
+  /*
+   * This is essentially a 'memcpy' between two surfaces. It moves a pixel
+   * aligned area from the source surface unscaled directly onto the
+   * drawtarget. This ignores both transform and clip.
+   *
+   * aSurface Surface to copy from
+   * aSourceRect Source rectangle to be copied
+   * aDest Destination point to copy the surface to
+   */
+  virtual void CopySurface(SourceSurface *aSurface,
+                           const IntRect &aSourceRect,
+                           const IntPoint &aDestination);
+
+  /*
+   * Fill a rectangle on the DrawTarget with a certain source pattern.
+   *
+   * aRect Rectangle that forms the mask of this filling operation
+   * aPattern Pattern that forms the source of this filling operation
+   * aOptions Options that are applied to this operation
+   */
+  virtual void FillRect(const Rect &aRect,
+                        const Pattern &aPattern,
+                        const DrawOptions &aOptions = DrawOptions());
+
+  /*
+   * Stroke a rectangle on the DrawTarget with a certain source pattern.
+   *
+   * aRect Rectangle that forms the mask of this stroking operation
+   * aPattern Pattern that forms the source of this stroking operation
+   * aOptions Options that are applied to this operation
+   */
+  virtual void StrokeRect(const Rect &aRect,
+                          const Pattern &aPattern,
+                          const StrokeOptions &aStrokeOptions = StrokeOptions(),
+                          const DrawOptions &aOptions = DrawOptions());
+
+  /*
+   * Stroke a line on the DrawTarget with a certain source pattern.
+   *
+   * aStart Starting point of the line
+   * aEnd End point of the line
+   * aPattern Pattern that forms the source of this stroking operation
+   * aOptions Options that are applied to this operation
+   */
+  virtual void StrokeLine(const Point &aStart,
+                          const Point &aEnd,
+                          const Pattern &aPattern,
+                          const StrokeOptions &aStrokeOptions = StrokeOptions(),
+                          const DrawOptions &aOptions = DrawOptions());
+
+  /*
+   * Stroke a path on the draw target with a certain source pattern.
+   *
+   * aPath Path that is to be stroked
+   * aPattern Pattern that should be used for the stroke
+   * aStrokeOptions Stroke options used for this operation
+   * aOptions Draw options used for this operation
+   */
+  virtual void Stroke(const Path *aPath,
+                      const Pattern &aPattern,
+                      const StrokeOptions &aStrokeOptions = StrokeOptions(),
+                      const DrawOptions &aOptions = DrawOptions());
+  
+  /*
+   * Fill a path on the draw target with a certain source pattern.
+   *
+   * aPath Path that is to be filled
+   * aPattern Pattern that should be used for the fill
+   * aOptions Draw options used for this operation
+   */
+  virtual void Fill(const Path *aPath,
+                    const Pattern &aPattern,
+                    const DrawOptions &aOptions = DrawOptions());
+
+  /*
+   * Fill a series of clyphs on the draw target with a certain source pattern.
+   */
+  virtual void FillGlyphs(ScaledFont *aFont,
+                          const GlyphBuffer &aBuffer,
+                          const Pattern &aPattern,
+                          const DrawOptions &aOptions = DrawOptions(),
+                          const GlyphRenderingOptions *aRenderingOptions = NULL);
+
+  /*
+   * This takes a source pattern and a mask, and composites the source pattern
+   * onto the destination surface using the alpha channel of the mask pattern
+   * as a mask for the operation.
+   *
+   * aSource Source pattern
+   * aMask Mask pattern
+   * aOptions Drawing options
+   */
+  virtual void Mask(const Pattern &aSource,
+                    const Pattern &aMask,
+                    const DrawOptions &aOptions = DrawOptions());
+
+  /*
+   * Push a clip to the DrawTarget.
+   *
+   * aPath The path to clip to
+   */
+  virtual void PushClip(const Path *aPath);
+
+  /*
+   * Push an axis-aligned rectangular clip to the DrawTarget. This rectangle
+   * is specified in user space.
+   *
+   * aRect The rect to clip to
+   */
+  virtual void PushClipRect(const Rect &aRect);
+
+  /* Pop a clip from the DrawTarget. A pop without a corresponding push will
+   * be ignored.
+   */
+  virtual void PopClip();
+
+  /*
+   * Create a SourceSurface optimized for use with this DrawTarget from
+   * existing bitmap data in memory.
+   *
+   * The SourceSurface does not take ownership of aData, and may be freed at any time.
+   */
+  virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
+                                                                  const IntSize &aSize,
+                                                                  int32_t aStride,
+                                                                  SurfaceFormat aFormat) const;
+
+  /*
+   * Create a SourceSurface optimized for use with this DrawTarget from
+   * an arbitrary other SourceSurface. This may return aSourceSurface or some
+   * other existing surface.
+   */
+  virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const;
+
+  /*
+   * Create a SourceSurface for a type of NativeSurface. This may fail if the
+   * draw target does not know how to deal with the type of NativeSurface passed
+   * in.
+   */
+  virtual TemporaryRef<SourceSurface>
+    CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const;
+
+  /*
+   * Create a DrawTarget whose snapshot is optimized for use with this DrawTarget.
+   */
+  virtual TemporaryRef<DrawTarget>
+    CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
+
+  /*
+   * Create a path builder with the specified fillmode.
+   *
+   * We need the fill mode up front because of Direct2D.
+   * ID2D1SimplifiedGeometrySink requires the fill mode
+   * to be set before calling BeginFigure().
+   */
+  virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const;
+
+  /*
+   * Create a GradientStops object that holds information about a set of
+   * gradient stops, this object is required for linear or radial gradient
+   * patterns to represent the color stops in the gradient.
+   *
+   * aStops An array of gradient stops
+   * aNumStops Number of stops in the array aStops
+   * aExtendNone This describes how to extend the stop color outside of the
+   *             gradient area.
+   */
+  virtual TemporaryRef<GradientStops>
+    CreateGradientStops(GradientStop *aStops,
+                        uint32_t aNumStops,
+                        ExtendMode aExtendMode = EXTEND_CLAMP) const;
+
+  /*
+   * Set a transform on the surface, this transform is applied at drawing time
+   * to both the mask and source of the operation.
+   */
+  virtual void SetTransform(const Matrix &aTransform);
+
+  /* Tries to get a native surface for a DrawTarget, this may fail if the
+   * draw target cannot convert to this surface type.
+   */
+  virtual void *GetNativeSurface(NativeSurfaceType aType) { return mFinalDT->GetNativeSurface(aType); }
+
+private:
+  Path *GetPathForPathRecording(const Path *aPath) const;
+  void EnsureStored(const Path *aPath);
+
+  RefPtr<DrawEventRecorderPrivate> mRecorder;
+  RefPtr<DrawTarget> mFinalDT;
+};
+
+}
+}
+
+#endif /* MOZILLA_GFX_DRAWTARGETRECORDING_H_ */
--- a/gfx/2d/Makefile.in
+++ b/gfx/2d/Makefile.in
@@ -36,16 +36,20 @@ EXPORTS_mozilla/gfx	= \
 
 CPPSRCS	= \
         Factory.cpp \
         Rect.cpp \
         Matrix.cpp \
         DrawTargetCairo.cpp \
         SourceSurfaceCairo.cpp \
         PathCairo.cpp \
+        DrawTargetRecording.cpp \
+        PathRecording.cpp \
+        RecordedEvent.cpp \
+        DrawEventRecorder.cpp \
         Blur.cpp \
         ScaledFontBase.cpp \
         DrawTargetDual.cpp \
         ImageScaling.cpp \
         SourceSurfaceRawData.cpp \
         $(NULL)
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
new file mode 100644
--- /dev/null
+++ b/gfx/2d/PathRecording.cpp
@@ -0,0 +1,120 @@
+/* -*- 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 "PathRecording.h"
+#include "DrawEventRecorder.h"
+
+namespace mozilla {
+namespace gfx {
+
+using namespace std;
+
+void
+PathBuilderRecording::MoveTo(const Point &aPoint)
+{
+  PathOp op;
+  op.mType = PathOp::OP_MOVETO;
+  op.mP1 = aPoint;
+  mPathOps.push_back(op);
+  mPathBuilder->MoveTo(aPoint);
+}
+
+void
+PathBuilderRecording::LineTo(const Point &aPoint)
+{
+  PathOp op;
+  op.mType = PathOp::OP_LINETO;
+  op.mP1 = aPoint;
+  mPathOps.push_back(op);
+  mPathBuilder->LineTo(aPoint);
+}
+
+void
+PathBuilderRecording::BezierTo(const Point &aCP1, const Point &aCP2, const Point &aCP3)
+{
+  PathOp op;
+  op.mType = PathOp::OP_BEZIERTO;
+  op.mP1 = aCP1;
+  op.mP2 = aCP2;
+  op.mP3 = aCP3;
+  mPathOps.push_back(op);
+  mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
+}
+
+void
+PathBuilderRecording::QuadraticBezierTo(const Point &aCP1, const Point &aCP2)
+{
+  PathOp op;
+  op.mType = PathOp::OP_QUADRATICBEZIERTO;
+  op.mP1 = aCP1;
+  op.mP2 = aCP2;
+  mPathOps.push_back(op);
+  mPathBuilder->QuadraticBezierTo(aCP1, aCP2);
+}
+
+void
+PathBuilderRecording::Close()
+{
+  PathOp op;
+  op.mType = PathOp::OP_CLOSE;
+  mPathOps.push_back(op);
+  mPathBuilder->Close();
+}
+
+Point
+PathBuilderRecording::CurrentPoint() const
+{
+  return mPathBuilder->CurrentPoint();
+}
+
+TemporaryRef<Path>
+PathBuilderRecording::Finish()
+{
+  RefPtr<Path> path = mPathBuilder->Finish();
+  return new PathRecording(path, mPathOps, mFillRule);
+}
+
+PathRecording::~PathRecording()
+{
+  for (size_t i = 0; i < mStoredRecorders.size(); i++) {
+    mStoredRecorders[i]->RemoveStoredPath(this);
+    mStoredRecorders[i]->RecordEvent(RecordedPathDestruction(this));
+  }
+}
+
+TemporaryRef<PathBuilder>
+PathRecording::CopyToBuilder(FillRule aFillRule) const
+{
+  RefPtr<PathBuilder> pathBuilder = mPath->CopyToBuilder(aFillRule);
+  RefPtr<PathBuilderRecording> recording = new PathBuilderRecording(pathBuilder, aFillRule);
+  recording->mPathOps = mPathOps;
+  return recording;
+}
+
+TemporaryRef<PathBuilder>
+PathRecording::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
+{
+  RefPtr<PathBuilder> pathBuilder = mPath->TransformedCopyToBuilder(aTransform, aFillRule);
+  RefPtr<PathBuilderRecording> recording = new PathBuilderRecording(pathBuilder, aFillRule);
+  typedef std::vector<PathOp> pathOpVec;
+  for (pathOpVec::const_iterator iter = mPathOps.begin(); iter != mPathOps.end(); iter++) {
+    PathOp newPathOp;
+    newPathOp.mType = iter->mType;
+    if (sPointCount[newPathOp.mType] >= 1) {
+      newPathOp.mP1 = aTransform * iter->mP1;
+    }
+    if (sPointCount[newPathOp.mType] >= 2) {
+      newPathOp.mP2 = aTransform * iter->mP2;
+    }
+    if (sPointCount[newPathOp.mType] >= 3) {
+      newPathOp.mP3 = aTransform * iter->mP3;
+    }
+    recording->mPathOps.push_back(newPathOp);
+  }
+  return recording;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/PathRecording.h
@@ -0,0 +1,126 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_PATHRECORDING_H_
+#define MOZILLA_GFX_PATHRECORDING_H_
+
+#include "2D.h"
+#include <vector>
+
+namespace mozilla {
+namespace gfx {
+
+struct PathOp
+{
+  enum OpType {
+    OP_MOVETO = 0,
+    OP_LINETO,
+    OP_BEZIERTO,
+    OP_QUADRATICBEZIERTO,
+    OP_ARCTO,
+    OP_CLOSE
+  };
+
+  OpType mType;
+  Point mP1;
+  Point mP2;
+  Point mP3;
+};
+
+const int32_t sPointCount[] = { 1, 1, 3, 2, 0, 0 };
+
+class PathRecording;
+class DrawEventRecorderPrivate;
+
+class PathBuilderRecording : public PathBuilder
+{
+public:
+  PathBuilderRecording(PathBuilder *aBuilder, FillRule aFillRule)
+    : mPathBuilder(aBuilder), mFillRule(aFillRule)
+  {
+  }
+
+  /* Move the current point in the path, any figure currently being drawn will
+   * be considered closed during fill operations, however when stroking the
+   * closing line segment will not be drawn.
+   */
+  virtual void MoveTo(const Point &aPoint);
+  /* Add a linesegment to the current figure */
+  virtual void LineTo(const Point &aPoint);
+  /* Add a cubic bezier curve to the current figure */
+  virtual void BezierTo(const Point &aCP1,
+                        const Point &aCP2,
+                        const Point &aCP3);
+  /* Add a quadratic bezier curve to the current figure */
+  virtual void QuadraticBezierTo(const Point &aCP1,
+                                 const Point &aCP2);
+  /* Close the current figure, this will essentially generate a line segment
+   * from the current point to the starting point for the current figure
+   */
+  virtual void Close();
+
+  /* Add an arc to the current figure */
+  virtual void Arc(const Point &, float, float, float, bool) { }
+
+  /* Point the current subpath is at - or where the next subpath will start
+   * if there is no active subpath.
+   */
+  virtual Point CurrentPoint() const;
+
+  virtual TemporaryRef<Path> Finish();
+
+private:
+  friend class PathRecording;
+
+  RefPtr<PathBuilder> mPathBuilder;
+  FillRule mFillRule;
+  std::vector<PathOp> mPathOps;
+};
+
+class PathRecording : public Path
+{
+public:
+  PathRecording(Path *aPath, const std::vector<PathOp> aOps, FillRule aFillRule)
+    : mPath(aPath), mPathOps(aOps), mFillRule(aFillRule)
+  {
+  }
+
+  ~PathRecording();
+
+  virtual BackendType GetBackendType() const { return BACKEND_RECORDING; }
+  virtual TemporaryRef<PathBuilder> CopyToBuilder(FillRule aFillRule = FILL_WINDING) const;
+  virtual TemporaryRef<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
+                                                             FillRule aFillRule = FILL_WINDING) const;
+  virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
+  { return mPath->ContainsPoint(aPoint, aTransform); }
+  
+  virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const
+  { return mPath->GetBounds(aTransform); }
+  
+  virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
+                                const Matrix &aTransform = Matrix()) const
+  { return mPath->GetStrokedBounds(aStrokeOptions, aTransform); }
+  
+  virtual FillRule GetFillRule() const { return mFillRule; }
+
+  void StorePath(std::ostream &aStream) const;
+  static void ReadPathToBuilder(std::istream &aStream, PathBuilder *aBuilder);
+
+private:
+  friend class DrawTargetRecording;
+  friend class RecordedPathCreation;
+
+  RefPtr<Path> mPath;
+  std::vector<PathOp> mPathOps;
+  FillRule mFillRule;
+
+  // Event recorders that have this path in their event stream.
+  std::vector<DrawEventRecorderPrivate*> mStoredRecorders;
+};
+
+}
+}
+
+#endif /* MOZILLA_GFX_PATHRECORDING_H_ */
new file mode 100644
--- /dev/null
+++ b/gfx/2d/RecordedEvent.cpp
@@ -0,0 +1,1198 @@
+/* -*- 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 "Tools.h"
+
+namespace mozilla {
+namespace gfx {
+
+using namespace std;
+
+static std::string NameFromBackend(BackendType aType)
+{
+  switch (aType) {
+  case BACKEND_NONE:
+    return "None";
+  case BACKEND_DIRECT2D:
+    return "Direct2D";
+  default:
+    return "Unknown";
+  }
+}
+
+#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(PATHCREATION, RecordedPathCreation);
+    LOAD_EVENT_TYPE(PATHDESTRUCTION, RecordedPathDestruction);
+    LOAD_EVENT_TYPE(SOURCESURFACECREATION, RecordedSourceSurfaceCreation);
+    LOAD_EVENT_TYPE(SOURCESURFACEDESTRUCTION, RecordedSourceSurfaceDestruction);
+    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);
+  default:
+    return NULL;
+  }
+}
+
+void
+RecordedEvent::RecordPatternData(std::ostream &aStream, const PatternStorage &aPattern) const
+{
+  WriteElement(aStream, aPattern.mType);
+
+  switch (aPattern.mType) {
+  case PATTERN_COLOR:
+    {
+      WriteElement(aStream, *reinterpret_cast<const ColorPatternStorage*>(&aPattern.mStorage));
+      return;
+    }
+  case PATTERN_LINEAR_GRADIENT:
+    {
+      WriteElement(aStream, *reinterpret_cast<const LinearGradientPatternStorage*>(&aPattern.mStorage));
+      return;
+    }
+  case PATTERN_RADIAL_GRADIENT:
+    {
+      WriteElement(aStream, *reinterpret_cast<const RadialGradientPatternStorage*>(&aPattern.mStorage));
+      return;
+    }
+  case PATTERN_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 PATTERN_COLOR:
+    {
+      ReadElement(aStream, *reinterpret_cast<ColorPatternStorage*>(&aPattern.mStorage));
+      return;
+    }
+  case PATTERN_LINEAR_GRADIENT:
+    {
+      ReadElement(aStream, *reinterpret_cast<LinearGradientPatternStorage*>(&aPattern.mStorage));
+      return;
+    }
+  case PATTERN_RADIAL_GRADIENT:
+    {
+      ReadElement(aStream, *reinterpret_cast<RadialGradientPatternStorage*>(&aPattern.mStorage));
+      return;
+    }
+  case PATTERN_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 PATTERN_COLOR:
+    {
+      reinterpret_cast<ColorPatternStorage*>(&aDestination.mStorage)->mColor =
+        static_cast<const ColorPattern*>(&aSource)->mColor;
+      return;
+    }
+  case PATTERN_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 PATTERN_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 PATTERN_SURFACE:
+    {
+      SurfacePatternStorage *store =
+        reinterpret_cast<SurfacePatternStorage*>(&aDestination.mStorage);
+      const SurfacePattern *pat =
+        static_cast<const SurfacePattern*>(&aSource);
+      store->mExtend = pat->mExtendMode;
+      store->mFilter = pat->mFilter;
+      store->mMatrix = pat->mMatrix;
+      store->mSurface = pat->mSurface;
+      return;
+    }
+  }
+}
+
+void
+RecordedEvent::RecordStrokeOptions(std::ostream &aStream, const StrokeOptions &aStrokeOptions) const
+{
+  WriteElement(aStream, aStrokeOptions);
+
+  if (!aStrokeOptions.mDashPattern) {
+    return;
+  }
+
+  aStream.write((char*)aStrokeOptions.mDashPattern, sizeof(Float) * aStrokeOptions.mDashLength);
+}
+
+void
+RecordedEvent::ReadStrokeOptions(std::istream &aStream, StrokeOptions &aStrokeOptions)
+{
+  ReadElement(aStream, aStrokeOptions);
+
+  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 PATTERN_COLOR:
+    {
+      const Color color = reinterpret_cast<const ColorPatternStorage*>(&aStorage.mStorage)->mColor;
+      aOutput << "Color: (" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")";
+      return;
+    }
+  case PATTERN_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 PATTERN_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 PATTERN_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::GetObject() const
+{
+  return mDT;
+}
+
+void
+RecordedDrawTargetCreation::PlayEvent(Translator *aTranslator) const
+{
+  RefPtr<DrawTarget> newDT =
+    aTranslator->GetReferenceDrawTarget()->CreateSimilarDrawTarget(mSize, mFormat);
+  aTranslator->AddDrawTarget(mRefPtr, newDT);
+}
+
+void
+RecordedDrawTargetCreation::RecordToStream(ostream &aStream) const
+{
+  WriteElement(aStream, mRefPtr);
+  WriteElement(aStream, mBackendType);
+  WriteElement(aStream, mSize);
+  WriteElement(aStream, mFormat);
+}
+
+RecordedDrawTargetCreation::RecordedDrawTargetCreation(istream &aStream)
+  : RecordedEvent(DRAWTARGETCREATION)
+{
+  ReadElement(aStream, mRefPtr);
+  ReadElement(aStream, mBackendType);
+  ReadElement(aStream, mSize);
+  ReadElement(aStream, mFormat);
+}
+
+void
+RecordedDrawTargetCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+  aStringStream << "[" << mRefPtr << "] DrawTarget Creation (Type: " << NameFromBackend(mBackendType) << ", Size: " << mSize.width << "x" << mSize.height << ")";
+}
+
+
+void
+RecordedDrawTargetDestruction::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->RemoveDrawTarget(mRefPtr);
+}
+
+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";
+}
+
+struct GenericPattern
+{
+  GenericPattern(const PatternStorage &aStorage, Translator *aTranslator)
+    : mPattern(NULL), mTranslator(aTranslator)
+  {
+    mStorage = const_cast<PatternStorage*>(&aStorage);
+  }
+
+  ~GenericPattern() {
+    if (mPattern) {
+      mPattern->~Pattern();
+    }
+  }
+
+  operator Pattern*()
+  {
+    switch(mStorage->mType) {
+    case PATTERN_COLOR:
+      return new (mColPat) ColorPattern(reinterpret_cast<ColorPatternStorage*>(&mStorage->mStorage)->mColor);
+    case PATTERN_SURFACE:
+      {
+        SurfacePatternStorage *storage = reinterpret_cast<SurfacePatternStorage*>(&mStorage->mStorage);
+        mPattern =
+          new (mSurfPat) SurfacePattern(mTranslator->LookupSourceSurface(storage->mSurface),
+                                        storage->mExtend, storage->mMatrix, storage->mFilter);
+        return mPattern;
+      }
+    case PATTERN_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 PATTERN_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;
+};
+
+void
+RecordedFillRect::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->FillRect(mRect, *GenericPattern(mPattern, aTranslator), mOptions);
+}
+
+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);
+}
+
+void
+RecordedStrokeRect::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->StrokeRect(mRect, *GenericPattern(mPattern, aTranslator), mStrokeOptions, mOptions);
+}
+
+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);
+}
+
+void
+RecordedStrokeLine::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->StrokeLine(mBegin, mEnd, *GenericPattern(mPattern, aTranslator), mStrokeOptions, mOptions);
+}
+
+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);
+}
+
+void
+RecordedFill::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->Fill(aTranslator->LookupPath(mPath), *GenericPattern(mPattern, aTranslator), mOptions);
+}
+
+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;
+}
+
+void
+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);
+}
+
+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);
+}
+
+void
+RecordedMask::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->Mask(*GenericPattern(mSource, aTranslator), *GenericPattern(mMask, aTranslator), mOptions);
+}
+
+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);
+}
+
+void
+RecordedStroke::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->Stroke(aTranslator->LookupPath(mPath), *GenericPattern(mPattern, aTranslator), mStrokeOptions, mOptions);
+}
+
+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);
+}
+
+void
+RecordedClearRect::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->ClearRect(mRect);
+}
+
+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 << ") ";
+}
+
+void
+RecordedCopySurface::PlayEvent(Translator *aTranslator) const
+{
+	aTranslator->LookupDrawTarget(mDT)->CopySurface(aTranslator->LookupSourceSurface(mSourceSurface),
+                                                  mSourceRect, mDest);
+}
+
+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 << ")";
+}
+
+void
+RecordedPushClip::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->PushClip(aTranslator->LookupPath(mPath));
+}
+
+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 << ") ";
+}
+
+void
+RecordedPushClipRect::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->PushClipRect(mRect);
+}
+
+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 << ") ";
+}
+
+void
+RecordedPopClip::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->PopClip();
+}
+
+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";
+}
+
+void
+RecordedSetTransform::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->SetTransform(mTransform);
+}
+
+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 << " ]";
+}
+
+void
+RecordedDrawSurface::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->
+    DrawSurface(aTranslator->LookupSourceSurface(mRefSource), mDest, mSource,
+                mDSOptions, mOptions);
+}
+
+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 << ")";
+}
+
+void
+RecordedDrawSurfaceWithShadow::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->
+    DrawSurfaceWithShadow(aTranslator->LookupSourceSurface(mRefSource),
+                          mDest, mColor, mOffset, mSigma, mOp);
+}
+
+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()
+{
+}
+
+void
+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);
+}
+
+void
+RecordedPathCreation::RecordToStream(ostream &aStream) const
+{
+  WriteElement(aStream, mRefPtr);
+  WriteElement(aStream, 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)
+{
+  size_t size;
+
+  ReadElement(aStream, mRefPtr);
+  ReadElement(aStream, size);
+  ReadElement(aStream, mFillRule);
+
+  for (size_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() << ")";
+}
+void
+RecordedPathDestruction::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->RemovePath(mRefPtr);
+}
+
+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;
+  }
+}
+
+void
+RecordedSourceSurfaceCreation::PlayEvent(Translator *aTranslator) const
+{
+  RefPtr<SourceSurface> src = aTranslator->GetReferenceDrawTarget()->
+    CreateSourceSurfaceFromData(mData, mSize, mSize.width * BytesPerPixel(mFormat), mFormat);
+  aTranslator->AddSourceSurface(mRefPtr, src);
+}
+
+void
+RecordedSourceSurfaceCreation::RecordToStream(ostream &aStream) const
+{
+  WriteElement(aStream, mRefPtr);
+  WriteElement(aStream, mSize);
+  WriteElement(aStream, mFormat);
+  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 char[mSize.width * mSize.height * BytesPerPixel(mFormat)];
+  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 << ")";
+}
+
+void
+RecordedSourceSurfaceDestruction::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->RemoveSourceSurface(mRefPtr);
+}
+
+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";
+}
+
+RecordedGradientStopsCreation::~RecordedGradientStopsCreation()
+{
+  if (mDataOwned) {
+    delete [] mStops;
+  }
+}
+
+void
+RecordedGradientStopsCreation::PlayEvent(Translator *aTranslator) const
+{
+  RefPtr<GradientStops> src = aTranslator->GetReferenceDrawTarget()->
+    CreateGradientStops(mStops, mNumStops, mExtendMode);
+  aTranslator->AddGradientStops(mRefPtr, src);
+}
+
+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 << ")";
+}
+
+void
+RecordedGradientStopsDestruction::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->RemoveGradientStops(mRefPtr);
+}
+
+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";
+}
+
+void
+RecordedSnapshot::PlayEvent(Translator *aTranslator) const
+{
+  RefPtr<SourceSurface> src = aTranslator->LookupDrawTarget(mDT)->Snapshot();
+  aTranslator->AddSourceSurface(mRefPtr, src);
+}
+
+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 << ")";
+}
+
+RecordedScaledFontCreation::~RecordedScaledFontCreation()
+{
+  delete [] mData;
+}
+
+void
+RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const
+{
+  RefPtr<ScaledFont> scaledFont =
+    Factory::CreateScaledFontForTrueTypeData(mData, mSize, mIndex, mGlyphSize,
+                                             aTranslator->GetDesiredFontType());
+  aTranslator->AddScaledFont(mRefPtr, scaledFont);
+}
+
+void
+RecordedScaledFontCreation::RecordToStream(std::ostream &aStream) const
+{
+  WriteElement(aStream, mRefPtr);
+  WriteElement(aStream, mIndex);
+  WriteElement(aStream, mGlyphSize);
+  WriteElement(aStream, mSize);
+  aStream.write((const char*)mData, mSize);
+}
+
+void
+RecordedScaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+  aStringStream << "[" << mRefPtr << "] ScaledFont Created";
+}
+
+void
+RecordedScaledFontCreation::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize)
+{
+  mData = new uint8_t[aSize];
+  memcpy(mData, aData, aSize);
+  mSize = aSize;
+  mIndex = aIndex;
+  mGlyphSize = aGlyphSize;
+}
+
+RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream)
+  : RecordedEvent(SCALEDFONTCREATION)
+{
+  ReadElement(aStream, mRefPtr);
+  ReadElement(aStream, mIndex);
+  ReadElement(aStream, mGlyphSize);
+  ReadElement(aStream, mSize);
+  mData = new uint8_t[mSize];
+  aStream.read((char*)mData, mSize);
+}
+
+void
+RecordedScaledFontDestruction::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->RemoveScaledFont(mRefPtr);
+}
+
+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";
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/RecordedEvent.h
@@ -0,0 +1,869 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_RECORDEDEVENT_H_
+#define MOZILLA_GFX_RECORDEDEVENT_H_
+
+#include "2D.h"
+#include <ostream>
+#include <sstream>
+#include "RecordingTypes.h"
+#include "PathRecording.h"
+
+namespace mozilla {
+namespace gfx {
+
+// A change in major revision means a change in event binary format, causing
+// loss of backwards compatibility. Old streams will not work in a player
+// using a newer major revision. And new streams will not work in a player
+// using an older major revision.
+const uint16_t kMajorRevision = 1;
+// A change in minor revision means additions of new events. New streams will
+// not play in older players.
+const uint16_t kMinorRevision = 0;
+
+struct ReferencePtr
+{
+  ReferencePtr()
+    : mLongPtr(0)
+  {}
+
+  ReferencePtr(const void* aLongPtr)
+    : mLongPtr(uint64_t(aLongPtr))
+  {}
+
+  template <typename T>
+  ReferencePtr(const RefPtr<T>& aPtr)
+    : mLongPtr(uint64_t(aPtr.get()))
+  {}
+
+  ReferencePtr &operator =(const void* aLongPtr) {
+    mLongPtr = uint64_t(aLongPtr);
+    return *this;
+  }
+
+  template <typename T>
+  ReferencePtr &operator =(const RefPtr<T>& aPtr) {
+    mLongPtr = uint64_t(aPtr.get());
+    return *this;
+  }
+
+  operator void*() const {
+    return (void*)mLongPtr;
+  }
+
+  uint64_t mLongPtr;
+};
+
+static std::string StringFromPtr(ReferencePtr aPtr)
+{
+  std::stringstream stream;
+  stream << aPtr;
+  return stream.str();
+}
+
+class Translator
+{
+public:
+  virtual DrawTarget *LookupDrawTarget(ReferencePtr aRefPtr) = 0;
+  virtual Path *LookupPath(ReferencePtr aRefPtr) = 0;
+  virtual SourceSurface *LookupSourceSurface(ReferencePtr aRefPtr) = 0;
+  virtual GradientStops *LookupGradientStops(ReferencePtr aRefPtr) = 0;
+  virtual ScaledFont *LookupScaledFont(ReferencePtr aRefPtr) = 0;
+  virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) = 0;
+  virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0;
+  virtual void AddPath(ReferencePtr aRefPtr, Path *aPath) = 0;
+  virtual void RemovePath(ReferencePtr aRefPtr) = 0;
+  virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface *aPath) = 0;
+  virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0;
+  virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops *aPath) = 0;
+  virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0;
+  virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) = 0;
+  virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0;
+
+  virtual DrawTarget *GetReferenceDrawTarget() = 0;
+  virtual FontType GetDesiredFontType() = 0;
+};
+
+struct ColorPatternStorage
+{
+  Color mColor;
+};
+
+struct LinearGradientPatternStorage
+{
+  Point mBegin;
+  Point mEnd;
+  ReferencePtr mStops;
+  Matrix mMatrix;
+};
+
+struct RadialGradientPatternStorage
+{
+  Point mCenter1;
+  Point mCenter2;
+  Float mRadius1;
+  Float mRadius2;
+  ReferencePtr mStops;
+  Matrix mMatrix;
+};
+
+struct SurfacePatternStorage
+{
+  ExtendMode mExtend;
+  Filter mFilter;
+  ReferencePtr mSurface;
+  Matrix mMatrix;
+};
+
+struct PatternStorage
+{
+  PatternType mType;
+  union {
+    char *mStorage;
+    char mColor[sizeof(ColorPatternStorage)];
+    char mLinear[sizeof(LinearGradientPatternStorage)];
+    char mRadial[sizeof(RadialGradientPatternStorage)];
+    char mSurface[sizeof(SurfacePatternStorage)];
+  };
+};
+
+class RecordedEvent {
+public:
+  enum EventType {
+    DRAWTARGETCREATION = 0,
+    DRAWTARGETDESTRUCTION,
+    FILLRECT,
+    STROKERECT,
+    STROKELINE,
+    CLEARRECT,
+    COPYSURFACE,
+    SETTRANSFORM,
+    PUSHCLIP,
+    PUSHCLIPRECT,
+    POPCLIP,
+    FILL,
+    FILLGLYPHS,
+    MASK,
+    STROKE,
+    DRAWSURFACE,
+    DRAWSURFACEWITHSHADOW,
+    PATHCREATION,
+    PATHDESTRUCTION,
+    SOURCESURFACECREATION,
+    SOURCESURFACEDESTRUCTION,
+    GRADIENTSTOPSCREATION,
+    GRADIENTSTOPSDESTRUCTION,
+    SNAPSHOT,
+    SCALEDFONTCREATION,
+    SCALEDFONTDESTRUCTION
+  };
+
+  virtual void PlayEvent(Translator *aTranslator) const {}
+
+  virtual void RecordToStream(std::ostream &aStream) const {}
+
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const { }
+
+  void RecordPatternData(std::ostream &aStream, const PatternStorage &aPatternStorage) const;
+  void ReadPatternData(std::istream &aStream, PatternStorage &aPatternStorage) const;
+  void StorePattern(PatternStorage &aDestination, const Pattern &aSource) const;
+  void RecordStrokeOptions(std::ostream &aStream, const StrokeOptions &aStrokeOptions) const;
+  void ReadStrokeOptions(std::istream &aStream, StrokeOptions &aStrokeOptions);
+
+  virtual std::string GetName() const = 0;
+
+  virtual ReferencePtr GetObject() const = 0;
+
+  virtual ReferencePtr GetDestinedDT() { return nullptr; }
+
+  void OutputSimplePatternInfo(const PatternStorage &aStorage, std::stringstream &aOutput) const;
+
+  static RecordedEvent *LoadEventFromStream(std::istream &aStream, EventType aType);
+
+  EventType GetType() { return (EventType)mType; }
+protected:
+  friend class DrawEventRecorderPrivate;
+
+  RecordedEvent(int32_t aType) : mType(aType)
+  {}
+
+  int32_t mType;
+  std::vector<Float> mDashPatternStorage;
+};
+
+class RecordedDrawingEvent : public RecordedEvent
+{
+public:
+   virtual ReferencePtr GetDestinedDT() { return mDT; }
+
+protected:
+  RecordedDrawingEvent(EventType aType, DrawTarget *aTarget)
+    : RecordedEvent(aType), mDT(aTarget)
+  {
+  }
+
+  RecordedDrawingEvent(EventType aType, std::istream &aStream);
+  virtual void RecordToStream(std::ostream &aStream) const;
+
+  virtual ReferencePtr GetObject() const;
+
+  DrawTarget *mDT;
+};
+
+class RecordedDrawTargetCreation : public RecordedEvent {
+public:
+  RecordedDrawTargetCreation(ReferencePtr aRefPtr, BackendType aType, const IntSize &aSize, SurfaceFormat aFormat)
+    : RecordedEvent(DRAWTARGETCREATION), mRefPtr(aRefPtr), mBackendType(aType), mSize(aSize), mFormat(aFormat)
+  {}
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "DrawTarget Creation"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+
+  ReferencePtr mRefPtr;
+  BackendType mBackendType;
+  IntSize mSize;
+  SurfaceFormat mFormat;
+  
+private:
+  friend class RecordedEvent;
+
+  RecordedDrawTargetCreation(std::istream &aStream);
+};
+
+class RecordedDrawTargetDestruction : public RecordedEvent {
+public:
+  RecordedDrawTargetDestruction(ReferencePtr aRefPtr)
+    : RecordedEvent(DRAWTARGETDESTRUCTION), mRefPtr(aRefPtr)
+  {}
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "DrawTarget Destruction"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+
+  ReferencePtr mRefPtr;
+
+  BackendType mBackendType;
+private:
+  friend class RecordedEvent;
+
+  RecordedDrawTargetDestruction(std::istream &aStream);
+};
+
+class RecordedFillRect : public RecordedDrawingEvent {
+public:
+  RecordedFillRect(DrawTarget *aDT, const Rect &aRect, const Pattern &aPattern, const DrawOptions &aOptions)
+    : RecordedDrawingEvent(FILLRECT, aDT), mRect(aRect), mOptions(aOptions)
+  {
+    StorePattern(mPattern, aPattern);
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "FillRect"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedFillRect(std::istream &aStream);
+
+  Rect mRect;
+  PatternStorage mPattern;
+  DrawOptions mOptions;
+};
+
+class RecordedStrokeRect : public RecordedDrawingEvent {
+public:
+  RecordedStrokeRect(DrawTarget *aDT, const Rect &aRect, const Pattern &aPattern,
+                     const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions)
+    : RecordedDrawingEvent(STROKERECT, aDT), mRect(aRect),
+      mStrokeOptions(aStrokeOptions), mOptions(aOptions)
+  {
+    StorePattern(mPattern, aPattern);
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "StrokeRect"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedStrokeRect(std::istream &aStream);
+
+  Rect mRect;
+  PatternStorage mPattern;
+  StrokeOptions mStrokeOptions;
+  DrawOptions mOptions;
+};
+
+class RecordedStrokeLine : public RecordedDrawingEvent {
+public:
+  RecordedStrokeLine(DrawTarget *aDT, const Point &aBegin, const Point &aEnd,
+                     const Pattern &aPattern, const StrokeOptions &aStrokeOptions,
+                     const DrawOptions &aOptions)
+    : RecordedDrawingEvent(STROKELINE, aDT), mBegin(aBegin), mEnd(aEnd),
+      mStrokeOptions(aStrokeOptions), mOptions(aOptions)
+  {
+    StorePattern(mPattern, aPattern);
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "StrokeLine"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedStrokeLine(std::istream &aStream);
+
+  Point mBegin;
+  Point mEnd;
+  PatternStorage mPattern;
+  StrokeOptions mStrokeOptions;
+  DrawOptions mOptions;
+};
+
+class RecordedFill : public RecordedDrawingEvent {
+public:
+  RecordedFill(DrawTarget *aDT, ReferencePtr aPath, const Pattern &aPattern, const DrawOptions &aOptions)
+    : RecordedDrawingEvent(FILL, aDT), mPath(aPath), mOptions(aOptions)
+  {
+    StorePattern(mPattern, aPattern);
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "Fill"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedFill(std::istream &aStream);
+
+  ReferencePtr mPath;
+  PatternStorage mPattern;
+  DrawOptions mOptions;
+};
+
+class RecordedFillGlyphs : public RecordedDrawingEvent {
+public:
+  RecordedFillGlyphs(DrawTarget *aDT, ReferencePtr aScaledFont, const Pattern &aPattern, const DrawOptions &aOptions,
+                     const Glyph *aGlyphs, uint32_t aNumGlyphs)
+    : RecordedDrawingEvent(FILLGLYPHS, aDT), mScaledFont(aScaledFont), mOptions(aOptions)
+  {
+    StorePattern(mPattern, aPattern);
+    mNumGlyphs = aNumGlyphs;
+    mGlyphs = new Glyph[aNumGlyphs];
+    memcpy(mGlyphs, aGlyphs, sizeof(Glyph) * aNumGlyphs);
+  }
+  virtual ~RecordedFillGlyphs();
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "FillGlyphs"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedFillGlyphs(std::istream &aStream);
+
+  ReferencePtr mScaledFont;
+  PatternStorage mPattern;
+  DrawOptions mOptions;
+  Glyph *mGlyphs;
+  uint32_t mNumGlyphs;
+};
+
+class RecordedMask : public RecordedDrawingEvent {
+public:
+  RecordedMask(DrawTarget *aDT, const Pattern &aSource, const Pattern &aMask, const DrawOptions &aOptions)
+    : RecordedDrawingEvent(MASK, aDT), mOptions(aOptions)
+  {
+    StorePattern(mSource, aSource);
+    StorePattern(mMask, aMask);
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "Mask"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedMask(std::istream &aStream);
+
+  PatternStorage mSource;
+  PatternStorage mMask;
+  DrawOptions mOptions;
+};
+
+class RecordedStroke : public RecordedDrawingEvent {
+public:
+  RecordedStroke(DrawTarget *aDT, ReferencePtr aPath, const Pattern &aPattern,
+                     const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions)
+    : RecordedDrawingEvent(STROKE, aDT), mPath(aPath),
+      mStrokeOptions(aStrokeOptions), mOptions(aOptions)
+  {
+    StorePattern(mPattern, aPattern);
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "Stroke"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedStroke(std::istream &aStream);
+
+  ReferencePtr mPath;
+  PatternStorage mPattern;
+  StrokeOptions mStrokeOptions;
+  DrawOptions mOptions;
+};
+
+class RecordedClearRect : public RecordedDrawingEvent {
+public:
+  RecordedClearRect(DrawTarget *aDT, const Rect &aRect)
+    : RecordedDrawingEvent(CLEARRECT, aDT), mRect(aRect)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "ClearRect"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedClearRect(std::istream &aStream);
+
+  Rect mRect;
+};
+
+class RecordedCopySurface : public RecordedDrawingEvent {
+public:
+  RecordedCopySurface(DrawTarget *aDT, ReferencePtr aSourceSurface,
+                      const IntRect &aSourceRect, const IntPoint &aDest)
+    : RecordedDrawingEvent(COPYSURFACE, aDT), mSourceSurface(aSourceSurface),
+	  mSourceRect(aSourceRect), mDest(aDest)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "CopySurface"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedCopySurface(std::istream &aStream);
+
+  ReferencePtr mSourceSurface;
+  IntRect mSourceRect;
+  IntPoint mDest;
+};
+
+class RecordedPushClip : public RecordedDrawingEvent {
+public:
+  RecordedPushClip(DrawTarget *aDT, ReferencePtr aPath)
+    : RecordedDrawingEvent(PUSHCLIP, aDT), mPath(aPath)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "PushClip"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedPushClip(std::istream &aStream);
+
+  ReferencePtr mPath;
+};
+
+class RecordedPushClipRect : public RecordedDrawingEvent {
+public:
+  RecordedPushClipRect(DrawTarget *aDT, const Rect &aRect)
+    : RecordedDrawingEvent(PUSHCLIPRECT, aDT), mRect(aRect)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "PushClipRect"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedPushClipRect(std::istream &aStream);
+
+  Rect mRect;
+};
+
+class RecordedPopClip : public RecordedDrawingEvent {
+public:
+  RecordedPopClip(DrawTarget *aDT)
+    : RecordedDrawingEvent(POPCLIP, aDT)
+  {}
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "PopClip"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedPopClip(std::istream &aStream);
+};
+
+class RecordedSetTransform : public RecordedDrawingEvent {
+public:
+  RecordedSetTransform(DrawTarget *aDT, const Matrix &aTransform)
+    : RecordedDrawingEvent(SETTRANSFORM, aDT), mTransform(aTransform)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "SetTransform"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedSetTransform(std::istream &aStream);
+
+  Matrix mTransform;
+};
+
+class RecordedDrawSurface : public RecordedDrawingEvent {
+public:
+  RecordedDrawSurface(DrawTarget *aDT, ReferencePtr aRefSource, const Rect &aDest,
+                      const Rect &aSource, const DrawSurfaceOptions &aDSOptions,
+                      const DrawOptions &aOptions)
+    : RecordedDrawingEvent(DRAWSURFACE, aDT), mRefSource(aRefSource), mDest(aDest)
+    , mSource(aSource), mDSOptions(aDSOptions), mOptions(aOptions)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "DrawSurface"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedDrawSurface(std::istream &aStream);
+
+  ReferencePtr mRefSource;
+  Rect mDest;
+  Rect mSource;
+  DrawSurfaceOptions mDSOptions;
+  DrawOptions mOptions;
+};
+
+class RecordedDrawSurfaceWithShadow : public RecordedDrawingEvent {
+public:
+  RecordedDrawSurfaceWithShadow(DrawTarget *aDT, ReferencePtr aRefSource, const Point &aDest,
+                                const Color &aColor, const Point &aOffset,
+                                Float aSigma, CompositionOp aOp)
+    : RecordedDrawingEvent(DRAWSURFACEWITHSHADOW, aDT), mRefSource(aRefSource), mDest(aDest)
+    , mColor(aColor), mOffset(aOffset), mSigma(aSigma), mOp(aOp)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "DrawSurfaceWithShadow"; }
+private:
+  friend class RecordedEvent;
+
+  RecordedDrawSurfaceWithShadow(std::istream &aStream);
+
+  ReferencePtr mRefSource;
+  Point mDest;
+  Color mColor;
+  Point mOffset;
+  Float mSigma;
+  CompositionOp mOp;
+};
+
+class RecordedPathCreation : public RecordedEvent {
+public:
+  RecordedPathCreation(PathRecording *aPath);
+  ~RecordedPathCreation();
+  
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "Path Creation"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+  FillRule mFillRule;
+  std::vector<PathOp> mPathOps;
+
+  RecordedPathCreation(std::istream &aStream);
+};
+
+class RecordedPathDestruction : public RecordedEvent {
+public:
+  RecordedPathDestruction(PathRecording *aPath)
+    : RecordedEvent(PATHDESTRUCTION), mRefPtr(aPath)
+  {
+  }
+  
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "Path Destruction"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+
+  RecordedPathDestruction(std::istream &aStream);
+};
+
+class RecordedSourceSurfaceCreation : public RecordedEvent {
+public:
+  RecordedSourceSurfaceCreation(ReferencePtr aRefPtr, uint8_t *aData, int32_t aStride,
+                                const IntSize &aSize, SurfaceFormat aFormat)
+    : RecordedEvent(SOURCESURFACECREATION), mRefPtr(aRefPtr), mData(aData)
+    , mStride(aStride), mSize(aSize), mFormat(aFormat), mDataOwned(false)
+  {
+  }
+
+  ~RecordedSourceSurfaceCreation();
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "SourceSurface Creation"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+  uint8_t *mData;
+  int32_t mStride;
+  IntSize mSize;
+  SurfaceFormat mFormat;
+  bool mDataOwned;
+
+  RecordedSourceSurfaceCreation(std::istream &aStream);
+};
+
+class RecordedSourceSurfaceDestruction : public RecordedEvent {
+public:
+  RecordedSourceSurfaceDestruction(ReferencePtr aRefPtr)
+    : RecordedEvent(SOURCESURFACEDESTRUCTION), mRefPtr(aRefPtr)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "SourceSurface Destruction"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+
+  RecordedSourceSurfaceDestruction(std::istream &aStream);
+};
+
+class RecordedGradientStopsCreation : public RecordedEvent {
+public:
+  RecordedGradientStopsCreation(ReferencePtr aRefPtr, GradientStop *aStops,
+                                uint32_t aNumStops, ExtendMode aExtendMode)
+    : RecordedEvent(GRADIENTSTOPSCREATION), mRefPtr(aRefPtr), mStops(aStops)
+    , mNumStops(aNumStops), mExtendMode(aExtendMode), mDataOwned(false)
+  {
+  }
+
+  ~RecordedGradientStopsCreation();
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "GradientStops Creation"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+  GradientStop *mStops;
+  uint32_t mNumStops;
+  ExtendMode mExtendMode;
+  bool mDataOwned;
+
+  RecordedGradientStopsCreation(std::istream &aStream);
+};
+
+class RecordedGradientStopsDestruction : public RecordedEvent {
+public:
+  RecordedGradientStopsDestruction(ReferencePtr aRefPtr)
+    : RecordedEvent(GRADIENTSTOPSDESTRUCTION), mRefPtr(aRefPtr)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "GradientStops Destruction"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+
+  RecordedGradientStopsDestruction(std::istream &aStream);
+};
+
+class RecordedSnapshot : public RecordedEvent {
+public:
+  RecordedSnapshot(ReferencePtr aRefPtr, DrawTarget *aDT)
+    : RecordedEvent(SNAPSHOT), mRefPtr(aRefPtr), mDT(aDT)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "Snapshot"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+  DrawTarget *mDT;
+
+  RecordedSnapshot(std::istream &aStream);
+};
+
+class RecordedScaledFontCreation : public RecordedEvent {
+public:
+  static void FontDataProc(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize, void* aBaton)
+  {
+    static_cast<RecordedScaledFontCreation*>(aBaton)->SetFontData(aData, aSize, aIndex, aGlyphSize);
+  }
+
+  RecordedScaledFontCreation(ReferencePtr aRefPtr, ScaledFont *aScaledFont)
+    : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr), mData(NULL)
+  {
+    aScaledFont->GetFontFileData(&FontDataProc, this);
+  }
+
+  ~RecordedScaledFontCreation();
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "ScaledFont Creation"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+
+  void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize);
+
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+  uint8_t *mData;
+  uint32_t mSize;
+  Float mGlyphSize;
+  uint32_t mIndex;
+
+  RecordedScaledFontCreation(std::istream &aStream);
+};
+
+class RecordedScaledFontDestruction : public RecordedEvent {
+public:
+  RecordedScaledFontDestruction(ReferencePtr aRefPtr)
+    : RecordedEvent(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+  
+  virtual std::string GetName() const { return "ScaledFont Destruction"; }
+  virtual ReferencePtr GetObject() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+
+  RecordedScaledFontDestruction(std::istream &aStream);
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/2d/RecordingTypes.h
@@ -0,0 +1,41 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_RECORDINGTYPES_H_
+#define MOZILLA_GFX_RECORDINGTYPES_H_
+
+#include <ostream>
+
+namespace mozilla {
+namespace gfx {
+
+template<class T>
+struct ElementStreamFormat
+{
+  static void Write(std::ostream &aStream, const T &aElement)
+  {
+    aStream.write(reinterpret_cast<const char*>(&aElement), sizeof(T));
+  }
+  static void Read(std::istream &aStream, T &aElement)
+  {
+    aStream.read(reinterpret_cast<char *>(&aElement), sizeof(T));
+  }
+};
+
+template<class T>
+void WriteElement(std::ostream &aStream, const T &aElement)
+{
+  ElementStreamFormat<T>::Write(aStream, aElement);
+}
+template<class T>
+void ReadElement(std::istream &aStream, T &aElement)
+{
+  ElementStreamFormat<T>::Read(aStream, aElement);
+}
+
+}
+}
+
+#endif /* MOZILLA_GFX_RECORDINGTYPES_H_ */
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -21,17 +21,18 @@ enum SurfaceType
   SURFACE_DATA, /* Data surface - bitmap in memory */
   SURFACE_D2D1_BITMAP, /* Surface wrapping a ID2D1Bitmap */
   SURFACE_D2D1_DRAWTARGET, /* Surface made from a D2D draw target */
   SURFACE_CAIRO, /* Surface wrapping a cairo surface */
   SURFACE_CAIRO_IMAGE, /* Data surface wrapping a cairo image surface */
   SURFACE_COREGRAPHICS_IMAGE, /* Surface wrapping a CoreGraphics Image */
   SURFACE_COREGRAPHICS_CGCONTEXT, /* Surface wrapping a CG context */
   SURFACE_SKIA, /* Surface wrapping a Skia bitmap */
-  SURFACE_DUAL_DT /* Snapshot of a dual drawtarget */
+  SURFACE_DUAL_DT, /* Snapshot of a dual drawtarget */
+  SURFACE_RECORDING /* Surface used for recording */
 };
 
 enum SurfaceFormat
 {
   FORMAT_B8G8R8A8,
   FORMAT_B8G8R8X8,
   FORMAT_R5G6B5,
   FORMAT_A8
@@ -39,17 +40,18 @@ enum SurfaceFormat
 
 enum BackendType
 {
   BACKEND_NONE = 0,
   BACKEND_DIRECT2D,
   BACKEND_COREGRAPHICS,
   BACKEND_COREGRAPHICS_ACCELERATED,
   BACKEND_CAIRO,
-  BACKEND_SKIA
+  BACKEND_SKIA,
+  BACKEND_RECORDING
 };
 
 enum FontType
 {
   FONT_DWRITE,
   FONT_GDI,
   FONT_MAC,
   FONT_SKIA,
--- a/gfx/2d/gfx2d.vcxproj
+++ b/gfx/2d/gfx2d.vcxproj
@@ -76,43 +76,52 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClInclude Include="2D.h" />
     <ClInclude Include="BaseMargin.h" />
     <ClInclude Include="BasePoint.h" />
     <ClInclude Include="BaseRect.h" />
     <ClInclude Include="BaseSize.h" />
+    <ClInclude Include="DrawEventRecorder.h" />
     <ClInclude Include="DrawTargetD2D.h" />
     <ClInclude Include="DrawTargetDual.h" />
+    <ClInclude Include="DrawTargetRecording.h" />
     <ClInclude Include="GradientStopsD2D.h" />
     <ClInclude Include="HelpersD2D.h" />
     <ClInclude Include="ImageScaling.h" />
     <ClInclude Include="Logging.h" />
     <ClInclude Include="Matrix.h" />
     <ClInclude Include="PathD2D.h" />
+    <ClInclude Include="PathRecording.h" />
     <ClInclude Include="Point.h" />
+    <ClInclude Include="RecordedEvent.h" />
+    <ClInclude Include="RecordingTypes.h" />
     <ClInclude Include="Rect.h" />
     <ClInclude Include="ScaledFontBase.h" />
     <ClInclude Include="ScaledFontDWrite.h" />
     <ClInclude Include="SourceSurfaceD2D.h" />
     <ClInclude Include="SourceSurfaceD2DTarget.h" />
     <ClInclude Include="SourceSurfaceRawData.h" />
     <ClInclude Include="Tools.h" />
     <ClInclude Include="Types.h" />
     <ClInclude Include="UserData.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="DrawEventRecorder.cpp" />
     <ClCompile Include="DrawTargetD2D.cpp" />
     <ClCompile Include="DrawTargetDual.cpp" />
+    <ClCompile Include="DrawTargetRecording.cpp" />
     <ClCompile Include="Factory.cpp" />
     <ClCompile Include="ImageScaling.cpp" />
     <ClCompile Include="ImageScalingSSE2.cpp" />
     <ClCompile Include="Matrix.cpp" />
     <ClCompile Include="PathD2D.cpp" />
+    <ClCompile Include="PathRecording.cpp" />
+    <ClCompile Include="RecordedEvent.cpp" />
     <ClCompile Include="ScaledFontBase.cpp" />
     <ClCompile Include="ScaledFontDWrite.cpp" />
     <ClCompile Include="SourceSurfaceD2D.cpp" />
     <ClCompile Include="SourceSurfaceD2DTarget.cpp" />
     <ClCompile Include="SourceSurfaceRawData.cpp" />
   </ItemGroup>
   <ItemGroup>
     <None Include="Makefile.in" />
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -121,16 +121,18 @@ GetBackendName(mozilla::gfx::BackendType
       case mozilla::gfx::BACKEND_COREGRAPHICS_ACCELERATED:
         return "quartz accelerated";
       case mozilla::gfx::BACKEND_COREGRAPHICS:
         return "quartz";
       case mozilla::gfx::BACKEND_CAIRO:
         return "cairo";
       case mozilla::gfx::BACKEND_SKIA:
         return "skia";
+      case mozilla::gfx::BACKEND_RECORDING:
+        return "recording";
       case mozilla::gfx::BACKEND_NONE:
         return "none";
   }
   MOZ_NOT_REACHED("Incomplete switch");
 }
 
 class THEBES_API gfxPlatform {
 public: