Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/2d/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 135 kB image not shown  

SSL RecordedEventImpl.h

  Interaktion und
PortierbarkeitC
 

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef MOZILLA_GFX_RECORDEDEVENTIMPL_H_
#define MOZILLA_GFX_RECORDEDEVENTIMPL_H_

#include "RecordedEvent.h"

#include "PathRecording.h"
#include "RecordingTypes.h"
#include "Tools.h"
#include "Filters.h"
#include "Logging.h"
#include "ScaledFontBase.h"
#include "SFNTData.h"

#include "mozilla/layers/LayersSurfaces.h"

namespace mozilla {
namespace gfx {

class RecordedDrawTargetCreation
    : public RecordedEventDerived<RecordedDrawTargetCreation> {
 public:
  RecordedDrawTargetCreation(ReferencePtr aRefPtr, BackendType aType,
                             const IntRect& aRect, SurfaceFormat aFormat,
                             bool aHasExistingData = false,
                             SourceSurface* aExistingData = nullptr)
      : RecordedEventDerived(DRAWTARGETCREATION),
        mRefPtr(aRefPtr),
        mBackendType(aType),
        mRect(aRect),
        mFormat(aFormat),
        mHasExistingData(aHasExistingData),
        mExistingData(aExistingData) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawTarget Creation"; }

  ReferencePtr mRefPtr;
  BackendType mBackendType;
  IntRect mRect;
  SurfaceFormat mFormat;
  bool mHasExistingData = false;
  RefPtr<SourceSurface> mExistingData;

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawTargetCreation(S& aStream);
};

class RecordedDrawTargetDestruction
    : public RecordedEventDerived<RecordedDrawTargetDestruction> {
 public:
  MOZ_IMPLICIT RecordedDrawTargetDestruction(ReferencePtr aRefPtr)
      : RecordedEventDerived(DRAWTARGETDESTRUCTION),
        mRefPtr(aRefPtr),
        mBackendType(BackendType::NONE) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawTarget Destruction"; }

  ReferencePtr mRefPtr;

  BackendType mBackendType;

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawTargetDestruction(S& aStream);
};

class RecordedSetCurrentDrawTarget
    : public RecordedEventDerived<RecordedSetCurrentDrawTarget> {
 public:
  MOZ_IMPLICIT RecordedSetCurrentDrawTarget(ReferencePtr aRefPtr)
      : RecordedEventDerived(SETCURRENTDRAWTARGET), mRefPtr(aRefPtr) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "SetCurrentDrawTarget"; }

  ReferencePtr mRefPtr;

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedSetCurrentDrawTarget(S& aStream);
};

class RecordedCreateSimilarDrawTarget
    : public RecordedEventDerived<RecordedCreateSimilarDrawTarget> {
 public:
  RecordedCreateSimilarDrawTarget(ReferencePtr aRefPtr, const IntSize& aSize,
                                  SurfaceFormat aFormat)
      : RecordedEventDerived(CREATESIMILARDRAWTARGET),
        mRefPtr(aRefPtr),
        mSize(aSize),
        mFormat(aFormat) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "CreateSimilarDrawTarget"; }

  ReferencePtr mRefPtr;
  IntSize mSize;
  SurfaceFormat mFormat;

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedCreateSimilarDrawTarget(S& aStream);
};

class RecordedCreateClippedDrawTarget
    : public RecordedEventDerived<RecordedCreateClippedDrawTarget> {
 public:
  RecordedCreateClippedDrawTarget(ReferencePtr aRefPtr, const Rect& aBounds,
                                  SurfaceFormat aFormat)
      : RecordedEventDerived(CREATECLIPPEDDRAWTARGET),
        mRefPtr(aRefPtr),
        mBounds(aBounds),
        mFormat(aFormat) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "CreateClippedDrawTarget"; }

  ReferencePtr mRefPtr;
  Rect mBounds;
  SurfaceFormat mFormat;

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedCreateClippedDrawTarget(S& aStream);
};

class RecordedCreateDrawTargetForFilter
    : public RecordedEventDerived<RecordedCreateDrawTargetForFilter> {
 public:
  RecordedCreateDrawTargetForFilter(ReferencePtr aRefPtr,
                                    const IntSize& aMaxSize,
                                    SurfaceFormat aFormat, FilterNode* aFilter,
                                    FilterNode* aSource,
                                    const Rect& aSourceRect,
                                    const Point& aDestPoint)
      : RecordedEventDerived(CREATEDRAWTARGETFORFILTER),
        mRefPtr(aRefPtr),
        mMaxSize(aMaxSize),
        mFormat(aFormat),
        mFilter(aFilter),
        mSource(aSource),
        mSourceRect(aSourceRect),
        mDestPoint(aDestPoint) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  std::string GetName() const override {
    return "CreateSimilarDrawTargetForFilter";
  }

  ReferencePtr mRefPtr;
  IntSize mMaxSize;
  SurfaceFormat mFormat;
  ReferencePtr mFilter;
  ReferencePtr mSource;
  Rect mSourceRect;
  Point mDestPoint;

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedCreateDrawTargetForFilter(S& aStream);
};

class RecordedFillRect : public RecordedEventDerived<RecordedFillRect> {
 public:
  RecordedFillRect(const Rect& aRect, const Pattern& aPattern,
                   const DrawOptions& aOptions)
      : RecordedEventDerived(FILLRECT),
        mRect(aRect),
        mPattern(),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "FillRect"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedFillRect(S& aStream);

  Rect mRect;
  PatternStorage mPattern;
  DrawOptions mOptions;
};

class RecordedStrokeRect : public RecordedEventDerived<RecordedStrokeRect> {
 public:
  RecordedStrokeRect(const Rect& aRect, const Pattern& aPattern,
                     const StrokeOptions& aStrokeOptions,
                     const DrawOptions& aOptions)
      : RecordedEventDerived(STROKERECT),
        mRect(aRect),
        mPattern(),
        mStrokeOptions(aStrokeOptions),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "StrokeRect"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedStrokeRect(S& aStream);

  Rect mRect;
  PatternStorage mPattern;
  StrokeOptions mStrokeOptions;
  DrawOptions mOptions;
};

class RecordedStrokeLine : public RecordedEventDerived<RecordedStrokeLine> {
 public:
  RecordedStrokeLine(const Point& aBegin, const Point& aEnd,
                     const Pattern& aPattern,
                     const StrokeOptions& aStrokeOptions,
                     const DrawOptions& aOptions)
      : RecordedEventDerived(STROKELINE),
        mBegin(aBegin),
        mEnd(aEnd),
        mPattern(),
        mStrokeOptions(aStrokeOptions),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "StrokeLine"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedStrokeLine(S& aStream);

  Point mBegin;
  Point mEnd;
  PatternStorage mPattern;
  StrokeOptions mStrokeOptions;
  DrawOptions mOptions;
};

class RecordedStrokeCircle : public RecordedEventDerived<RecordedStrokeCircle> {
 public:
  RecordedStrokeCircle(Circle aCircle, const Pattern& aPattern,
                       const StrokeOptions& aStrokeOptions,
                       const DrawOptions& aOptions)
      : RecordedEventDerived(STROKECIRCLE),
        mCircle(aCircle),
        mPattern(),
        mStrokeOptions(aStrokeOptions),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "StrokeCircle"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedStrokeCircle(S& aStream);

  Circle mCircle;
  PatternStorage mPattern;
  StrokeOptions mStrokeOptions;
  DrawOptions mOptions;
};

class RecordedFill : public RecordedEventDerived<RecordedFill> {
 public:
  RecordedFill(ReferencePtr aPath, const Pattern& aPattern,
               const DrawOptions& aOptions)
      : RecordedEventDerived(FILL),
        mPath(aPath),
        mPattern(),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Fill"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedFill(S& aStream);

  ReferencePtr mPath;
  PatternStorage mPattern;
  DrawOptions mOptions;
};

class RecordedFillCircle : public RecordedEventDerived<RecordedFillCircle> {
 public:
  RecordedFillCircle(Circle aCircle, const Pattern& aPattern,
                     const DrawOptions& aOptions)
      : RecordedEventDerived(FILLCIRCLE),
        mCircle(aCircle),
        mPattern(),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "FillCircle"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedFillCircle(S& aStream);

  Circle mCircle;
  PatternStorage mPattern;
  DrawOptions mOptions;
};

template <class Derived>
class RecordedDrawGlyphs : public RecordedEventDerived<Derived> {
 public:
  RecordedDrawGlyphs(RecordedEvent::EventType aType, ReferencePtr aScaledFont,
                     const Pattern& aPattern, const DrawOptions& aOptions,
                     const Glyph* aGlyphs, uint32_t aNumGlyphs)
      : RecordedEventDerived<Derived>(aType),
        mScaledFont(aScaledFont),
        mPattern(),
        mOptions(aOptions) {
    this->StorePattern(mPattern, aPattern);
    mNumGlyphs = aNumGlyphs;
    mGlyphs = new Glyph[aNumGlyphs];
    memcpy(mGlyphs, aGlyphs, sizeof(Glyph) * aNumGlyphs);
  }
  virtual ~RecordedDrawGlyphs();

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

 protected:
  friend class RecordedEvent;

  template <class S>
  RecordedDrawGlyphs(RecordedEvent::EventType aType, S& aStream);

  virtual void DrawGlyphs(DrawTarget* aDT, ScaledFont* aScaledFont,
                          const GlyphBuffer& aBuffer,
                          const Pattern& aPattern) const = 0;

  ReferencePtr mScaledFont;
  PatternStorage mPattern;
  DrawOptions mOptions;
  Glyph* mGlyphs = nullptr;
  uint32_t mNumGlyphs = 0;
};

class RecordedFillGlyphs : public RecordedDrawGlyphs<RecordedFillGlyphs> {
 public:
  RecordedFillGlyphs(ReferencePtr aScaledFont, const Pattern& aPattern,
                     const DrawOptions& aOptions, const Glyph* aGlyphs,
                     uint32_t aNumGlyphs)
      : RecordedDrawGlyphs(FILLGLYPHS, aScaledFont, aPattern, aOptions, aGlyphs,
                           aNumGlyphs) {}

  std::string GetName() const override { return "FillGlyphs"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedFillGlyphs(S& aStream)
      : RecordedDrawGlyphs(FILLGLYPHS, aStream) {}

  void DrawGlyphs(DrawTarget* aDT, ScaledFont* aScaledFont,
                  const GlyphBuffer& aBuffer,
                  const Pattern& aPattern) const override {
    aDT->FillGlyphs(aScaledFont, aBuffer, aPattern, mOptions);
  }
};

class RecordedStrokeGlyphs : public RecordedDrawGlyphs<RecordedStrokeGlyphs> {
 public:
  RecordedStrokeGlyphs(ReferencePtr aScaledFont, const Pattern& aPattern,
                       const StrokeOptions& aStrokeOptions,
                       const DrawOptions& aOptions, const Glyph* aGlyphs,
                       uint32_t aNumGlyphs)
      : RecordedDrawGlyphs(STROKEGLYPHS, aScaledFont, aPattern, aOptions,
                           aGlyphs, aNumGlyphs),
        mStrokeOptions(aStrokeOptions) {}

  std::string GetName() const override { return "StrokeGlyphs"; }

  template <class S>
  void Record(S& aStream) const {
    RecordedDrawGlyphs::Record(aStream);
    RecordStrokeOptions(aStream, mStrokeOptions);
  }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedStrokeGlyphs(S& aStream)
      : RecordedDrawGlyphs(STROKEGLYPHS, aStream) {
    ReadStrokeOptions(aStream, mStrokeOptions);
  }

  void DrawGlyphs(DrawTarget* aDT, ScaledFont* aScaledFont,
                  const GlyphBuffer& aBuffer,
                  const Pattern& aPattern) const override {
    aDT->StrokeGlyphs(aScaledFont, aBuffer, aPattern, mStrokeOptions, mOptions);
  }

  StrokeOptions mStrokeOptions;
};

class RecordedMask : public RecordedEventDerived<RecordedMask> {
 public:
  RecordedMask(const Pattern& aSource, const Pattern& aMask,
               const DrawOptions& aOptions)
      : RecordedEventDerived(MASK), mSource(), mMask(), mOptions(aOptions) {
    StorePattern(mSource, aSource);
    StorePattern(mMask, aMask);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Mask"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedMask(S& aStream);

  PatternStorage mSource;
  PatternStorage mMask;
  DrawOptions mOptions;
};

class RecordedStroke : public RecordedEventDerived<RecordedStroke> {
 public:
  RecordedStroke(ReferencePtr aPath, const Pattern& aPattern,
                 const StrokeOptions& aStrokeOptions,
                 const DrawOptions& aOptions)
      : RecordedEventDerived(STROKE),
        mPath(aPath),
        mPattern(),
        mStrokeOptions(aStrokeOptions),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Stroke"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedStroke(S& aStream);

  ReferencePtr mPath;
  PatternStorage mPattern;
  StrokeOptions mStrokeOptions;
  DrawOptions mOptions;
};

class RecordedClearRect : public RecordedEventDerived<RecordedClearRect> {
 public:
  explicit RecordedClearRect(const Rect& aRect)
      : RecordedEventDerived(CLEARRECT), mRect(aRect) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "ClearRect"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedClearRect(S& aStream);

  Rect mRect;
};

class RecordedCopySurface : public RecordedEventDerived<RecordedCopySurface> {
 public:
  RecordedCopySurface(ReferencePtr aSourceSurface, const IntRect& aSourceRect,
                      const IntPoint& aDest)
      : RecordedEventDerived(COPYSURFACE),
        mSourceSurface(aSourceSurface),
        mSourceRect(aSourceRect),
        mDest(aDest) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "CopySurface"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedCopySurface(S& aStream);

  ReferencePtr mSourceSurface;
  IntRect mSourceRect;
  IntPoint mDest;
};

class RecordedPushClip : public RecordedEventDerived<RecordedPushClip> {
 public:
  explicit RecordedPushClip(ReferencePtr aPath)
      : RecordedEventDerived(PUSHCLIP), mPath(aPath) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "PushClip"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedPushClip(S& aStream);

  ReferencePtr mPath;
};

class RecordedPushClipRect : public RecordedEventDerived<RecordedPushClipRect> {
 public:
  explicit RecordedPushClipRect(const Rect& aRect)
      : RecordedEventDerived(PUSHCLIPRECT), mRect(aRect) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "PushClipRect"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedPushClipRect(S& aStream);

  Rect mRect;
};

class RecordedPopClip : public RecordedEventDerived<RecordedPopClip> {
 public:
  MOZ_IMPLICIT RecordedPopClip() : RecordedEventDerived(POPCLIP) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "PopClip"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedPopClip(S& aStream);
};

class RecordedRemoveAllClips
    : public RecordedEventDerived<RecordedRemoveAllClips> {
 public:
  MOZ_IMPLICIT RecordedRemoveAllClips()
      : RecordedEventDerived(REMOVEALLCLIPS) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "RemoveAllClips"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedRemoveAllClips(S& aStream);
};

class RecordedPushLayer : public RecordedEventDerived<RecordedPushLayer> {
 public:
  RecordedPushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
                    const Matrix& aMaskTransform, const IntRect& aBounds,
                    bool aCopyBackground)
      : RecordedEventDerived(PUSHLAYER),
        mOpaque(aOpaque),
        mOpacity(aOpacity),
        mMask(aMask),
        mMaskTransform(aMaskTransform),
        mBounds(aBounds),
        mCopyBackground(aCopyBackground) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "PushLayer"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedPushLayer(S& aStream);

  bool mOpaque = false;
  Float mOpacity = 1.0f;
  ReferencePtr mMask;
  Matrix mMaskTransform;
  IntRect mBounds;
  bool mCopyBackground = false;
};

class RecordedPushLayerWithBlend
    : public RecordedEventDerived<RecordedPushLayerWithBlend> {
 public:
  RecordedPushLayerWithBlend(bool aOpaque, Float aOpacity, SourceSurface* aMask,
                             const Matrix& aMaskTransform,
                             const IntRect& aBounds, bool aCopyBackground,
                             CompositionOp aCompositionOp)
      : RecordedEventDerived(PUSHLAYERWITHBLEND),
        mOpaque(aOpaque),
        mOpacity(aOpacity),
        mMask(aMask),
        mMaskTransform(aMaskTransform),
        mBounds(aBounds),
        mCopyBackground(aCopyBackground),
        mCompositionOp(aCompositionOp) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "PushLayerWithBlend"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedPushLayerWithBlend(S& aStream);

  bool mOpaque = false;
  Float mOpacity = 1.0f;
  ReferencePtr mMask;
  Matrix mMaskTransform;
  IntRect mBounds;
  bool mCopyBackground = false;
  CompositionOp mCompositionOp = CompositionOp::OP_OVER;
};

class RecordedPopLayer : public RecordedEventDerived<RecordedPopLayer> {
 public:
  RecordedPopLayer() : RecordedEventDerived(POPLAYER) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "PopLayer"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedPopLayer(S& aStream);
};

class RecordedSetPermitSubpixelAA
    : public RecordedEventDerived<RecordedSetPermitSubpixelAA> {
 public:
  explicit RecordedSetPermitSubpixelAA(bool aPermitSubpixelAA)
      : RecordedEventDerived(SETPERMITSUBPIXELAA),
        mPermitSubpixelAA(aPermitSubpixelAA) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "SetPermitSubpixelAA"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedSetPermitSubpixelAA(S& aStream);

  bool mPermitSubpixelAA = false;
};

class RecordedSetTransform : public RecordedEventDerived<RecordedSetTransform> {
 public:
  explicit RecordedSetTransform(const Matrix& aTransform)
      : RecordedEventDerived(SETTRANSFORM), mTransform(aTransform) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "SetTransform"; }

  Matrix mTransform;

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedSetTransform(S& aStream);
};

class RecordedDrawSurface : public RecordedEventDerived<RecordedDrawSurface> {
 public:
  RecordedDrawSurface(ReferencePtr aRefSource, const Rect& aDest,
                      const Rect& aSource, const DrawSurfaceOptions& aDSOptions,
                      const DrawOptions& aOptions)
      : RecordedEventDerived(DRAWSURFACE),
        mRefSource(aRefSource),
        mDest(aDest),
        mSource(aSource),
        mDSOptions(aDSOptions),
        mOptions(aOptions) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawSurface"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawSurface(S& aStream);

  ReferencePtr mRefSource;
  Rect mDest;
  Rect mSource;
  DrawSurfaceOptions mDSOptions;
  DrawOptions mOptions;
};

class RecordedDrawSurfaceDescriptor
    : public RecordedEventDerived<RecordedDrawSurfaceDescriptor> {
 public:
  RecordedDrawSurfaceDescriptor(const layers::SurfaceDescriptor& aDesc,
                                const Rect& aDest, const Rect& aSource,
                                const DrawSurfaceOptions& aDSOptions,
                                const DrawOptions& aOptions)
      : RecordedEventDerived(DRAWSURFACEDESCRIPTOR),
        mDesc(aDesc),
        mDest(aDest),
        mSource(aSource),
        mDSOptions(aDSOptions),
        mOptions(aOptions) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawSurfaceDescriptor"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawSurfaceDescriptor(S& aStream);

  layers::SurfaceDescriptor mDesc;
  Rect mDest;
  Rect mSource;
  DrawSurfaceOptions mDSOptions;
  DrawOptions mOptions;
};

class RecordedDrawDependentSurface
    : public RecordedEventDerived<RecordedDrawDependentSurface> {
 public:
  RecordedDrawDependentSurface(uint64_t aId, const Rect& aDest)
      : RecordedEventDerived(DRAWDEPENDENTSURFACE), mId(aId), mDest(aDest) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawDependentSurface"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawDependentSurface(S& aStream);

  uint64_t mId;
  Rect mDest;
};

class RecordedDrawSurfaceWithShadow
    : public RecordedEventDerived<RecordedDrawSurfaceWithShadow> {
 public:
  RecordedDrawSurfaceWithShadow(ReferencePtr aRefSource, const Point& aDest,
                                const ShadowOptions& aShadow, CompositionOp aOp)
      : RecordedEventDerived(DRAWSURFACEWITHSHADOW),
        mRefSource(aRefSource),
        mDest(aDest),
        mShadow(aShadow),
        mOp(aOp) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawSurfaceWithShadow"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawSurfaceWithShadow(S& aStream);

  ReferencePtr mRefSource;
  Point mDest;
  ShadowOptions mShadow;
  CompositionOp mOp;
};

class RecordedDrawShadow : public RecordedEventDerived<RecordedDrawShadow> {
 public:
  RecordedDrawShadow(ReferencePtr aPath, const Pattern& aPattern,
                     const ShadowOptions& aShadow, const DrawOptions& aOptions,
                     const StrokeOptions* aStrokeOptions)
      : RecordedEventDerived(DRAWSHADOW),
        mPath(aPath),
        mPattern(),
        mShadow(aShadow),
        mOptions(aOptions),
        mHasStrokeOptions(!!aStrokeOptions),
        mStrokeOptions(aStrokeOptions ? *aStrokeOptions : StrokeOptions()) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawShadow"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawShadow(S& aStream);

  ReferencePtr mPath;
  PatternStorage mPattern;
  ShadowOptions mShadow;
  DrawOptions mOptions;
  bool mHasStrokeOptions = false;
  StrokeOptions mStrokeOptions;
};

class RecordedDrawFilter : public RecordedEventDerived<RecordedDrawFilter> {
 public:
  RecordedDrawFilter(ReferencePtr aNode, const Rect& aSourceRect,
                     const Point& aDestPoint, const DrawOptions& aOptions)
      : RecordedEventDerived(DRAWFILTER),
        mNode(aNode),
        mSourceRect(aSourceRect),
        mDestPoint(aDestPoint),
        mOptions(aOptions) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "DrawFilter"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDrawFilter(S& aStream);

  ReferencePtr mNode;
  Rect mSourceRect;
  Point mDestPoint;
  DrawOptions mOptions;
};

class RecordedPathCreation : public RecordedEventDerived<RecordedPathCreation> {
 public:
  MOZ_IMPLICIT RecordedPathCreation(PathRecording* aPath);

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Path Creation"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mDT;
  ReferencePtr mRefPtr;
  FillRule mFillRule;
  RefPtr<PathRecording> mPath;
  UniquePtr<PathOps> mPathOps;

  template <class S>
  MOZ_IMPLICIT RecordedPathCreation(S& aStream);
};

class RecordedPathDestruction
    : public RecordedEventDerived<RecordedPathDestruction> {
 public:
  MOZ_IMPLICIT RecordedPathDestruction(PathRecording* aPath)
      : RecordedEventDerived(PATHDESTRUCTION), mRefPtr(aPath) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Path Destruction"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedPathDestruction(S& aStream);
};

class RecordedSourceSurfaceCreation
    : public RecordedEventDerived<RecordedSourceSurfaceCreation> {
 public:
  RecordedSourceSurfaceCreation(ReferencePtr aRefPtr, uint8_t* aData,
                                int32_t aStride, const IntSize& aSize,
                                SurfaceFormat aFormat)
      : RecordedEventDerived(SOURCESURFACECREATION),
        mRefPtr(aRefPtr),
        mData(aData),
        mStride(aStride),
        mSize(aSize),
        mFormat(aFormat),
        mDataOwned(false) {}

  ~RecordedSourceSurfaceCreation();

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "SourceSurface Creation"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  uint8_t* mData = nullptr;
  int32_t mStride;
  IntSize mSize;
  SurfaceFormat mFormat;
  mutable bool mDataOwned;

  template <class S>
  MOZ_IMPLICIT RecordedSourceSurfaceCreation(S& aStream);
};

class RecordedSourceSurfaceDestruction
    : public RecordedEventDerived<RecordedSourceSurfaceDestruction> {
 public:
  MOZ_IMPLICIT RecordedSourceSurfaceDestruction(ReferencePtr aRefPtr)
      : RecordedEventDerived(SOURCESURFACEDESTRUCTION), mRefPtr(aRefPtr) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "SourceSurface Destruction"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedSourceSurfaceDestruction(S& aStream);
};

class RecordedOptimizeSourceSurface
    : public RecordedEventDerived<RecordedOptimizeSourceSurface> {
 public:
  RecordedOptimizeSourceSurface(ReferencePtr aSurface,
                                ReferencePtr aOptimizedSurface)
      : RecordedEventDerived(OPTIMIZESOURCESURFACE),
        mSurface(aSurface),
        mOptimizedSurface(aOptimizedSurface) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "OptimizeSourceSurface"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mSurface;
  ReferencePtr mOptimizedSurface;

  template <class S>
  MOZ_IMPLICIT RecordedOptimizeSourceSurface(S& aStream);
};

class RecordedExternalSurfaceCreation
    : public RecordedEventDerived<RecordedExternalSurfaceCreation> {
 public:
  RecordedExternalSurfaceCreation(ReferencePtr aRefPtr, const uint64_t aKey)
      : RecordedEventDerived(EXTERNALSURFACECREATION),
        mRefPtr(aRefPtr),
        mKey(aKey) {}

  ~RecordedExternalSurfaceCreation() = default;

  virtual bool PlayEvent(Translator* aTranslator) const;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const;

  virtual std::string GetName() const {
    return "SourceSurfaceSharedData Creation";
  }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  uint64_t mKey;

  template <class S>
  MOZ_IMPLICIT RecordedExternalSurfaceCreation(S& aStream);
};

class RecordedFilterNodeCreation
    : public RecordedEventDerived<RecordedFilterNodeCreation> {
 public:
  RecordedFilterNodeCreation(ReferencePtr aRefPtr, FilterType aType)
      : RecordedEventDerived(FILTERNODECREATION),
        mRefPtr(aRefPtr),
        mType(aType) {}

  ~RecordedFilterNodeCreation();

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "FilterNode Creation"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  FilterType mType;

  template <class S>
  MOZ_IMPLICIT RecordedFilterNodeCreation(S& aStream);
};

class RecordedFilterNodeDestruction
    : public RecordedEventDerived<RecordedFilterNodeDestruction> {
 public:
  MOZ_IMPLICIT RecordedFilterNodeDestruction(ReferencePtr aRefPtr)
      : RecordedEventDerived(FILTERNODEDESTRUCTION), mRefPtr(aRefPtr) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "FilterNode Destruction"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedFilterNodeDestruction(S& aStream);
};

class RecordedGradientStopsCreation
    : public RecordedEventDerived<RecordedGradientStopsCreation> {
 public:
  RecordedGradientStopsCreation(ReferencePtr aRefPtr, GradientStop* aStops,
                                uint32_t aNumStops, ExtendMode aExtendMode)
      : RecordedEventDerived(GRADIENTSTOPSCREATION),
        mRefPtr(aRefPtr),
        mStops(aStops),
        mNumStops(aNumStops),
        mExtendMode(aExtendMode),
        mDataOwned(false) {}

  ~RecordedGradientStopsCreation();

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "GradientStops Creation"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  GradientStop* mStops = nullptr;
  uint32_t mNumStops = 0;
  ExtendMode mExtendMode;
  bool mDataOwned;

  template <class S>
  MOZ_IMPLICIT RecordedGradientStopsCreation(S& aStream);
};

class RecordedGradientStopsDestruction
    : public RecordedEventDerived<RecordedGradientStopsDestruction> {
 public:
  MOZ_IMPLICIT RecordedGradientStopsDestruction(ReferencePtr aRefPtr)
      : RecordedEventDerived(GRADIENTSTOPSDESTRUCTION), mRefPtr(aRefPtr) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "GradientStops Destruction"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedGradientStopsDestruction(S& aStream);
};

class RecordedFlush : public RecordedEventDerived<RecordedFlush> {
 public:
  explicit RecordedFlush() : RecordedEventDerived(FLUSH) {}

  bool PlayEvent(Translator* aTranslator) const final;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  virtual std::string GetName() const override { return "Flush"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedFlush(S& aStream);
};

class RecordedDetachAllSnapshots
    : public RecordedEventDerived<RecordedDetachAllSnapshots> {
 public:
  explicit RecordedDetachAllSnapshots()
      : RecordedEventDerived(DETACHALLSNAPSHOTS) {}

  bool PlayEvent(Translator* aTranslator) const final;

  template <class S>
  void Record(S& aStream) const;
  virtual void OutputSimpleEventInfo(
      std::stringstream& aStringStream) const override;

  virtual std::string GetName() const override { return "DetachAllSnapshots"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedDetachAllSnapshots(S& aStream);
};

class RecordedSnapshot : public RecordedEventDerived<RecordedSnapshot> {
 public:
  explicit RecordedSnapshot(ReferencePtr aRefPtr)
      : RecordedEventDerived(SNAPSHOT), mRefPtr(aRefPtr) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Snapshot"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedSnapshot(S& aStream);
};

class RecordedIntoLuminanceSource
    : public RecordedEventDerived<RecordedIntoLuminanceSource> {
 public:
  RecordedIntoLuminanceSource(ReferencePtr aRefPtr,
                              LuminanceType aLuminanceType, float aOpacity)
      : RecordedEventDerived(INTOLUMINANCE),
        mRefPtr(aRefPtr),
        mLuminanceType(aLuminanceType),
        mOpacity(aOpacity) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "IntoLuminanceSource"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  LuminanceType mLuminanceType;
  float mOpacity;

  template <class S>
  MOZ_IMPLICIT RecordedIntoLuminanceSource(S& aStream);
};

class RecordedExtractSubrect
    : public RecordedEventDerived<RecordedExtractSubrect> {
 public:
  RecordedExtractSubrect(ReferencePtr aRefPtr, ReferencePtr aSourceSurface,
                         const IntRect& aSubrect)
      : RecordedEventDerived(EXTRACTSUBRECT),
        mRefPtr(aRefPtr),
        mSourceSurface(aSourceSurface),
        mSubrect(aSubrect) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "ExtractSubrect"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  ReferencePtr mSourceSurface;
  IntRect mSubrect;

  template <class S>
  MOZ_IMPLICIT RecordedExtractSubrect(S& aStream);
};

class RecordedFontData : public RecordedEventDerived<RecordedFontData> {
 public:
  static void FontDataProc(const uint8_t* aData, uint32_t aSize,
                           uint32_t aIndex, void* aBaton) {
    auto recordedFontData = static_cast<RecordedFontData*>(aBaton);
    recordedFontData->SetFontData(aData, aSize, aIndex);
  }

  explicit RecordedFontData(UnscaledFont* aUnscaledFont)
      : RecordedEventDerived(FONTDATA),
        mType(aUnscaledFont->GetType()),
        mFontDetails() {
    mGetFontFileDataSucceeded =
        aUnscaledFont->GetFontFileData(&FontDataProc, this) && mData;
  }

  virtual ~RecordedFontData();

  bool IsValid() const { return mGetFontFileDataSucceeded; }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Font Data"; }

  void SetFontData(const uint8_t* aData, uint32_t aSize, uint32_t aIndex);

  bool GetFontDetails(RecordedFontDetails& fontDetails);

 private:
  friend class RecordedEvent;

  FontType mType;
  uint8_t* mData = nullptr;
  RecordedFontDetails mFontDetails;

  bool mGetFontFileDataSucceeded;

  template <class S>
  MOZ_IMPLICIT RecordedFontData(S& aStream);
};

class RecordedFontDescriptor
    : public RecordedEventDerived<RecordedFontDescriptor> {
 public:
  static void FontDescCb(const uint8_t* aData, uint32_t aSize, uint32_t aIndex,
                         void* aBaton) {
    auto recordedFontDesc = static_cast<RecordedFontDescriptor*>(aBaton);
    recordedFontDesc->SetFontDescriptor(aData, aSize, aIndex);
  }

  explicit RecordedFontDescriptor(UnscaledFont* aUnscaledFont)
      : RecordedEventDerived(FONTDESC),
        mType(aUnscaledFont->GetType()),
        mIndex(0),
        mRefPtr(aUnscaledFont) {
    mHasDesc = aUnscaledFont->GetFontDescriptor(FontDescCb, this);
  }

  virtual ~RecordedFontDescriptor();

  bool IsValid() const { return mHasDesc; }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Font Desc"; }

 private:
  friend class RecordedEvent;

  void SetFontDescriptor(const uint8_t* aData, uint32_t aSize, uint32_t aIndex);

  bool mHasDesc;

  FontType mType;
  std::vector<uint8_t> mData;
  uint32_t mIndex;
  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedFontDescriptor(S& aStream);
};

class RecordedUnscaledFontCreation
    : public RecordedEventDerived<RecordedUnscaledFontCreation> {
 public:
  static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize,
                                   void* aBaton) {
    auto recordedUnscaledFontCreation =
        static_cast<RecordedUnscaledFontCreation*>(aBaton);
    recordedUnscaledFontCreation->SetFontInstanceData(aData, aSize);
  }

  RecordedUnscaledFontCreation(UnscaledFont* aUnscaledFont,
                               RecordedFontDetails aFontDetails)
      : RecordedEventDerived(UNSCALEDFONTCREATION),
        mRefPtr(aUnscaledFont),
        mFontDataKey(aFontDetails.fontDataKey),
        mIndex(aFontDetails.index) {
    aUnscaledFont->GetFontInstanceData(FontInstanceDataProc, this);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "UnscaledFont Creation"; }

  void SetFontInstanceData(const uint8_t* aData, uint32_t aSize);

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  uint64_t mFontDataKey;
  uint32_t mIndex;
  std::vector<uint8_t> mInstanceData;

  template <class S>
  MOZ_IMPLICIT RecordedUnscaledFontCreation(S& aStream);
};

class RecordedUnscaledFontDestruction
    : public RecordedEventDerived<RecordedUnscaledFontDestruction> {
 public:
  MOZ_IMPLICIT RecordedUnscaledFontDestruction(ReferencePtr aRefPtr)
      : RecordedEventDerived(UNSCALEDFONTDESTRUCTION), mRefPtr(aRefPtr) {}

  bool PlayEvent(Translator* aTranslator) const override;
  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "UnscaledFont Destruction"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedUnscaledFontDestruction(S& aStream);
};

class RecordedScaledFontCreation
    : public RecordedEventDerived<RecordedScaledFontCreation> {
 public:
  static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize,
                                   const FontVariation* aVariations,
                                   uint32_t aNumVariations, void* aBaton) {
    auto recordedScaledFontCreation =
        static_cast<RecordedScaledFontCreation*>(aBaton);
    recordedScaledFontCreation->SetFontInstanceData(aData, aSize, aVariations,
                                                    aNumVariations);
  }

  RecordedScaledFontCreation(ScaledFont* aScaledFont,
                             UnscaledFont* aUnscaledFont)
      : RecordedEventDerived(SCALEDFONTCREATION),
        mRefPtr(aScaledFont),
        mUnscaledFont(aUnscaledFont),
        mGlyphSize(aScaledFont->GetSize()) {
    aScaledFont->GetFontInstanceData(FontInstanceDataProc, this);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "ScaledFont Creation"; }

  void SetFontInstanceData(const uint8_t* aData, uint32_t aSize,
                           const FontVariation* aVariations,
                           uint32_t aNumVariations);

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;
  ReferencePtr mUnscaledFont;
  Float mGlyphSize;
  std::vector<uint8_t> mInstanceData;
  std::vector<FontVariation> mVariations;

  template <class S>
  MOZ_IMPLICIT RecordedScaledFontCreation(S& aStream);
};

class RecordedScaledFontDestruction
    : public RecordedEventDerived<RecordedScaledFontDestruction> {
 public:
  MOZ_IMPLICIT RecordedScaledFontDestruction(ReferencePtr aRefPtr)
      : RecordedEventDerived(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr) {}

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "ScaledFont Destruction"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mRefPtr;

  template <class S>
  MOZ_IMPLICIT RecordedScaledFontDestruction(S& aStream);
};

class RecordedMaskSurface : public RecordedEventDerived<RecordedMaskSurface> {
 public:
  RecordedMaskSurface(const Pattern& aPattern, ReferencePtr aRefMask,
                      const Point& aOffset, const DrawOptions& aOptions)
      : RecordedEventDerived(MASKSURFACE),
        mPattern(),
        mRefMask(aRefMask),
        mOffset(aOffset),
        mOptions(aOptions) {
    StorePattern(mPattern, aPattern);
  }

  bool PlayEvent(Translator* aTranslator) const override;

  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "MaskSurface"; }

 private:
  friend class RecordedEvent;

  template <class S>
  MOZ_IMPLICIT RecordedMaskSurface(S& aStream);

  PatternStorage mPattern;
  ReferencePtr mRefMask;
  Point mOffset;
  DrawOptions mOptions;
};

class RecordedFilterNodeSetAttribute
    : public RecordedEventDerived<RecordedFilterNodeSetAttribute> {
 public:
  enum ArgType {
    ARGTYPE_UINT32,
    ARGTYPE_BOOL,
    ARGTYPE_FLOAT,
    ARGTYPE_SIZE,
    ARGTYPE_INTSIZE,
    ARGTYPE_INTPOINT,
    ARGTYPE_RECT,
    ARGTYPE_INTRECT,
    ARGTYPE_POINT,
    ARGTYPE_MATRIX,
    ARGTYPE_MATRIX5X4,
    ARGTYPE_POINT3D,
    ARGTYPE_COLOR,
    ARGTYPE_FLOAT_ARRAY
  };

  template <typename T>
  RecordedFilterNodeSetAttribute(FilterNode* aNode, uint32_t aIndex,
                                 T aArgument, ArgType aArgType)
      : RecordedEventDerived(FILTERNODESETATTRIBUTE),
        mNode(aNode),
        mIndex(aIndex),
        mArgType(aArgType) {
    mPayload.resize(sizeof(T));
    memcpy(&mPayload.front(), &aArgument, sizeof(T));
  }

  RecordedFilterNodeSetAttribute(FilterNode* aNode, uint32_t aIndex,
                                 const Float* aFloat, uint32_t aSize)
      : RecordedEventDerived(FILTERNODESETATTRIBUTE),
        mNode(aNode),
        mIndex(aIndex),
        mArgType(ARGTYPE_FLOAT_ARRAY) {
    mPayload.resize(sizeof(Float) * aSize);
    memcpy(&mPayload.front(), aFloat, sizeof(Float) * aSize);
  }

  bool PlayEvent(Translator* aTranslator) const override;
  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "SetAttribute"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mNode;

  uint32_t mIndex;
  ArgType mArgType;
  std::vector<uint8_t> mPayload;

  template <class S>
  MOZ_IMPLICIT RecordedFilterNodeSetAttribute(S& aStream);
};

class RecordedFilterNodeSetInput
    : public RecordedEventDerived<RecordedFilterNodeSetInput> {
 public:
  RecordedFilterNodeSetInput(FilterNode* aNode, uint32_t aIndex,
                             FilterNode* aInputNode)
      : RecordedEventDerived(FILTERNODESETINPUT),
        mNode(aNode),
        mIndex(aIndex),
        mInputFilter(aInputNode),
        mInputSurface(nullptr) {}

  RecordedFilterNodeSetInput(FilterNode* aNode, uint32_t aIndex,
                             SourceSurface* aInputSurface)
      : RecordedEventDerived(FILTERNODESETINPUT),
        mNode(aNode),
        mIndex(aIndex),
        mInputFilter(nullptr),
        mInputSurface(aInputSurface) {}

  bool PlayEvent(Translator* aTranslator) const override;
  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "SetInput"; }

 private:
  friend class RecordedEvent;

  ReferencePtr mNode;
  uint32_t mIndex;
  ReferencePtr mInputFilter;
  ReferencePtr mInputSurface;

  template <class S>
  MOZ_IMPLICIT RecordedFilterNodeSetInput(S& aStream);
};

class RecordedLink : public RecordedEventDerived<RecordedLink> {
 public:
  RecordedLink(const char* aLocalDest, const char* aURI, const Rect& aRect)
      : RecordedEventDerived(LINK),
        mLocalDest(aLocalDest),
        mURI(aURI),
        mRect(aRect) {}

  bool PlayEvent(Translator* aTranslator) const override;
  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Link"; }

 private:
  friend class RecordedEvent;

  std::string mLocalDest;
  std::string mURI;
  Rect mRect;

  template <class S>
  MOZ_IMPLICIT RecordedLink(S& aStream);
};

class RecordedDestination : public RecordedEventDerived<RecordedDestination> {
 public:
  RecordedDestination(const char* aDestination, const Point& aPoint)
      : RecordedEventDerived(DESTINATION),
        mDestination(aDestination),
        mPoint(aPoint) {}

  bool PlayEvent(Translator* aTranslator) const override;
  template <class S>
  void Record(S& aStream) const;
  void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;

  std::string GetName() const override { return "Destination"; }

 private:
  friend class RecordedEvent;

  std::string mDestination;
  Point mPoint;

  template <class S>
  MOZ_IMPLICIT RecordedDestination(S& aStream);
};

static std::string NameFromBackend(BackendType aType) {
  switch (aType) {
    case BackendType::NONE:
      return "None";
    case BackendType::DIRECT2D:
      return "Direct2D";
    default:
      return "Unknown";
  }
}

template <class S>
void RecordedEvent::RecordPatternData(S& aStream,
                                      const PatternStorage& aPattern) const {
  WriteElement(aStream, aPattern.mType);

  switch (aPattern.mType) {
    case PatternType::COLOR: {
      WriteElement(aStream, *reinterpret_cast<const ColorPatternStorage*>(
                                &aPattern.mStorage));
      return;
    }
    case PatternType::LINEAR_GRADIENT: {
      WriteElement(aStream,
                   *reinterpret_cast<const LinearGradientPatternStorage*>(
                       &aPattern.mStorage));
      return;
    }
    case PatternType::RADIAL_GRADIENT: {
      WriteElement(aStream,
                   *reinterpret_cast<const RadialGradientPatternStorage*>(
                       &aPattern.mStorage));
      return;
    }
    case PatternType::CONIC_GRADIENT: {
      WriteElement(aStream,
                   *reinterpret_cast<const ConicGradientPatternStorage*>(
                       &aPattern.mStorage));
      return;
    }
    case PatternType::SURFACE: {
      WriteElement(aStream, *reinterpret_cast<const SurfacePatternStorage*>(
                                &aPattern.mStorage));
      return;
    }
    default:
      return;
  }
}

template <class S>
void RecordedEvent::ReadPatternData(S& aStream,
                                    PatternStorage& aPattern) const {
  ReadElementConstrained(aStream, aPattern.mType, PatternType::COLOR,
                         kHighestPatternType);

  switch (aPattern.mType) {
    case PatternType::COLOR: {
      ReadElement(aStream,
                  *reinterpret_cast<ColorPatternStorage*>(&aPattern.mStorage));
      return;
    }
    case PatternType::LINEAR_GRADIENT: {
      ReadElement(aStream, *reinterpret_cast<LinearGradientPatternStorage*>(
                               &aPattern.mStorage));
      return;
    }
    case PatternType::RADIAL_GRADIENT: {
      ReadElement(aStream, *reinterpret_cast<RadialGradientPatternStorage*>(
                               &aPattern.mStorage));
      return;
    }
    case PatternType::CONIC_GRADIENT: {
      ReadElement(aStream, *reinterpret_cast<ConicGradientPatternStorage*>(
                               &aPattern.mStorage));
      return;
    }
    case PatternType::SURFACE: {
      SurfacePatternStorage* sps =
          reinterpret_cast<SurfacePatternStorage*>(&aPattern.mStorage);
      ReadElement(aStream, *sps);
      if (sps->mExtend < ExtendMode::CLAMP ||
          sps->mExtend > ExtendMode::REFLECT) {
        aStream.SetIsBad();
        return;
      }

      if (sps->mSamplingFilter < SamplingFilter::GOOD ||
          sps->mSamplingFilter >= SamplingFilter::SENTINEL) {
        aStream.SetIsBad();
      }
      return;
    }
    default:
      return;
  }
}

inline void RecordedEvent::StorePattern(PatternStorage& aDestination,
                                        const Pattern& aSource) const {
  aDestination.mType = aSource.GetType();

  switch (aSource.GetType()) {
    case PatternType::COLOR: {
      reinterpret_cast<ColorPatternStorage*>(&aDestination.mStorage)->mColor =
          static_cast<const ColorPattern*>(&aSource)->mColor;
      return;
    }
    case PatternType::LINEAR_GRADIENT: {
      LinearGradientPatternStorage* store =
          reinterpret_cast<LinearGradientPatternStorage*>(
              &aDestination.mStorage);
      const LinearGradientPattern* pat =
          static_cast<const LinearGradientPattern*>(&aSource);
      store->mBegin = pat->mBegin;
      store->mEnd = pat->mEnd;
      store->mMatrix = pat->mMatrix;
      store->mStops = pat->mStops.get();
      return;
    }
    case PatternType::RADIAL_GRADIENT: {
      RadialGradientPatternStorage* store =
          reinterpret_cast<RadialGradientPatternStorage*>(
              &aDestination.mStorage);
      const RadialGradientPattern* pat =
          static_cast<const RadialGradientPattern*>(&aSource);
      store->mCenter1 = pat->mCenter1;
      store->mCenter2 = pat->mCenter2;
      store->mRadius1 = pat->mRadius1;
      store->mRadius2 = pat->mRadius2;
      store->mMatrix = pat->mMatrix;
      store->mStops = pat->mStops.get();
      return;
    }
    case PatternType::CONIC_GRADIENT: {
      ConicGradientPatternStorage* store =
          reinterpret_cast<ConicGradientPatternStorage*>(
              &aDestination.mStorage);
      const ConicGradientPattern* pat =
          static_cast<const ConicGradientPattern*>(&aSource);
      store->mCenter = pat->mCenter;
      store->mAngle = pat->mAngle;
      store->mStartOffset = pat->mStartOffset;
      store->mEndOffset = pat->mEndOffset;
      store->mMatrix = pat->mMatrix;
      store->mStops = pat->mStops.get();
      return;
    }
    case PatternType::SURFACE: {
      SurfacePatternStorage* store =
          reinterpret_cast<SurfacePatternStorage*>(&aDestination.mStorage);
      const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aSource);
      store->mExtend = pat->mExtendMode;
      store->mSamplingFilter = pat->mSamplingFilter;
      store->mMatrix = pat->mMatrix;
      store->mSurface = pat->mSurface;
      store->mSamplingRect = pat->mSamplingRect;
      return;
    }
  }
}

template <class S>
void RecordedEvent::RecordStrokeOptions(
    S& aStream, const StrokeOptions& aStrokeOptions) const {
  JoinStyle joinStyle = aStrokeOptions.mLineJoin;
  CapStyle capStyle = aStrokeOptions.mLineCap;

  WriteElement(aStream, uint64_t(aStrokeOptions.mDashLength));
  WriteElement(aStream, aStrokeOptions.mLineWidth);
  WriteElement(aStream, aStrokeOptions.mMiterLimit);
  WriteElement(aStream, joinStyle);
  WriteElement(aStream, capStyle);

  if (!aStrokeOptions.mDashPattern) {
    return;
  }

  WriteElement(aStream, aStrokeOptions.mDashOffset);
  aStream.write((char*)aStrokeOptions.mDashPattern,
                sizeof(Float) * aStrokeOptions.mDashLength);
}

template <class S>
void RecordedEvent::ReadStrokeOptions(S& aStream,
                                      StrokeOptions& aStrokeOptions) {
  uint64_t dashLength;
  JoinStyle joinStyle;
  CapStyle capStyle;

  ReadElement(aStream, dashLength);
  ReadElement(aStream, aStrokeOptions.mLineWidth);
  ReadElement(aStream, aStrokeOptions.mMiterLimit);
  ReadElementConstrained(aStream, joinStyle, JoinStyle::BEVEL,
                         JoinStyle::MITER_OR_BEVEL);
  ReadElementConstrained(aStream, capStyle, CapStyle::BUTT, CapStyle::SQUARE);
  // On 32 bit we truncate the value of dashLength.
  // See also bug 811850 for history.
  aStrokeOptions.mDashLength = size_t(dashLength);
  aStrokeOptions.mLineJoin = joinStyle;
  aStrokeOptions.mLineCap = capStyle;

  if (!aStrokeOptions.mDashLength || !aStream.good()) {
    return;
  }

  ReadElement(aStream, aStrokeOptions.mDashOffset);

  mDashPatternStorage.resize(aStrokeOptions.mDashLength);
  aStrokeOptions.mDashPattern = &mDashPatternStorage.front();
  aStream.read((char*)aStrokeOptions.mDashPattern,
               sizeof(Float) * aStrokeOptions.mDashLength);
}

template <class S>
static void ReadDrawOptions(S& aStream, DrawOptions& aDrawOptions) {
  ReadElement(aStream, aDrawOptions);
  if (aDrawOptions.mAntialiasMode < AntialiasMode::NONE ||
      aDrawOptions.mAntialiasMode > AntialiasMode::DEFAULT) {
    aStream.SetIsBad();
    return;
  }

  if (aDrawOptions.mCompositionOp < CompositionOp::OP_CLEAR ||
      aDrawOptions.mCompositionOp > CompositionOp::OP_COUNT) {
    aStream.SetIsBad();
  }
}

template <class S>
static void ReadDrawSurfaceOptions(S& aStream,
                                   DrawSurfaceOptions& aDrawSurfaceOptions) {
  ReadElement(aStream, aDrawSurfaceOptions);
  if (aDrawSurfaceOptions.mSamplingFilter < SamplingFilter::GOOD ||
      aDrawSurfaceOptions.mSamplingFilter >= SamplingFilter::SENTINEL) {
    aStream.SetIsBad();
    return;
  }

  if (aDrawSurfaceOptions.mSamplingBounds < SamplingBounds::UNBOUNDED ||
      aDrawSurfaceOptions.mSamplingBounds > SamplingBounds::BOUNDED) {
    aStream.SetIsBad();
  }
}

inline void RecordedEvent::OutputSimplePatternInfo(
    const PatternStorage& aStorage, std::stringstream& aOutput) const {
  switch (aStorage.mType) {
    case PatternType::COLOR: {
      const DeviceColor color =
          reinterpret_cast<const ColorPatternStorage*>(&aStorage.mStorage)
              ->mColor;
      aOutput << "DeviceColor: (" << color.r << ", " << color.g << ", "
              << color.b << ", " << color.a << ")";
      return;
    }
    case PatternType::LINEAR_GRADIENT: {
      const LinearGradientPatternStorage* store =
          reinterpret_cast<const LinearGradientPatternStorage*>(
              &aStorage.mStorage);

      aOutput << "LinearGradient (" << store->mBegin.x << ", "
              << store->mBegin.y << ") - (" << store->mEnd.x << ", "
              << store->mEnd.y << ") Stops: " << store->mStops;
      return;
    }
    case PatternType::RADIAL_GRADIENT: {
      const RadialGradientPatternStorage* store =
          reinterpret_cast<const RadialGradientPatternStorage*>(
              &aStorage.mStorage);
      aOutput << "RadialGradient (Center 1: (" << store->mCenter1.x << ", "
              << store->mCenter2.y << ") Radius 2: " << store->mRadius2;
      return;
    }
    case PatternType::CONIC_GRADIENT: {
      const ConicGradientPatternStorage* store =
          reinterpret_cast<const ConicGradientPatternStorage*>(
              &aStorage.mStorage);
      aOutput << "ConicGradient (Center: (" << store->mCenter.x << ", "
              << store->mCenter.y << ") Angle: " << store->mAngle
              << " Range:" << store->mStartOffset << " - " << store->mEndOffset;
      return;
    }
    case PatternType::SURFACE: {
      const SurfacePatternStorage* store =
          reinterpret_cast<const SurfacePatternStorage*>(&aStorage.mStorage);
      aOutput << "Surface (0x" << store->mSurface << ")";
      return;
    }
  }
}

inline bool RecordedDrawTargetCreation::PlayEvent(
    Translator* aTranslator) const {
  RefPtr<DrawTarget> newDT =
      aTranslator->CreateDrawTarget(mRefPtr, mRect.Size(), mFormat);

  // If we couldn't create a DrawTarget this will probably cause us to crash
  // with nullptr later in the playback, so return false to abort.
  if (!newDT) {
    return false;
  }

  if (mHasExistingData) {
    Rect dataRect(0, 0, mExistingData->GetSize().width,
                  mExistingData->GetSize().height);
    newDT->DrawSurface(mExistingData, dataRect, dataRect);
  }

  return true;
}

template <class S>
void RecordedDrawTargetCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mBackendType);
  WriteElement(aStream, mRect);
  WriteElement(aStream, mFormat);
  WriteElement(aStream, mHasExistingData);

  if (mHasExistingData) {
    MOZ_ASSERT(mExistingData);
    MOZ_ASSERT(mExistingData->GetSize() == mRect.Size());
    RefPtr<DataSourceSurface> dataSurf = mExistingData->GetDataSurface();

    DataSourceSurface::ScopedMap map(dataSurf, DataSourceSurface::READ);
    for (int y = 0; y < mRect.height; y++) {
      aStream.write((const char*)map.GetData() + y * map.GetStride(),
                    BytesPerPixel(mFormat) * mRect.width);
    }
  }
}

template <class S>
RecordedDrawTargetCreation::RecordedDrawTargetCreation(S& aStream)
    : RecordedEventDerived(DRAWTARGETCREATION), mExistingData(nullptr) {
  ReadElement(aStream, mRefPtr);
  ReadElementConstrained(aStream, mBackendType, BackendType::NONE,
                         BackendType::WEBRENDER_TEXT);
  ReadElement(aStream, mRect);
  ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32,
                         SurfaceFormat::UNKNOWN);
  ReadElement(aStream, mHasExistingData);

  if (mHasExistingData) {
    RefPtr<DataSourceSurface> dataSurf =
        Factory::CreateDataSourceSurface(mRect.Size(), mFormat);
    if (!dataSurf) {
      gfxWarning()
          << "RecordedDrawTargetCreation had to reset mHasExistingData";
      mHasExistingData = false;
      return;
    }

    DataSourceSurface::ScopedMap map(dataSurf, DataSourceSurface::READ);
    for (int y = 0; y < mRect.height; y++) {
      aStream.read((char*)map.GetData() + y * map.GetStride(),
                   BytesPerPixel(mFormat) * mRect.width);
    }
    mExistingData = dataSurf;
  }
}

inline void RecordedDrawTargetCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] DrawTarget Creation (Type: "
                << NameFromBackend(mBackendType) << ", Size: " << mRect.width
                << "x" << mRect.height << ")";
}

inline bool RecordedDrawTargetDestruction::PlayEvent(
    Translator* aTranslator) const {
  aTranslator->RemoveDrawTarget(mRefPtr);
  return true;
}

template <class S>
void RecordedDrawTargetDestruction::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedDrawTargetDestruction::RecordedDrawTargetDestruction(S& aStream)
    : RecordedEventDerived(DRAWTARGETDESTRUCTION) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedDrawTargetDestruction::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] DrawTarget Destruction";
}

inline bool RecordedSetCurrentDrawTarget::PlayEvent(
    Translator* aTranslator) const {
  return aTranslator->SetCurrentDrawTarget(mRefPtr);
}

template <class S>
void RecordedSetCurrentDrawTarget::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedSetCurrentDrawTarget::RecordedSetCurrentDrawTarget(S& aStream)
    : RecordedEventDerived(SETCURRENTDRAWTARGET) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedSetCurrentDrawTarget::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] SetCurrentDrawTarget";
}

inline bool RecordedCreateSimilarDrawTarget::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* drawTarget = aTranslator->GetCurrentDrawTarget();
  if (!drawTarget) {
    return false;
  }

  RefPtr<DrawTarget> newDT =
      drawTarget->CreateSimilarDrawTarget(mSize, mFormat);

  // If we couldn't create a DrawTarget this will probably cause us to crash
  // with nullptr later in the playback, so return false to abort.
  if (!newDT) {
    return false;
  }

  aTranslator->AddDrawTarget(mRefPtr, newDT);
  return true;
}

template <class S>
void RecordedCreateSimilarDrawTarget::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mSize);
  WriteElement(aStream, mFormat);
}

template <class S>
RecordedCreateSimilarDrawTarget::RecordedCreateSimilarDrawTarget(S& aStream)
    : RecordedEventDerived(CREATESIMILARDRAWTARGET) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mSize);
  ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32,
                         SurfaceFormat::UNKNOWN);
}

inline void RecordedCreateSimilarDrawTarget::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr
                << "] CreateSimilarDrawTarget (Size: " << mSize.width << "x"
                << mSize.height << ")";
}

inline bool RecordedCreateDrawTargetForFilter::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  IntRect baseRect = dt->GetRect();

  auto maxRect = IntRect(IntPoint(0, 0), mMaxSize);

  auto clone = dt->GetTransform();
  bool invertible = clone.Invert();
  // mSourceRect is in filter space. The filter outputs from mSourceRect need
  // to be drawn at mDestPoint in user space.
  Rect userSpaceSource = Rect(mDestPoint, mSourceRect.Size());
  if (invertible) {
    // Try to reduce the source rect so that it's not much bigger
    // than the draw target. The result is not minimal. Examples
    // are left as an exercise for the reader.
    auto destRect = IntRectToRect(baseRect);
    Rect userSpaceBounds = clone.TransformBounds(destRect);
    userSpaceSource = userSpaceSource.Intersect(userSpaceBounds);
  }

  // Compute how much we moved the top-left of the source rect by, and use that
  // to compute the new dest point, and move our intersected source rect back
  // into the (new) filter space.
  Point shift = userSpaceSource.TopLeft() - mDestPoint;
  Rect filterSpaceSource =
      Rect(mSourceRect.TopLeft() + shift, userSpaceSource.Size());

  baseRect = RoundedOut(filterSpaceSource);
  FilterNode* filter = aTranslator->LookupFilterNode(mFilter);
  if (!filter) {
    return false;
  }

  IntRect transformedRect = filter->MapRectToSource(
      baseRect, maxRect, aTranslator->LookupFilterNode(mSource));

  // Intersect with maxRect to make sure we didn't end up with something bigger
  transformedRect = transformedRect.Intersect(maxRect);

  // If we end up with an empty rect make it 1x1 so that things don't break.
  if (transformedRect.IsEmpty()) {
    transformedRect = IntRect(0, 0, 1, 1);
  }

  RefPtr<DrawTarget> newDT =
      dt->CreateSimilarDrawTarget(transformedRect.Size(), mFormat);
  if (!newDT) {
    return false;
  }
  newDT =
      gfx::Factory::CreateOffsetDrawTarget(newDT, transformedRect.TopLeft());

  // If we couldn't create a DrawTarget this will probably cause us to crash
  // with nullptr later in the playback, so return false to abort.
  if (!newDT) {
    return false;
  }

  aTranslator->AddDrawTarget(mRefPtr, newDT);
  return true;
}

inline bool RecordedCreateClippedDrawTarget::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  RefPtr<DrawTarget> newDT = dt->CreateClippedDrawTarget(mBounds, mFormat);

  // If we couldn't create a DrawTarget this will probably cause us to crash
  // with nullptr later in the playback, so return false to abort.
  if (!newDT) {
    return false;
  }

  aTranslator->AddDrawTarget(mRefPtr, newDT);
  return true;
}

template <class S>
void RecordedCreateClippedDrawTarget::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mBounds);
  WriteElement(aStream, mFormat);
}

template <class S>
RecordedCreateClippedDrawTarget::RecordedCreateClippedDrawTarget(S& aStream)
    : RecordedEventDerived(CREATECLIPPEDDRAWTARGET) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mBounds);
  ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32,
                         SurfaceFormat::UNKNOWN);
}

inline void RecordedCreateClippedDrawTarget::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] CreateClippedDrawTarget ()";
}

template <class S>
void RecordedCreateDrawTargetForFilter::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mMaxSize);
  WriteElement(aStream, mFormat);
  WriteElement(aStream, mFilter);
  WriteElement(aStream, mSource);
  WriteElement(aStream, mSourceRect);
  WriteElement(aStream, mDestPoint);
}

template <class S>
RecordedCreateDrawTargetForFilter::RecordedCreateDrawTargetForFilter(S& aStream)
    : RecordedEventDerived(CREATEDRAWTARGETFORFILTER) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mMaxSize);
  ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32,
                         SurfaceFormat::UNKNOWN);
  ReadElement(aStream, mFilter);
  ReadElement(aStream, mSource);
  ReadElement(aStream, mSourceRect);
  ReadElement(aStream, mDestPoint);
}

inline void RecordedCreateDrawTargetForFilter::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] CreateDrawTargetForFilter ()";
}

struct GenericPattern {
  GenericPattern(const PatternStorage& aStorage, Translator* aTranslator)
      : mPattern(nullptr), mTranslator(aTranslator) {
    mStorage = const_cast<PatternStorage*>(&aStorage);
  }

  ~GenericPattern() {
    if (mPattern) {
      mPattern->~Pattern();
    }
  }

  operator Pattern*() {
    switch (mStorage->mType) {
      case PatternType::COLOR:
        return new (mColPat) ColorPattern(
            reinterpret_cast<ColorPatternStorage*>(&mStorage->mStorage)
                ->mColor);
      case PatternType::SURFACE: {
        SurfacePatternStorage* storage =
            reinterpret_cast<SurfacePatternStorage*>(&mStorage->mStorage);
        mPattern = new (mSurfPat)
            SurfacePattern(mTranslator->LookupSourceSurface(storage->mSurface),
                           storage->mExtend, storage->mMatrix,
                           storage->mSamplingFilter, storage->mSamplingRect);
        return mPattern;
      }
      case PatternType::LINEAR_GRADIENT: {
        LinearGradientPatternStorage* storage =
            reinterpret_cast<LinearGradientPatternStorage*>(
                &mStorage->mStorage);
        mPattern = new (mLinGradPat) LinearGradientPattern(
            storage->mBegin, storage->mEnd,
            storage->mStops ? mTranslator->LookupGradientStops(storage->mStops)
                            : nullptr,
            storage->mMatrix);
        return mPattern;
      }
      case PatternType::RADIAL_GRADIENT: {
        RadialGradientPatternStorage* storage =
            reinterpret_cast<RadialGradientPatternStorage*>(
                &mStorage->mStorage);
        mPattern = new (mRadGradPat) RadialGradientPattern(
            storage->mCenter1, storage->mCenter2, storage->mRadius1,
            storage->mRadius2,
            storage->mStops ? mTranslator->LookupGradientStops(storage->mStops)
                            : nullptr,
            storage->mMatrix);
        return mPattern;
      }
      case PatternType::CONIC_GRADIENT: {
        ConicGradientPatternStorage* storage =
            reinterpret_cast<ConicGradientPatternStorage*>(&mStorage->mStorage);
        mPattern = new (mConGradPat) ConicGradientPattern(
            storage->mCenter, storage->mAngle, storage->mStartOffset,
            storage->mEndOffset,
            storage->mStops ? mTranslator->LookupGradientStops(storage->mStops)
                            : nullptr,
            storage->mMatrix);
        return mPattern;
      }
      default:
        return new (mColPat) ColorPattern(DeviceColor());
    }

    return mPattern;
  }

  union {
    char mColPat[sizeof(ColorPattern)];
    char mLinGradPat[sizeof(LinearGradientPattern)];
    char mRadGradPat[sizeof(RadialGradientPattern)];
    char mConGradPat[sizeof(ConicGradientPattern)];
    char mSurfPat[sizeof(SurfacePattern)];
  };

  PatternStorage* mStorage;
  Pattern* mPattern;
  Translator* mTranslator;
};

inline bool RecordedFillRect::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->FillRect(mRect, *GenericPattern(mPattern, aTranslator), mOptions);
  return true;
}

template <class S>
void RecordedFillRect::Record(S& aStream) const {
  WriteElement(aStream, mRect);
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mPattern);
}

template <class S>
RecordedFillRect::RecordedFillRect(S& aStream)
    : RecordedEventDerived(FILLRECT) {
  ReadElement(aStream, mRect);
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mPattern);
}

inline void RecordedFillRect::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "FillRect (" << mRect.X() << ", " << mRect.Y() << " - "
                << mRect.Width() << " x " << mRect.Height() << ") ";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

inline bool RecordedStrokeRect::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->StrokeRect(mRect, *GenericPattern(mPattern, aTranslator), mStrokeOptions,
                 mOptions);
  return true;
}

template <class S>
void RecordedStrokeRect::Record(S& aStream) const {
  WriteElement(aStream, mRect);
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mPattern);
  RecordStrokeOptions(aStream, mStrokeOptions);
}

template <class S>
RecordedStrokeRect::RecordedStrokeRect(S& aStream)
    : RecordedEventDerived(STROKERECT) {
  ReadElement(aStream, mRect);
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mPattern);
  ReadStrokeOptions(aStream, mStrokeOptions);
}

inline void RecordedStrokeRect::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "StrokeRect (" << mRect.X() << ", " << mRect.Y() << " - "
                << mRect.Width() << " x " << mRect.Height()
                << ") LineWidth: " << mStrokeOptions.mLineWidth << "px ";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

inline bool RecordedStrokeLine::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->StrokeLine(mBegin, mEnd, *GenericPattern(mPattern, aTranslator),
                 mStrokeOptions, mOptions);
  return true;
}

template <class S>
void RecordedStrokeLine::Record(S& aStream) const {
  WriteElement(aStream, mBegin);
  WriteElement(aStream, mEnd);
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mPattern);
  RecordStrokeOptions(aStream, mStrokeOptions);
}

template <class S>
RecordedStrokeLine::RecordedStrokeLine(S& aStream)
    : RecordedEventDerived(STROKELINE) {
  ReadElement(aStream, mBegin);
  ReadElement(aStream, mEnd);
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mPattern);
  ReadStrokeOptions(aStream, mStrokeOptions);
}

inline void RecordedStrokeLine::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "StrokeLine (" << mBegin.x << ", " << mBegin.y << " - "
                << mEnd.x << ", " << mEnd.y
                << ") LineWidth: " << mStrokeOptions.mLineWidth << "px ";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

inline bool RecordedStrokeCircle::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->StrokeCircle(mCircle.origin, mCircle.radius,
                   *GenericPattern(mPattern, aTranslator), mStrokeOptions,
                   mOptions);
  return true;
}

template <class S>
void RecordedStrokeCircle::Record(S& aStream) const {
  WriteElement(aStream, mCircle);
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mPattern);
  RecordStrokeOptions(aStream, mStrokeOptions);
}

template <class S>
RecordedStrokeCircle::RecordedStrokeCircle(S& aStream)
    : RecordedEventDerived(STROKECIRCLE) {
  ReadElement(aStream, mCircle);
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mPattern);
  ReadStrokeOptions(aStream, mStrokeOptions);
}

inline void RecordedStrokeCircle::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "StrokeCircle (" << mCircle.origin.x << ", "
                << mCircle.origin.y << " - " << mCircle.radius
                << ") LineWidth: " << mStrokeOptions.mLineWidth << "px ";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

inline bool RecordedFill::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->Fill(aTranslator->LookupPath(mPath),
           *GenericPattern(mPattern, aTranslator), mOptions);
  return true;
}

template <class S>
RecordedFill::RecordedFill(S& aStream) : RecordedEventDerived(FILL) {
  ReadElement(aStream, mPath);
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mPattern);
}

template <class S>
void RecordedFill::Record(S& aStream) const {
  WriteElement(aStream, mPath);
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mPattern);
}

inline void RecordedFill::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "Fill (" << mPath << ") ";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

inline bool RecordedFillCircle::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->FillCircle(mCircle.origin, mCircle.radius,
                 *GenericPattern(mPattern, aTranslator), mOptions);
  return true;
}

template <class S>
void RecordedFillCircle::Record(S& aStream) const {
  WriteElement(aStream, mCircle);
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mPattern);
}

template <class S>
RecordedFillCircle::RecordedFillCircle(S& aStream)
    : RecordedEventDerived(FILLCIRCLE) {
  ReadElement(aStream, mCircle);
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mPattern);
}

inline void RecordedFillCircle::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "FillCircle (" << mCircle.origin.x << ", "
                << mCircle.origin.y << " - " << mCircle.radius << ")";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

template <class T>
inline RecordedDrawGlyphs<T>::~RecordedDrawGlyphs() {
  delete[] mGlyphs;
}

template <class T>
inline bool RecordedDrawGlyphs<T>::PlayEvent(Translator* aTranslator) const {
  if (mNumGlyphs > 0 && !mGlyphs) {
    // Glyph allocation failed
    return false;
  }

  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  ScaledFont* scaledFont = aTranslator->LookupScaledFont(mScaledFont);
  if (!scaledFont) {
    return false;
  }

  GlyphBuffer buffer;
  buffer.mGlyphs = mGlyphs;
  buffer.mNumGlyphs = mNumGlyphs;
  DrawGlyphs(dt, scaledFont, buffer, *GenericPattern(mPattern, aTranslator));
  return true;
}

template <class T>
template <class S>
RecordedDrawGlyphs<T>::RecordedDrawGlyphs(RecordedEvent::EventType aType,
                                          S& aStream)
    : RecordedEventDerived<T>(aType) {
  ReadElement(aStream, mScaledFont);
  ReadDrawOptions(aStream, mOptions);
  this->ReadPatternData(aStream, mPattern);
  ReadElement(aStream, mNumGlyphs);
  if (!aStream.good() || mNumGlyphs <= 0) {
    return;
  }

  mGlyphs = new (fallible) Glyph[mNumGlyphs];
  if (!mGlyphs) {
    gfxCriticalNote << "RecordedDrawGlyphs failed to allocate glyphs of size "
                    << mNumGlyphs;
    aStream.SetIsBad();
  } else {
    aStream.read((char*)mGlyphs, sizeof(Glyph) * mNumGlyphs);
  }
}

template <class T>
template <class S>
void RecordedDrawGlyphs<T>::Record(S& aStream) const {
  WriteElement(aStream, mScaledFont);
  WriteElement(aStream, mOptions);
  this->RecordPatternData(aStream, mPattern);
  WriteElement(aStream, mNumGlyphs);
  aStream.write((char*)mGlyphs, sizeof(Glyph) * mNumGlyphs);
}

template <class T>
inline void RecordedDrawGlyphs<T>::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << this->GetName() << " (" << mScaledFont << ") ";
  this->OutputSimplePatternInfo(mPattern, aStringStream);
}

inline bool RecordedMask::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->Mask(*GenericPattern(mSource, aTranslator),
           *GenericPattern(mMask, aTranslator), mOptions);
  return true;
}

template <class S>
RecordedMask::RecordedMask(S& aStream) : RecordedEventDerived(MASK) {
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mSource);
  ReadPatternData(aStream, mMask);
}

template <class S>
void RecordedMask::Record(S& aStream) const {
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mSource);
  RecordPatternData(aStream, mMask);
}

inline void RecordedMask::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "Mask (Source: ";
  OutputSimplePatternInfo(mSource, aStringStream);
  aStringStream << " Mask: ";
  OutputSimplePatternInfo(mMask, aStringStream);
}

inline bool RecordedStroke::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  Path* path = aTranslator->LookupPath(mPath);
  if (!path) {
    return false;
  }

  dt->Stroke(path, *GenericPattern(mPattern, aTranslator), mStrokeOptions,
             mOptions);
  return true;
}

template <class S>
void RecordedStroke::Record(S& aStream) const {
  WriteElement(aStream, mPath);
  WriteElement(aStream, mOptions);
  RecordPatternData(aStream, mPattern);
  RecordStrokeOptions(aStream, mStrokeOptions);
}

template <class S>
RecordedStroke::RecordedStroke(S& aStream) : RecordedEventDerived(STROKE) {
  ReadElement(aStream, mPath);
  ReadDrawOptions(aStream, mOptions);
  ReadPatternData(aStream, mPattern);
  ReadStrokeOptions(aStream, mStrokeOptions);
}

inline void RecordedStroke::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "Stroke (" << mPath
                << ") LineWidth: " << mStrokeOptions.mLineWidth << "px ";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

inline bool RecordedClearRect::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->ClearRect(mRect);
  return true;
}

template <class S>
void RecordedClearRect::Record(S& aStream) const {
  WriteElement(aStream, mRect);
}

template <class S>
RecordedClearRect::RecordedClearRect(S& aStream)
    : RecordedEventDerived(CLEARRECT) {
  ReadElement(aStream, mRect);
}

inline void RecordedClearRect::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "ClearRect (" << mRect.X() << ", " << mRect.Y() << " - "
                << mRect.Width() << " x " << mRect.Height() << ") ";
}

inline bool RecordedCopySurface::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  SourceSurface* surface = aTranslator->LookupSourceSurface(mSourceSurface);
  if (!surface) {
    return false;
  }

  dt->CopySurface(surface, mSourceRect, mDest);
  return true;
}

template <class S>
void RecordedCopySurface::Record(S& aStream) const {
  WriteElement(aStream, mSourceSurface);
  WriteElement(aStream, mSourceRect);
  WriteElement(aStream, mDest);
}

template <class S>
RecordedCopySurface::RecordedCopySurface(S& aStream)
    : RecordedEventDerived(COPYSURFACE) {
  ReadElement(aStream, mSourceSurface);
  ReadElement(aStream, mSourceRect);
  ReadElement(aStream, mDest);
}

inline void RecordedCopySurface::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "CopySurface (" << mSourceSurface << ")";
}

inline bool RecordedPushClip::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  Path* path = aTranslator->LookupPath(mPath);
  if (!path) {
    return false;
  }

  dt->PushClip(path);
  return true;
}

template <class S>
void RecordedPushClip::Record(S& aStream) const {
  WriteElement(aStream, mPath);
}

template <class S>
RecordedPushClip::RecordedPushClip(S& aStream)
    : RecordedEventDerived(PUSHCLIP) {
  ReadElement(aStream, mPath);
}

inline void RecordedPushClip::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "PushClip (" << mPath << ") ";
}

inline bool RecordedPushClipRect::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->PushClipRect(mRect);
  return true;
}

template <class S>
void RecordedPushClipRect::Record(S& aStream) const {
  WriteElement(aStream, mRect);
}

template <class S>
RecordedPushClipRect::RecordedPushClipRect(S& aStream)
    : RecordedEventDerived(PUSHCLIPRECT) {
  ReadElement(aStream, mRect);
}

inline void RecordedPushClipRect::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "PushClipRect (" << mRect.X() << ", " << mRect.Y() << " - "
                << mRect.Width() << " x " << mRect.Height() << ") ";
}

inline bool RecordedPopClip::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->PopClip();
  return true;
}

template <class S>
void RecordedPopClip::Record(S& aStream) const {}

template <class S>
RecordedPopClip::RecordedPopClip(S& aStream) : RecordedEventDerived(POPCLIP) {}

inline void RecordedPopClip::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "PopClip";
}

inline bool RecordedRemoveAllClips::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->RemoveAllClips();
  return true;
}

template <class S>
void RecordedRemoveAllClips::Record(S& aStream) const {}

template <class S>
RecordedRemoveAllClips::RecordedRemoveAllClips(S& aStream)
    : RecordedEventDerived(REMOVEALLCLIPS) {}

inline void RecordedRemoveAllClips::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "RemoveAllClips";
}

inline bool RecordedPushLayer::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  SourceSurface* mask =
      mMask ? aTranslator->LookupSourceSurface(mMask) : nullptr;
  dt->PushLayer(mOpaque, mOpacity, mask, mMaskTransform, mBounds,
                mCopyBackground);
  return true;
}

template <class S>
void RecordedPushLayer::Record(S& aStream) const {
  WriteElement(aStream, mOpaque);
  WriteElement(aStream, mOpacity);
  WriteElement(aStream, mMask);
  WriteElement(aStream, mMaskTransform);
  WriteElement(aStream, mBounds);
  WriteElement(aStream, mCopyBackground);
}

template <class S>
RecordedPushLayer::RecordedPushLayer(S& aStream)
    : RecordedEventDerived(PUSHLAYER) {
  ReadElement(aStream, mOpaque);
  ReadElement(aStream, mOpacity);
  ReadElement(aStream, mMask);
  ReadElement(aStream, mMaskTransform);
  ReadElement(aStream, mBounds);
  ReadElement(aStream, mCopyBackground);
}

inline void RecordedPushLayer::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "PushPLayer (Opaque=" << mOpaque << ", Opacity=" << mOpacity
                << ", Mask Ref=" << mMask << ") ";
}

inline bool RecordedPushLayerWithBlend::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  SourceSurface* mask =
      mMask ? aTranslator->LookupSourceSurface(mMask) : nullptr;
  dt->PushLayerWithBlend(mOpaque, mOpacity, mask, mMaskTransform, mBounds,
                         mCopyBackground, mCompositionOp);
  return true;
}

template <class S>
void RecordedPushLayerWithBlend::Record(S& aStream) const {
  WriteElement(aStream, mOpaque);
  WriteElement(aStream, mOpacity);
  WriteElement(aStream, mMask);
  WriteElement(aStream, mMaskTransform);
  WriteElement(aStream, mBounds);
  WriteElement(aStream, mCopyBackground);
  WriteElement(aStream, mCompositionOp);
}

template <class S>
RecordedPushLayerWithBlend::RecordedPushLayerWithBlend(S& aStream)
    : RecordedEventDerived(PUSHLAYERWITHBLEND) {
  ReadElement(aStream, mOpaque);
  ReadElement(aStream, mOpacity);
  ReadElement(aStream, mMask);
  ReadElement(aStream, mMaskTransform);
  ReadElement(aStream, mBounds);
  ReadElement(aStream, mCopyBackground);
  ReadElementConstrained(aStream, mCompositionOp, CompositionOp::OP_OVER,
                         CompositionOp::OP_COUNT);
}

inline void RecordedPushLayerWithBlend::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "PushLayerWithBlend (Opaque=" << mOpaque
                << ", Opacity=" << mOpacity << ", Mask Ref=" << mMask << ") ";
}

inline bool RecordedPopLayer::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->PopLayer();
  return true;
}

template <class S>
void RecordedPopLayer::Record(S& aStream) const {}

template <class S>
RecordedPopLayer::RecordedPopLayer(S& aStream)
    : RecordedEventDerived(POPLAYER) {}

inline void RecordedPopLayer::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "PopLayer";
}

inline bool RecordedSetPermitSubpixelAA::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->SetPermitSubpixelAA(mPermitSubpixelAA);
  return true;
}

template <class S>
void RecordedSetPermitSubpixelAA::Record(S& aStream) const {
  WriteElement(aStream, mPermitSubpixelAA);
}

template <class S>
RecordedSetPermitSubpixelAA::RecordedSetPermitSubpixelAA(S& aStream)
    : RecordedEventDerived(SETPERMITSUBPIXELAA) {
  ReadElement(aStream, mPermitSubpixelAA);
}

inline void RecordedSetPermitSubpixelAA::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "SetPermitSubpixelAA (" << mPermitSubpixelAA << ")";
}

inline bool RecordedSetTransform::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  // If we're drawing to the reference DT, then we need to manually apply
  // its initial transform, otherwise we'll just clobber it with only the
  // the transform that was visible to the code doing the recording.
  if (dt == aTranslator->GetReferenceDrawTarget()) {
    dt->SetTransform(mTransform *
                     aTranslator->GetReferenceDrawTargetTransform());
  } else {
    dt->SetTransform(mTransform);
  }

  return true;
}

template <class S>
void RecordedSetTransform::Record(S& aStream) const {
  WriteElement(aStream, mTransform);
}

template <class S>
RecordedSetTransform::RecordedSetTransform(S& aStream)
    : RecordedEventDerived(SETTRANSFORM) {
  ReadElement(aStream, mTransform);
}

inline void RecordedSetTransform::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "SetTransform [ " << mTransform._11 << " " << mTransform._12
                << " ; " << mTransform._21 << " " << mTransform._22 << " ; "
                << mTransform._31 << " " << mTransform._32 << " ]";
}

inline bool RecordedDrawSurface::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  SourceSurface* surface = aTranslator->LookupSourceSurface(mRefSource);
  if (!surface) {
    return false;
  }

  dt->DrawSurface(surface, mDest, mSource, mDSOptions, mOptions);
  return true;
}

template <class S>
void RecordedDrawSurface::Record(S& aStream) const {
  WriteElement(aStream, mRefSource);
  WriteElement(aStream, mDest);
  WriteElement(aStream, mSource);
  WriteElement(aStream, mDSOptions);
  WriteElement(aStream, mOptions);
}

template <class S>
RecordedDrawSurface::RecordedDrawSurface(S& aStream)
    : RecordedEventDerived(DRAWSURFACE) {
  ReadElement(aStream, mRefSource);
  ReadElement(aStream, mDest);
  ReadElement(aStream, mSource);
  ReadDrawSurfaceOptions(aStream, mDSOptions);
  ReadDrawOptions(aStream, mOptions);
}

inline void RecordedDrawSurface::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "DrawSurface (" << mRefSource << ")";
}

inline bool RecordedDrawSurfaceDescriptor::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  RefPtr<SourceSurface> surface =
      aTranslator->LookupSourceSurfaceFromSurfaceDescriptor(mDesc);
  if (!surface) {
    return false;
  }

  RefPtr<SourceSurface> opt = dt->OptimizeSourceSurface(surface);
  if (opt) {
    surface = opt;
  }

  dt->DrawSurface(surface, mDest, mSource, mDSOptions, mOptions);
  return true;
}

template <class S>
void RecordedDrawSurfaceDescriptor::Record(S& aStream) const {
  WriteElement(aStream, mDesc);
  WriteElement(aStream, mDest);
  WriteElement(aStream, mSource);
  WriteElement(aStream, mDSOptions);
  WriteElement(aStream, mOptions);
}

template <class S>
RecordedDrawSurfaceDescriptor::RecordedDrawSurfaceDescriptor(S& aStream)
    : RecordedEventDerived(DRAWSURFACEDESCRIPTOR) {
  ReadElement(aStream, mDesc);
  ReadElement(aStream, mDest);
  ReadElement(aStream, mSource);
  ReadDrawSurfaceOptions(aStream, mDSOptions);
  ReadDrawOptions(aStream, mOptions);
}

inline void RecordedDrawSurfaceDescriptor::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "DrawSurfaceDescriptor (" << mDesc.type() << ")";
}

inline bool RecordedDrawDependentSurface::PlayEvent(
    Translator* aTranslator) const {
  aTranslator->DrawDependentSurface(mId, mDest);
  return true;
}

template <class S>
void RecordedDrawDependentSurface::Record(S& aStream) const {
  WriteElement(aStream, mId);
  WriteElement(aStream, mDest);
}

template <class S>
RecordedDrawDependentSurface::RecordedDrawDependentSurface(S& aStream)
    : RecordedEventDerived(DRAWDEPENDENTSURFACE) {
  ReadElement(aStream, mId);
  ReadElement(aStream, mDest);
}

inline void RecordedDrawDependentSurface::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "DrawDependentSurface (" << mId << ")";
}

inline bool RecordedDrawFilter::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  FilterNode* filter = aTranslator->LookupFilterNode(mNode);
  if (!filter) {
    return false;
  }

  dt->DrawFilter(filter, mSourceRect, mDestPoint, mOptions);
  return true;
}

template <class S>
void RecordedDrawFilter::Record(S& aStream) const {
  WriteElement(aStream, mNode);
  WriteElement(aStream, mSourceRect);
  WriteElement(aStream, mDestPoint);
  WriteElement(aStream, mOptions);
}

template <class S>
RecordedDrawFilter::RecordedDrawFilter(S& aStream)
    : RecordedEventDerived(DRAWFILTER) {
  ReadElement(aStream, mNode);
  ReadElement(aStream, mSourceRect);
  ReadElement(aStream, mDestPoint);
  ReadDrawOptions(aStream, mOptions);
}

inline void RecordedDrawFilter::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "DrawFilter (" << mNode << ")";
}

inline bool RecordedDrawSurfaceWithShadow::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  SourceSurface* surface = aTranslator->LookupSourceSurface(mRefSource);
  if (!surface) {
    return false;
  }

  dt->DrawSurfaceWithShadow(surface, mDest, mShadow, mOp);
  return true;
}

template <class S>
void RecordedDrawSurfaceWithShadow::Record(S& aStream) const {
  WriteElement(aStream, mRefSource);
  WriteElement(aStream, mDest);
  WriteElement(aStream, mShadow);
  WriteElement(aStream, mOp);
}

template <class S>
RecordedDrawSurfaceWithShadow::RecordedDrawSurfaceWithShadow(S& aStream)
    : RecordedEventDerived(DRAWSURFACEWITHSHADOW) {
  ReadElement(aStream, mRefSource);
  ReadElement(aStream, mDest);
  ReadElement(aStream, mShadow);
  ReadElementConstrained(aStream, mOp, CompositionOp::OP_OVER,
                         CompositionOp::OP_COUNT);
}

inline void RecordedDrawSurfaceWithShadow::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "DrawSurfaceWithShadow (" << mRefSource << ") DeviceColor: ("
                << mShadow.mColor.r << ", " << mShadow.mColor.g << ", "
                << mShadow.mColor.b << ", " << mShadow.mColor.a << ")";
}

inline bool RecordedDrawShadow::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  Path* path = aTranslator->LookupPath(mPath);
  if (!path) {
    return false;
  }

  dt->DrawShadow(path, *GenericPattern(mPattern, aTranslator), mShadow,
                 mOptions, mHasStrokeOptions ? &mStrokeOptions : nullptr);
  return true;
}

template <class S>
void RecordedDrawShadow::Record(S& aStream) const {
  WriteElement(aStream, mPath);
  RecordPatternData(aStream, mPattern);
  WriteElement(aStream, mShadow);
  WriteElement(aStream, mOptions);
  WriteElement(aStream, mHasStrokeOptions);
  if (mHasStrokeOptions) {
    RecordStrokeOptions(aStream, mStrokeOptions);
  }
}

template <class S>
RecordedDrawShadow::RecordedDrawShadow(S& aStream)
    : RecordedEventDerived(DRAWSHADOW) {
  ReadElement(aStream, mPath);
  ReadPatternData(aStream, mPattern);
  ReadElement(aStream, mShadow);
  ReadDrawOptions(aStream, mOptions);
  ReadElement(aStream, mHasStrokeOptions);
  if (mHasStrokeOptions) {
    ReadStrokeOptions(aStream, mStrokeOptions);
  }
}

inline void RecordedDrawShadow::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "DrawShadow (" << mPath << ") DeviceColor: ("
                << mShadow.mColor.r << ", " << mShadow.mColor.g << ", "
                << mShadow.mColor.b << ", " << mShadow.mColor.a << ")";
}

inline RecordedPathCreation::RecordedPathCreation(PathRecording* aPath)
    : RecordedEventDerived(PATHCREATION),
      mRefPtr(aPath),
      mFillRule(aPath->mFillRule),
      mPath(aPath) {}

inline bool RecordedPathCreation::PlayEvent(Translator* aTranslator) const {
  DrawTarget* drawTarget = aTranslator->GetCurrentDrawTarget();
  if (!drawTarget) {
    return false;
  }

  RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(mFillRule);
  if (!mPathOps->CheckedStreamToSink(*builder)) {
    return false;
  }

  RefPtr<Path> path = builder->Finish();
  aTranslator->AddPath(mRefPtr, path);
  return true;
}

template <class S>
void RecordedPathCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mFillRule);
  mPath->mPathOps.Record(aStream);
}

template <class S>
RecordedPathCreation::RecordedPathCreation(S& aStream)
    : RecordedEventDerived(PATHCREATION) {
  ReadElement(aStream, mRefPtr);
  ReadElementConstrained(aStream, mFillRule, FillRule::FILL_WINDING,
                         FillRule::FILL_EVEN_ODD);
  mPathOps = MakeUnique<PathOps>(aStream);
}

inline void RecordedPathCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  size_t numberOfOps =
      mPath ? mPath->mPathOps.NumberOfOps() : mPathOps->NumberOfOps();
  aStringStream << "[" << mRefPtr << "] Path created (OpCount: " << numberOfOps
                << ")";
}
inline bool RecordedPathDestruction::PlayEvent(Translator* aTranslator) const {
  aTranslator->RemovePath(mRefPtr);
  return true;
}

template <class S>
void RecordedPathDestruction::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedPathDestruction::RecordedPathDestruction(S& aStream)
    : RecordedEventDerived(PATHDESTRUCTION) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedPathDestruction::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] Path Destroyed";
}

inline RecordedSourceSurfaceCreation::~RecordedSourceSurfaceCreation() {
  if (mDataOwned) {
    delete[] mData;
  }
}

inline bool RecordedSourceSurfaceCreation::PlayEvent(
    Translator* aTranslator) const {
  if (!mData) {
    return false;
  }

  RefPtr<SourceSurface> src = Factory::CreateWrappingDataSourceSurface(
      mData, mSize.width * BytesPerPixel(mFormat), mSize, mFormat,
      [](void* aClosure) { delete[] static_cast<uint8_t*>(aClosure); }, mData);
  if (src) {
    mDataOwned = false;
  }

  aTranslator->AddSourceSurface(mRefPtr, src);
  return true;
}

template <class S>
void RecordedSourceSurfaceCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mSize);
  WriteElement(aStream, mFormat);
  MOZ_ASSERT(mData);
  size_t dataFormatWidth = BytesPerPixel(mFormat) * mSize.width;
  const char* endSrc = (const char*)(mData + (mSize.height * mStride));
  for (const char* src = (const char*)mData; src < endSrc; src += mStride) {
    aStream.write(src, dataFormatWidth);
  }
}

template <class S>
RecordedSourceSurfaceCreation::RecordedSourceSurfaceCreation(S& aStream)
    : RecordedEventDerived(SOURCESURFACECREATION), mDataOwned(true) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mSize);
  ReadElementConstrained(aStream, mFormat, SurfaceFormat::A8R8G8B8_UINT32,
                         SurfaceFormat::UNKNOWN);

  if (!Factory::AllowedSurfaceSize(mSize)) {
    gfxCriticalNote << "RecordedSourceSurfaceCreation read invalid size "
                    << mSize;
    aStream.SetIsBad();
  }

  if (!aStream.good()) {
    return;
  }

  size_t size = 0;
  if (mSize.width >= 0 && mSize.height >= 0) {
    size = size_t(mSize.width) * size_t(mSize.height) * BytesPerPixel(mFormat);
    mData = new (fallible) uint8_t[size];
  }
  if (!mData) {
    gfxCriticalNote
        << "RecordedSourceSurfaceCreation failed to allocate data of size "
        << size;
    aStream.SetIsBad();
  } else {
    aStream.read((char*)mData, size);
  }
}

inline void RecordedSourceSurfaceCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr
                << "] SourceSurface created (Size: " << mSize.width << "x"
                << mSize.height << ")";
}

inline bool RecordedSourceSurfaceDestruction::PlayEvent(
    Translator* aTranslator) const {
  aTranslator->RemoveSourceSurface(mRefPtr);
  return true;
}

template <class S>
void RecordedSourceSurfaceDestruction::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedSourceSurfaceDestruction::RecordedSourceSurfaceDestruction(S& aStream)
    : RecordedEventDerived(SOURCESURFACEDESTRUCTION) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedSourceSurfaceDestruction::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] SourceSurface Destroyed";
}

inline bool RecordedOptimizeSourceSurface::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  SourceSurface* surface = aTranslator->LookupSourceSurface(mSurface);
  if (!surface) {
    return false;
  }

  RefPtr<SourceSurface> optimizedSurface = dt->OptimizeSourceSurface(surface);
  aTranslator->AddSourceSurface(mOptimizedSurface, optimizedSurface);
  return true;
}

template <class S>
void RecordedOptimizeSourceSurface::Record(S& aStream) const {
  WriteElement(aStream, mSurface);
  WriteElement(aStream, mOptimizedSurface);
}

template <class S>
RecordedOptimizeSourceSurface::RecordedOptimizeSourceSurface(S& aStream)
    : RecordedEventDerived(OPTIMIZESOURCESURFACE) {
  ReadElement(aStream, mSurface);
  ReadElement(aStream, mOptimizedSurface);
}

inline void RecordedOptimizeSourceSurface::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mSurface << "] Surface Optimized";
}

inline bool RecordedExternalSurfaceCreation::PlayEvent(
    Translator* aTranslator) const {
  RefPtr<SourceSurface> surface = aTranslator->LookupExternalSurface(mKey);
  if (!surface) {
    return false;
  }

  aTranslator->AddSourceSurface(mRefPtr, surface);
  return true;
}

template <class S>
void RecordedExternalSurfaceCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mKey);
}

template <class S>
RecordedExternalSurfaceCreation::RecordedExternalSurfaceCreation(S& aStream)
    : RecordedEventDerived(EXTERNALSURFACECREATION) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mKey);
}

inline void RecordedExternalSurfaceCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr
                << "] SourceSurfaceSharedData created (Key: " << mKey << ")";
}

inline RecordedFilterNodeCreation::~RecordedFilterNodeCreation() = default;

inline bool RecordedFilterNodeCreation::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* drawTarget = aTranslator->GetCurrentDrawTarget();
  if (!drawTarget) {
    return false;
  }

  RefPtr<FilterNode> node = drawTarget->CreateFilter(mType);
  aTranslator->AddFilterNode(mRefPtr, node);
  return true;
}

template <class S>
void RecordedFilterNodeCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mType);
}

template <class S>
RecordedFilterNodeCreation::RecordedFilterNodeCreation(S& aStream)
    : RecordedEventDerived(FILTERNODECREATION) {
  ReadElement(aStream, mRefPtr);
  ReadElementConstrained(aStream, mType, FilterType::BLEND,
                         FilterType::OPACITY);
}

inline void RecordedFilterNodeCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "CreateFilter [" << mRefPtr
                << "] FilterNode created (Type: " << int(mType) << ")";
}

inline bool RecordedFilterNodeDestruction::PlayEvent(
    Translator* aTranslator) const {
  aTranslator->RemoveFilterNode(mRefPtr);
  return true;
}

template <class S>
void RecordedFilterNodeDestruction::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedFilterNodeDestruction::RecordedFilterNodeDestruction(S& aStream)
    : RecordedEventDerived(FILTERNODEDESTRUCTION) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedFilterNodeDestruction::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] FilterNode Destroyed";
}

inline RecordedGradientStopsCreation::~RecordedGradientStopsCreation() {
  if (mDataOwned) {
    delete[] mStops;
  }
}

inline bool RecordedGradientStopsCreation::PlayEvent(
    Translator* aTranslator) const {
  if (mNumStops > 0 && !mStops) {
    // Stops allocation failed
    return false;
  }

  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  RefPtr<GradientStops> src =
      aTranslator->GetOrCreateGradientStops(dt, mStops, mNumStops, mExtendMode);
  aTranslator->AddGradientStops(mRefPtr, src);
  return true;
}

template <class S>
void RecordedGradientStopsCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mExtendMode);
  WriteElement(aStream, mNumStops);
  aStream.write((const char*)mStops, mNumStops * sizeof(GradientStop));
}

template <class S>
RecordedGradientStopsCreation::RecordedGradientStopsCreation(S& aStream)
    : RecordedEventDerived(GRADIENTSTOPSCREATION), mDataOwned(true) {
  ReadElement(aStream, mRefPtr);
  ReadElementConstrained(aStream, mExtendMode, ExtendMode::CLAMP,
                         ExtendMode::REFLECT);
  ReadElement(aStream, mNumStops);
  if (!aStream.good() || mNumStops <= 0) {
    return;
  }

  mStops = new (fallible) GradientStop[mNumStops];
  if (!mStops) {
    gfxCriticalNote
        << "RecordedGradientStopsCreation failed to allocate stops of size "
        << mNumStops;
    aStream.SetIsBad();
  } else {
    aStream.read((char*)mStops, mNumStops * sizeof(GradientStop));
  }
}

inline void RecordedGradientStopsCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr
                << "] GradientStops created (Stops: " << mNumStops << ")";
}

inline bool RecordedGradientStopsDestruction::PlayEvent(
    Translator* aTranslator) const {
  aTranslator->RemoveGradientStops(mRefPtr);
  return true;
}

template <class S>
void RecordedGradientStopsDestruction::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedGradientStopsDestruction::RecordedGradientStopsDestruction(S& aStream)
    : RecordedEventDerived(GRADIENTSTOPSDESTRUCTION) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedGradientStopsDestruction::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] GradientStops Destroyed";
}

inline bool RecordedIntoLuminanceSource::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  RefPtr<SourceSurface> src = dt->IntoLuminanceSource(mLuminanceType, mOpacity);
  aTranslator->AddSourceSurface(mRefPtr, src);
  return true;
}

template <class S>
void RecordedIntoLuminanceSource::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mLuminanceType);
  WriteElement(aStream, mOpacity);
}

template <class S>
RecordedIntoLuminanceSource::RecordedIntoLuminanceSource(S& aStream)
    : RecordedEventDerived(INTOLUMINANCE) {
  ReadElement(aStream, mRefPtr);
  ReadElementConstrained(aStream, mLuminanceType, LuminanceType::LUMINANCE,
                         LuminanceType::LINEARRGB);
  ReadElement(aStream, mOpacity);
}

inline void RecordedIntoLuminanceSource::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] Into Luminance Source";
}

inline bool RecordedExtractSubrect::PlayEvent(Translator* aTranslator) const {
  SourceSurface* sourceSurf = aTranslator->LookupSourceSurface(mSourceSurface);
  if (!sourceSurf) {
    return false;
  }

  RefPtr<SourceSurface> subSurf = sourceSurf->ExtractSubrect(mSubrect);
  if (!subSurf) {
    RefPtr<DrawTarget> dt =
        aTranslator->GetReferenceDrawTarget()->CreateSimilarDrawTarget(
            mSubrect.Size(), sourceSurf->GetFormat());
    if (dt) {
      dt->CopySurface(sourceSurf, mSubrect, IntPoint());
      subSurf = dt->Snapshot();
    }
  }
  if (!subSurf) {
    return false;
  }

  aTranslator->AddSourceSurface(mRefPtr, subSurf);
  return true;
}

template <class S>
void RecordedExtractSubrect::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mSourceSurface);
  WriteElement(aStream, mSubrect);
}

template <class S>
RecordedExtractSubrect::RecordedExtractSubrect(S& aStream)
    : RecordedEventDerived(EXTRACTSUBRECT) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mSourceSurface);
  ReadElement(aStream, mSubrect);
}

inline void RecordedExtractSubrect::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] Exract Subrect";
}

inline bool RecordedFlush::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->Flush();
  return true;
}

template <class S>
void RecordedFlush::Record(S& aStream) const {}

template <class S>
RecordedFlush::RecordedFlush(S& aStream) : RecordedEventDerived(FLUSH) {}

inline void RecordedFlush::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "Flush";
}

inline bool RecordedDetachAllSnapshots::PlayEvent(
    Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  dt->DetachAllSnapshots();
  return true;
}

template <class S>
void RecordedDetachAllSnapshots::Record(S& aStream) const {}

template <class S>
RecordedDetachAllSnapshots::RecordedDetachAllSnapshots(S& aStream)
    : RecordedEventDerived(DETACHALLSNAPSHOTS) {}

inline void RecordedDetachAllSnapshots::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "DetachAllSnapshots";
}

inline bool RecordedSnapshot::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  RefPtr<SourceSurface> src = dt->Snapshot();
  aTranslator->AddSourceSurface(mRefPtr, src);
  return true;
}

template <class S>
void RecordedSnapshot::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedSnapshot::RecordedSnapshot(S& aStream)
    : RecordedEventDerived(SNAPSHOT) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedSnapshot::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] Snapshot Created";
}

inline RecordedFontData::~RecordedFontData() { delete[] mData; }

inline bool RecordedFontData::PlayEvent(Translator* aTranslator) const {
  if (!mData) {
    return false;
  }

  RefPtr<NativeFontResource> fontResource = Factory::CreateNativeFontResource(
      mData, mFontDetails.size, mType, aTranslator->GetFontContext());
  if (!fontResource) {
    return false;
  }

  aTranslator->AddNativeFontResource(mFontDetails.fontDataKey, fontResource);
  return true;
}

template <class S>
void RecordedFontData::Record(S& aStream) const {
  MOZ_ASSERT(mGetFontFileDataSucceeded);

  WriteElement(aStream, mType);
  WriteElement(aStream, mFontDetails.fontDataKey);
  if (!mData) {
    WriteElement(aStream, 0);
  } else {
    WriteElement(aStream, mFontDetails.size);
    aStream.write((const char*)mData, mFontDetails.size);
  }
}

inline void RecordedFontData::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "Font Data of size " << mFontDetails.size;
}

inline void RecordedFontData::SetFontData(const uint8_t* aData, uint32_t aSize,
                                          uint32_t aIndex) {
  mData = new (fallible) uint8_t[aSize];
  if (!mData) {
    gfxCriticalNote
        << "RecordedFontData failed to allocate data for recording of size "
        << aSize;
  } else {
    memcpy(mData, aData, aSize);
  }
  mFontDetails.fontDataKey = SFNTData::GetUniqueKey(aData, aSize, 0, nullptr);
  mFontDetails.size = aSize;
  mFontDetails.index = aIndex;
}

inline bool RecordedFontData::GetFontDetails(RecordedFontDetails& fontDetails) {
  if (!mGetFontFileDataSucceeded) {
    return false;
  }

  fontDetails.fontDataKey = mFontDetails.fontDataKey;
  fontDetails.size = mFontDetails.size;
  fontDetails.index = mFontDetails.index;
  return true;
}

template <class S>
RecordedFontData::RecordedFontData(S& aStream)
    : RecordedEventDerived(FONTDATA), mType(FontType::UNKNOWN) {
  ReadElementConstrained(aStream, mType, FontType::DWRITE, FontType::UNKNOWN);
  ReadElement(aStream, mFontDetails.fontDataKey);
  ReadElement(aStream, mFontDetails.size);
  if (!mFontDetails.size || !aStream.good()) {
    return;
  }

  mData = new (fallible) uint8_t[mFontDetails.size];
  if (!mData) {
    gfxCriticalNote
        << "RecordedFontData failed to allocate data for playback of size "
        << mFontDetails.size;
    aStream.SetIsBad();
  } else {
    aStream.read((char*)mData, mFontDetails.size);
  }
}

inline RecordedFontDescriptor::~RecordedFontDescriptor() = default;

inline bool RecordedFontDescriptor::PlayEvent(Translator* aTranslator) const {
  RefPtr<UnscaledFont> font = Factory::CreateUnscaledFontFromFontDescriptor(
      mType, mData.data(), mData.size(), mIndex);
  if (!font) {
    gfxDevCrash(LogReason::InvalidFont)
        << "Failed creating UnscaledFont of type " << int(mType)
        << " from font descriptor";
    return false;
  }

  aTranslator->AddUnscaledFont(mRefPtr, font);
  return true;
}

template <class S>
void RecordedFontDescriptor::Record(S& aStream) const {
  MOZ_ASSERT(mHasDesc);
  WriteElement(aStream, mType);
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mIndex);
  WriteElement(aStream, (size_t)mData.size());
  if (mData.size()) {
    aStream.write((char*)mData.data(), mData.size());
  }
}

inline void RecordedFontDescriptor::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] Font Descriptor";
}

inline void RecordedFontDescriptor::SetFontDescriptor(const uint8_t* aData,
                                                      uint32_t aSize,
                                                      uint32_t aIndex) {
  mData.assign(aData, aData + aSize);
  mIndex = aIndex;
}

template <class S>
RecordedFontDescriptor::RecordedFontDescriptor(S& aStream)
    : RecordedEventDerived(FONTDESC) {
  ReadElementConstrained(aStream, mType, FontType::DWRITE, FontType::UNKNOWN);
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mIndex);

  size_t size;
  ReadElement(aStream, size);
  if (!aStream.good()) {
    return;
  }
  if (size) {
    mData.resize(size);
    aStream.read((char*)mData.data(), size);
  }
}

inline bool RecordedUnscaledFontCreation::PlayEvent(
    Translator* aTranslator) const {
  NativeFontResource* fontResource =
      aTranslator->LookupNativeFontResource(mFontDataKey);
  if (!fontResource) {
    gfxDevCrash(LogReason::NativeFontResourceNotFound)
        << "NativeFontResource lookup failed for key |" << hexa(mFontDataKey)
        << "|.";
    return false;
  }

  RefPtr<UnscaledFont> unscaledFont = fontResource->CreateUnscaledFont(
      mIndex, mInstanceData.data(), mInstanceData.size());
  aTranslator->AddUnscaledFont(mRefPtr, unscaledFont);
  return true;
}

template <class S>
void RecordedUnscaledFontCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mFontDataKey);
  WriteElement(aStream, mIndex);
  WriteElement(aStream, (size_t)mInstanceData.size());
  if (mInstanceData.size()) {
    aStream.write((char*)mInstanceData.data(), mInstanceData.size());
  }
}

inline void RecordedUnscaledFontCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] UnscaledFont Created";
}

inline void RecordedUnscaledFontCreation::SetFontInstanceData(
    const uint8_t* aData, uint32_t aSize) {
  if (aSize) {
    mInstanceData.assign(aData, aData + aSize);
  }
}

template <class S>
RecordedUnscaledFontCreation::RecordedUnscaledFontCreation(S& aStream)
    : RecordedEventDerived(UNSCALEDFONTCREATION) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mFontDataKey);
  ReadElement(aStream, mIndex);

  size_t size;
  ReadElement(aStream, size);
  if (!aStream.good()) {
    return;
  }
  if (size) {
    mInstanceData.resize(size);
    aStream.read((char*)mInstanceData.data(), size);
  }
}

inline bool RecordedUnscaledFontDestruction::PlayEvent(
    Translator* aTranslator) const {
  aTranslator->RemoveUnscaledFont(mRefPtr);
  return true;
}

template <class S>
void RecordedUnscaledFontDestruction::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedUnscaledFontDestruction::RecordedUnscaledFontDestruction(S& aStream)
    : RecordedEventDerived(UNSCALEDFONTDESTRUCTION) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedUnscaledFontDestruction::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] UnscaledFont Destroyed";
}

inline bool RecordedScaledFontCreation::PlayEvent(
    Translator* aTranslator) const {
  UnscaledFont* unscaledFont = aTranslator->LookupUnscaledFont(mUnscaledFont);
  if (!unscaledFont) {
    gfxDevCrash(LogReason::UnscaledFontNotFound)
        << "UnscaledFont lookup failed for key |" << hexa(mUnscaledFont)
        << "|.";
    return false;
  }

  RefPtr<ScaledFont> scaledFont = unscaledFont->CreateScaledFont(
      mGlyphSize, mInstanceData.data(), mInstanceData.size(),
      mVariations.data(), mVariations.size());

  aTranslator->AddScaledFont(mRefPtr, scaledFont);
  return true;
}

template <class S>
void RecordedScaledFontCreation::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
  WriteElement(aStream, mUnscaledFont);
  WriteElement(aStream, mGlyphSize);
  WriteElement(aStream, (size_t)mInstanceData.size());
  if (mInstanceData.size()) {
    aStream.write((char*)mInstanceData.data(), mInstanceData.size());
  }
  WriteElement(aStream, (size_t)mVariations.size());
  if (mVariations.size()) {
    aStream.write((char*)mVariations.data(),
                  sizeof(FontVariation) * mVariations.size());
  }
}

inline void RecordedScaledFontCreation::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] ScaledFont Created";
}

inline void RecordedScaledFontCreation::SetFontInstanceData(
    const uint8_t* aData, uint32_t aSize, const FontVariation* aVariations,
    uint32_t aNumVariations) {
  if (aSize) {
    mInstanceData.assign(aData, aData + aSize);
  }
  if (aNumVariations) {
    mVariations.assign(aVariations, aVariations + aNumVariations);
  }
}

template <class S>
RecordedScaledFontCreation::RecordedScaledFontCreation(S& aStream)
    : RecordedEventDerived(SCALEDFONTCREATION) {
  ReadElement(aStream, mRefPtr);
  ReadElement(aStream, mUnscaledFont);
  ReadElement(aStream, mGlyphSize);

  size_t size;
  ReadElement(aStream, size);
  if (!aStream.good()) {
    return;
  }
  if (size) {
    mInstanceData.resize(size);
    aStream.read((char*)mInstanceData.data(), size);
  }

  size_t numVariations;
  ReadElement(aStream, numVariations);
  if (!aStream.good()) {
    return;
  }
  if (numVariations) {
    mVariations.resize(numVariations);
    aStream.read((char*)mVariations.data(),
                 sizeof(FontVariation) * numVariations);
  }
}

inline bool RecordedScaledFontDestruction::PlayEvent(
    Translator* aTranslator) const {
  aTranslator->RemoveScaledFont(mRefPtr);
  return true;
}

template <class S>
void RecordedScaledFontDestruction::Record(S& aStream) const {
  WriteElement(aStream, mRefPtr);
}

template <class S>
RecordedScaledFontDestruction::RecordedScaledFontDestruction(S& aStream)
    : RecordedEventDerived(SCALEDFONTDESTRUCTION) {
  ReadElement(aStream, mRefPtr);
}

inline void RecordedScaledFontDestruction::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mRefPtr << "] ScaledFont Destroyed";
}

inline bool RecordedMaskSurface::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }

  SourceSurface* surface = aTranslator->LookupSourceSurface(mRefMask);
  if (!surface) {
    return false;
  }

  dt->MaskSurface(*GenericPattern(mPattern, aTranslator), surface, mOffset,
                  mOptions);
  return true;
}

template <class S>
void RecordedMaskSurface::Record(S& aStream) const {
  RecordPatternData(aStream, mPattern);
  WriteElement(aStream, mRefMask);
  WriteElement(aStream, mOffset);
  WriteElement(aStream, mOptions);
}

template <class S>
RecordedMaskSurface::RecordedMaskSurface(S& aStream)
    : RecordedEventDerived(MASKSURFACE) {
  ReadPatternData(aStream, mPattern);
  ReadElement(aStream, mRefMask);
  ReadElement(aStream, mOffset);
  ReadDrawOptions(aStream, mOptions);
}

inline void RecordedMaskSurface::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "MaskSurface (" << mRefMask << ")  Offset: (" << mOffset.x
                << "x" << mOffset.y << ") Pattern: ";
  OutputSimplePatternInfo(mPattern, aStringStream);
}

template <typename T>
void ReplaySetAttribute(FilterNode* aNode, uint32_t aIndex, T aValue) {
  aNode->SetAttribute(aIndex, aValue);
}

inline bool RecordedFilterNodeSetAttribute::PlayEvent(
    Translator* aTranslator) const {
  FilterNode* node = aTranslator->LookupFilterNode(mNode);
  if (!node) {
    return false;
  }

#define REPLAY_SET_ATTRIBUTE(type, argtype)                      \
  case ARGTYPE_##argtype:                                        \
    ReplaySetAttribute(node, mIndex, *(type*)&mPayload.front()); \
    break

  switch (mArgType) {
    REPLAY_SET_ATTRIBUTE(boolBOOL);
    REPLAY_SET_ATTRIBUTE(uint32_t, UINT32);
    REPLAY_SET_ATTRIBUTE(FloatFLOAT);
    REPLAY_SET_ATTRIBUTE(Size, SIZE);
    REPLAY_SET_ATTRIBUTE(IntSize, INTSIZE);
    REPLAY_SET_ATTRIBUTE(IntPoint, INTPOINT);
    REPLAY_SET_ATTRIBUTE(Rect, RECT);
    REPLAY_SET_ATTRIBUTE(IntRect, INTRECT);
    REPLAY_SET_ATTRIBUTE(Point, POINT);
    REPLAY_SET_ATTRIBUTE(Matrix, MATRIX);
    REPLAY_SET_ATTRIBUTE(Matrix5x4, MATRIX5X4);
    REPLAY_SET_ATTRIBUTE(Point3D, POINT3D);
    REPLAY_SET_ATTRIBUTE(DeviceColor, COLOR);
    case ARGTYPE_FLOAT_ARRAY:
      node->SetAttribute(mIndex,
                         reinterpret_cast<const Float*>(&mPayload.front()),
                         mPayload.size() / sizeof(Float));
      break;
  }

  return true;
}

template <class S>
void RecordedFilterNodeSetAttribute::Record(S& aStream) const {
  WriteElement(aStream, mNode);
  WriteElement(aStream, mIndex);
  WriteElement(aStream, mArgType);
  WriteElement(aStream, uint64_t(mPayload.size()));
  aStream.write((const char*)&mPayload.front(), mPayload.size());
}

template <class S>
RecordedFilterNodeSetAttribute::RecordedFilterNodeSetAttribute(S& aStream)
    : RecordedEventDerived(FILTERNODESETATTRIBUTE) {
  ReadElement(aStream, mNode);
  ReadElement(aStream, mIndex);
  ReadElementConstrained(aStream, mArgType, ArgType::ARGTYPE_UINT32,
                         ArgType::ARGTYPE_FLOAT_ARRAY);
  uint64_t size;
  ReadElement(aStream, size);
  if (!aStream.good()) {
    return;
  }

  mPayload.resize(size_t(size));
  aStream.read((char*)&mPayload.front(), size);
}

inline void RecordedFilterNodeSetAttribute::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ")";
}

inline bool RecordedFilterNodeSetInput::PlayEvent(
    Translator* aTranslator) const {
  FilterNode* node = aTranslator->LookupFilterNode(mNode);
  if (!node) {
    return false;
  }

  if (mInputFilter) {
    node->SetInput(mIndex, aTranslator->LookupFilterNode(mInputFilter));
  } else {
    node->SetInput(mIndex, aTranslator->LookupSourceSurface(mInputSurface));
  }

  return true;
}

template <class S>
void RecordedFilterNodeSetInput::Record(S& aStream) const {
  WriteElement(aStream, mNode);
  WriteElement(aStream, mIndex);
  WriteElement(aStream, mInputFilter);
  WriteElement(aStream, mInputSurface);
}

template <class S>
RecordedFilterNodeSetInput::RecordedFilterNodeSetInput(S& aStream)
    : RecordedEventDerived(FILTERNODESETINPUT) {
  ReadElement(aStream, mNode);
  ReadElement(aStream, mIndex);
  ReadElement(aStream, mInputFilter);
  ReadElement(aStream, mInputSurface);
}

inline void RecordedFilterNodeSetInput::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ", ";

  if (mInputFilter) {
    aStringStream << "Filter: " << mInputFilter;
  } else {
    aStringStream << "Surface: " << mInputSurface;
  }

  aStringStream << ")";
}

inline bool RecordedLink::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }
  dt->Link(mLocalDest.c_str(), mURI.c_str(), mRect);
  return true;
}

template <class S>
void RecordedLink::Record(S& aStream) const {
  WriteElement(aStream, mRect);
  uint32_t len = mLocalDest.length();
  WriteElement(aStream, len);
  if (len) {
    aStream.write(mLocalDest.data(), len);
  }
  len = mURI.length();
  WriteElement(aStream, len);
  if (len) {
    aStream.write(mURI.data(), len);
  }
}

template <class S>
RecordedLink::RecordedLink(S& aStream) : RecordedEventDerived(LINK) {
  ReadElement(aStream, mRect);
  uint32_t len;
  ReadElement(aStream, len);
  mLocalDest.resize(size_t(len));
  if (len && aStream.good()) {
    aStream.read(&mLocalDest.front(), len);
  }
  ReadElement(aStream, len);
  mURI.resize(size_t(len));
  if (len && aStream.good()) {
    aStream.read(&mURI.front(), len);
  }
}

inline void RecordedLink::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  if (mLocalDest.empty()) {
    aStringStream << "Link [" << mURI << " @ " << mRect << "]";
  } else {
    aStringStream << "Link [" << mLocalDest << " / " << mURI << " @ " << mRect
                  << "]";
  }
}

inline bool RecordedDestination::PlayEvent(Translator* aTranslator) const {
  DrawTarget* dt = aTranslator->GetCurrentDrawTarget();
  if (!dt) {
    return false;
  }
  dt->Destination(mDestination.c_str(), mPoint);
  return true;
}

template <class S>
void RecordedDestination::Record(S& aStream) const {
  WriteElement(aStream, mPoint);
  uint32_t len = mDestination.length();
  WriteElement(aStream, len);
  if (len) {
    aStream.write(mDestination.data(), len);
  }
}

template <class S>
RecordedDestination::RecordedDestination(S& aStream)
    : RecordedEventDerived(DESTINATION) {
  ReadElement(aStream, mPoint);
  uint32_t len;
  ReadElement(aStream, len);
  mDestination.resize(size_t(len));
  if (len && aStream.good()) {
    aStream.read(&mDestination.front(), len);
  }
}

inline void RecordedDestination::OutputSimpleEventInfo(
    std::stringstream& aStringStream) const {
  aStringStream << "Destination [" << mDestination << " @ " << mPoint << "]";
}

#define FOR_EACH_EVENT(f)                                          \
  f(DRAWTARGETCREATION, RecordedDrawTargetCreation);               \
  f(DRAWTARGETDESTRUCTION, RecordedDrawTargetDestruction);         \
  f(SETCURRENTDRAWTARGET, RecordedSetCurrentDrawTarget);           \
  f(FILLRECT, RecordedFillRect);                                   \
  f(STROKERECT, RecordedStrokeRect);                               \
  f(STROKELINE, RecordedStrokeLine);                               \
  f(STROKECIRCLE, RecordedStrokeCircle);                           \
  f(CLEARRECT, RecordedClearRect);                                 \
  f(COPYSURFACE, RecordedCopySurface);                             \
  f(SETPERMITSUBPIXELAA, RecordedSetPermitSubpixelAA);             \
  f(SETTRANSFORM, RecordedSetTransform);                           \
  f(PUSHCLIPRECT, RecordedPushClipRect);                           \
  f(PUSHCLIP, RecordedPushClip);                                   \
  f(POPCLIP, RecordedPopClip);                                     \
  f(REMOVEALLCLIPS, RecordedRemoveAllClips);                       \
  f(FILL, RecordedFill);                                           \
  f(FILLCIRCLE, RecordedFillCircle);                               \
  f(FILLGLYPHS, RecordedFillGlyphs);                               \
  f(STROKEGLYPHS, RecordedStrokeGlyphs);                           \
  f(MASK, RecordedMask);                                           \
  f(STROKE, RecordedStroke);                                       \
  f(DRAWSURFACE, RecordedDrawSurface);                             \
  f(DRAWSURFACEDESCRIPTOR, RecordedDrawSurfaceDescriptor);         \
  f(DRAWDEPENDENTSURFACE, RecordedDrawDependentSurface);           \
  f(DRAWSURFACEWITHSHADOW, RecordedDrawSurfaceWithShadow);         \
  f(DRAWSHADOW, RecordedDrawShadow);                               \
  f(DRAWFILTER, RecordedDrawFilter);                               \
  f(PATHCREATION, RecordedPathCreation);                           \
  f(PATHDESTRUCTION, RecordedPathDestruction);                     \
  f(SOURCESURFACECREATION, RecordedSourceSurfaceCreation);         \
  f(SOURCESURFACEDESTRUCTION, RecordedSourceSurfaceDestruction);   \
  f(FILTERNODECREATION, RecordedFilterNodeCreation);               \
  f(FILTERNODEDESTRUCTION, RecordedFilterNodeDestruction);         \
  f(GRADIENTSTOPSCREATION, RecordedGradientStopsCreation);         \
  f(GRADIENTSTOPSDESTRUCTION, RecordedGradientStopsDestruction);   \
  f(SNAPSHOT, RecordedSnapshot);                                   \
  f(SCALEDFONTCREATION, RecordedScaledFontCreation);               \
  f(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction);         \
  f(MASKSURFACE, RecordedMaskSurface);                             \
  f(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute);       \
  f(FILTERNODESETINPUT, RecordedFilterNodeSetInput);               \
  f(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget);     \
  f(CREATECLIPPEDDRAWTARGET, RecordedCreateClippedDrawTarget);     \
  f(CREATEDRAWTARGETFORFILTER, RecordedCreateDrawTargetForFilter); \
  f(FONTDATA, RecordedFontData);                                   \
  f(FONTDESC, RecordedFontDescriptor);                             \
  f(PUSHLAYER, RecordedPushLayer);                                 \
  f(PUSHLAYERWITHBLEND, RecordedPushLayerWithBlend);               \
  f(POPLAYER, RecordedPopLayer);                                   \
  f(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation);           \
  f(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction);     \
  f(INTOLUMINANCE, RecordedIntoLuminanceSource);                   \
  f(EXTRACTSUBRECT, RecordedExtractSubrect);                       \
  f(EXTERNALSURFACECREATION, RecordedExternalSurfaceCreation);     \
  f(FLUSH, RecordedFlush);                                         \
  f(DETACHALLSNAPSHOTS, RecordedDetachAllSnapshots);               \
  f(OPTIMIZESOURCESURFACE, RecordedOptimizeSourceSurface);         \
  f(LINK, RecordedLink);                                           \
  f(DESTINATION, RecordedDestination);

#define DO_WITH_EVENT_TYPE(_typeenum, _class) \
  case _typeenum: {                           \
    auto e = _class(aStream);                 \
    return aAction(&e);                       \
  }

template <class S>
bool RecordedEvent::DoWithEvent(
    S& aStream, EventType aType,
    const std::function<bool(RecordedEvent*)>& aAction) {
  switch (aType) {
    FOR_EACH_EVENT(DO_WITH_EVENT_TYPE)
    default:
      return false;
  }
}

}  // namespace gfx
}  // namespace mozilla

#endif

Messung V0.5 in Prozent
C=93 H=93 G=92

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.84Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-26) ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.