gfx/2d/DrawCommands.h
author Edouard Oger <eoger@fastmail.com>
Thu, 22 Feb 2018 16:30:39 +0800
changeset 459331 157f93b585b18e810942d3fc421b8dc9327b4419
parent 455919 48a7b3be6436ff4451125ed0099aec39f71a6671
child 460452 d12219f7d74b2ec74df6b9df88fab3e700ca51c3
permissions -rw-r--r--
Bug 1439777 p2 - Remove weave:ui:* related code. r=markh,tcsc MozReview-Commit-ID: D1H36YeiJCS

/* -*- 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_DRAWCOMMANDS_H_
#define MOZILLA_GFX_DRAWCOMMANDS_H_

#include <math.h>

#include "2D.h"
#include "Blur.h"
#include "Filters.h"
#include <vector>
#include "CaptureCommandList.h"
#include "DrawCommand.h"
#include "FilterNodeCapture.h"
#include "Logging.h"

namespace mozilla {
namespace gfx {

#define CLONE_INTO(Type) new (aList->Append<Type>()) Type

class StrokeOptionsCommand : public DrawingCommand
{
public:
  StrokeOptionsCommand(CommandType aType,
                       const StrokeOptions& aStrokeOptions)
    : DrawingCommand(aType)
    , mStrokeOptions(aStrokeOptions)
  {
    // Stroke Options dashes are owned by the caller.
    // Have to copy them here so they don't get freed
    // between now and replay.
    if (aStrokeOptions.mDashLength) {
      mDashes.resize(aStrokeOptions.mDashLength);
      mStrokeOptions.mDashPattern = &mDashes.front();
      PodCopy(&mDashes.front(), aStrokeOptions.mDashPattern, mStrokeOptions.mDashLength);
    }
  }

  virtual ~StrokeOptionsCommand() {}

protected:
  StrokeOptions mStrokeOptions;
  std::vector<Float> mDashes;
};

class StoredPattern
{
public:
  explicit StoredPattern(const Pattern& aPattern)
  {
    Assign(aPattern);
  }

  void Assign(const Pattern& aPattern)
  {
    switch (aPattern.GetType()) {
    case PatternType::COLOR:
      new (mColor)ColorPattern(*static_cast<const ColorPattern*>(&aPattern));
      return;
    case PatternType::SURFACE:
    {
      SurfacePattern* surfPat = new (mSurface)SurfacePattern(*static_cast<const SurfacePattern*>(&aPattern));
      surfPat->mSurface->GuaranteePersistance();
      return;
    }
    case PatternType::LINEAR_GRADIENT:
      new (mLinear)LinearGradientPattern(*static_cast<const LinearGradientPattern*>(&aPattern));
      return;
    case PatternType::RADIAL_GRADIENT:
      new (mRadial)RadialGradientPattern(*static_cast<const RadialGradientPattern*>(&aPattern));
      return;
    }
  }

  ~StoredPattern()
  {
    reinterpret_cast<Pattern*>(mPattern)->~Pattern();
  }

  Pattern* Get()
  {
    return reinterpret_cast<Pattern*>(mPattern);
  }

  const Pattern* Get() const
  {
    return reinterpret_cast<const Pattern*>(mPattern);
  }

  operator Pattern&()
  {
    return *reinterpret_cast<Pattern*>(mPattern);
  }

  operator const Pattern&() const
  {
    return *reinterpret_cast<const Pattern*>(mPattern);
  }

  StoredPattern(const StoredPattern& aPattern)
  {
    Assign(aPattern);
  }

private:
  StoredPattern operator=(const StoredPattern& aOther)
  {
    // Block this so that we notice if someone's doing excessive assigning.
    return *this;
  }

  union {
    char mPattern[sizeof(Pattern)];
    char mColor[sizeof(ColorPattern)];
    char mLinear[sizeof(LinearGradientPattern)];
    char mRadial[sizeof(RadialGradientPattern)];
    char mSurface[sizeof(SurfacePattern)];
  };
};

class DrawSurfaceCommand : public DrawingCommand
{
public:
  DrawSurfaceCommand(SourceSurface *aSurface, const Rect& aDest,
                     const Rect& aSource, const DrawSurfaceOptions& aSurfOptions,
                     const DrawOptions& aOptions)
    : DrawingCommand(DrawSurfaceCommand::Type)
    , mSurface(aSurface), mDest(aDest)
    , mSource(aSource), mSurfOptions(aSurfOptions)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(DrawSurfaceCommand)(mSurface, mDest, mSource, mSurfOptions, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->DrawSurface(mSurface, mDest, mSource, mSurfOptions, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[DrawSurface surf=" << mSurface;
    aStream << " dest=" << mDest;
    aStream << " src=" << mSource;
    aStream << " surfOpt=" << mSurfOptions;
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::DRAWSURFACE;

private:
  RefPtr<SourceSurface> mSurface;
  Rect mDest;
  Rect mSource;
  DrawSurfaceOptions mSurfOptions;
  DrawOptions mOptions;
};

class DrawSurfaceWithShadowCommand : public DrawingCommand
{
public:
  DrawSurfaceWithShadowCommand(SourceSurface *aSurface,
                               const Point &aDest,
                               const Color &aColor,
                               const Point &aOffset,
                               Float aSigma,
                               CompositionOp aOperator)
    : DrawingCommand(DrawSurfaceWithShadowCommand::Type),
      mSurface(aSurface),
      mDest(aDest),
      mColor(aColor),
      mOffset(aOffset),
      mSigma(aSigma),
      mOperator(aOperator)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(DrawSurfaceWithShadowCommand)(mSurface, mDest, mColor, mOffset, mSigma, mOperator);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->DrawSurfaceWithShadow(mSurface, mDest, mColor, mOffset, mSigma, mOperator);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[DrawSurfaceWithShadow surf=" << mSurface;
    aStream << " dest=" << mDest;
    aStream << " color=" << mColor;
    aStream << " offset=" << mOffset;
    aStream << " sigma=" << mSigma;
    aStream << " op=" << mOperator;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::DRAWSURFACEWITHSHADOW;

private:
  RefPtr<SourceSurface> mSurface;
  Point mDest;
  Color mColor;
  Point mOffset;
  Float mSigma;
  CompositionOp mOperator;
};

class DrawFilterCommand : public DrawingCommand
{
public:
  DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect,
                    const Point& aDestPoint, const DrawOptions& aOptions)
    : DrawingCommand(DrawFilterCommand::Type)
    , mFilter(aFilter), mSourceRect(aSourceRect)
    , mDestPoint(aDestPoint), mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(DrawFilterCommand)(mFilter, mSourceRect, mDestPoint, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    RefPtr<FilterNode> filter = mFilter;
    if (mFilter->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
      filter = static_cast<FilterNodeCapture*>(filter.get())->Validate(aDT);
    }
    aDT->DrawFilter(filter, mSourceRect, mDestPoint, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[DrawFilter surf=" << mFilter;
    aStream << " src=" << mSourceRect;
    aStream << " dest=" << mDestPoint;
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::DRAWFILTER;

private:
  RefPtr<FilterNode> mFilter;
  Rect mSourceRect;
  Point mDestPoint;
  DrawOptions mOptions;
};

class ClearRectCommand : public DrawingCommand
{
public:
  explicit ClearRectCommand(const Rect& aRect)
    : DrawingCommand(ClearRectCommand::Type)
    , mRect(aRect)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(ClearRectCommand)(mRect);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->ClearRect(mRect);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[ClearRect rect=" << mRect << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::CLEARRECT;

private:
  Rect mRect;
};

class CopySurfaceCommand : public DrawingCommand
{
public:
  CopySurfaceCommand(SourceSurface* aSurface,
                     const IntRect& aSourceRect,
                     const IntPoint& aDestination)
    : DrawingCommand(CopySurfaceCommand::Type)
    , mSurface(aSurface)
    , mSourceRect(aSourceRect)
    , mDestination(aDestination)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(CopySurfaceCommand)(mSurface, mSourceRect, mDestination);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform) const override
  {
    MOZ_ASSERT(!aTransform || !aTransform->HasNonIntegerTranslation());
    Point dest(Float(mDestination.x), Float(mDestination.y));
    if (aTransform) {
      dest = aTransform->TransformPoint(dest);
    }
    aDT->CopySurface(mSurface, mSourceRect, IntPoint(uint32_t(dest.x), uint32_t(dest.y)));
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[CopySurface surf=" << mSurface;
    aStream << " src=" << mSourceRect;
    aStream << " dest=" << mDestination;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::COPYSURFACE;

private:
  RefPtr<SourceSurface> mSurface;
  IntRect mSourceRect;
  IntPoint mDestination;
};

class FillRectCommand : public DrawingCommand
{
public:
  FillRectCommand(const Rect& aRect,
                  const Pattern& aPattern,
                  const DrawOptions& aOptions)
    : DrawingCommand(FillRectCommand::Type)
    , mRect(aRect)
    , mPattern(aPattern)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(FillRectCommand)(mRect, mPattern, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->FillRect(mRect, mPattern, mOptions);
  }

  bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const override
  {
    aDeviceRect = aTransform.TransformBounds(mRect);
    return true;
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[FillRect rect=" << mRect;
    aStream << " pattern=" << mPattern.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::FILLRECT;

private:
  Rect mRect;
  StoredPattern mPattern;
  DrawOptions mOptions;
};

class StrokeRectCommand : public StrokeOptionsCommand
{
public:
  StrokeRectCommand(const Rect& aRect,
                    const Pattern& aPattern,
                    const StrokeOptions& aStrokeOptions,
                    const DrawOptions& aOptions)
    : StrokeOptionsCommand(StrokeRectCommand::Type, aStrokeOptions)
    , mRect(aRect)
    , mPattern(aPattern)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(StrokeRectCommand)(mRect, mPattern, mStrokeOptions, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->StrokeRect(mRect, mPattern, mStrokeOptions, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[StrokeRect rect=" << mRect;
    aStream << " pattern=" << mPattern.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::STROKERECT;

private:
  Rect mRect;
  StoredPattern mPattern;
  DrawOptions mOptions;
};

class StrokeLineCommand : public StrokeOptionsCommand
{
public:
  StrokeLineCommand(const Point& aStart,
                    const Point& aEnd,
                    const Pattern& aPattern,
                    const StrokeOptions& aStrokeOptions,
                    const DrawOptions& aOptions)
    : StrokeOptionsCommand(StrokeLineCommand::Type, aStrokeOptions)
    , mStart(aStart)
    , mEnd(aEnd)
    , mPattern(aPattern)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(StrokeLineCommand)(mStart, mEnd, mPattern, mStrokeOptions, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->StrokeLine(mStart, mEnd, mPattern, mStrokeOptions, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[StrokeLine start=" << mStart;
    aStream << " end=" << mEnd;
    aStream << " pattern=" << mPattern.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::STROKELINE;

private:
  Point mStart;
  Point mEnd;
  StoredPattern mPattern;
  DrawOptions mOptions;
};

class FillCommand : public DrawingCommand
{
public:
  FillCommand(const Path* aPath,
              const Pattern& aPattern,
              const DrawOptions& aOptions)
    : DrawingCommand(FillCommand::Type)
    , mPath(const_cast<Path*>(aPath))
    , mPattern(aPattern)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(FillCommand)(mPath, mPattern, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->Fill(mPath, mPattern, mOptions);
  }

  bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const override
  {
    aDeviceRect = mPath->GetBounds(aTransform);
    return true;
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[FillCommand path=" << mPath;
    aStream << " pattern=" << mPattern.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::FILL;

private:
  RefPtr<Path> mPath;
  StoredPattern mPattern;
  DrawOptions mOptions;
};

#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif

#ifndef M_SQRT1_2
#define M_SQRT1_2 0.707106781186547524400844362104849039
#endif

// The logic for this comes from _cairo_stroke_style_max_distance_from_path
static Rect
PathExtentsToMaxStrokeExtents(const StrokeOptions &aStrokeOptions,
                              const Rect &aRect,
                              const Matrix &aTransform)
{
  double styleExpansionFactor = 0.5f;

  if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
    styleExpansionFactor = M_SQRT1_2;
  }

  if (aStrokeOptions.mLineJoin == JoinStyle::MITER &&
      styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) {
    styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit;
  }

  styleExpansionFactor *= aStrokeOptions.mLineWidth;

  double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
  double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);

  // Even if the stroke only partially covers a pixel, it must still render to
  // full pixels. Round up to compensate for this.
  dx = ceil(dx);
  dy = ceil(dy);

  Rect result = aRect;
  result.Inflate(dx, dy);
  return result;
}


class StrokeCommand : public StrokeOptionsCommand
{
public:
  StrokeCommand(const Path* aPath,
                const Pattern& aPattern,
                const StrokeOptions& aStrokeOptions,
                const DrawOptions& aOptions)
    : StrokeOptionsCommand(StrokeCommand::Type, aStrokeOptions)
    , mPath(const_cast<Path*>(aPath))
    , mPattern(aPattern)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(StrokeCommand)(mPath, mPattern, mStrokeOptions, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->Stroke(mPath, mPattern, mStrokeOptions, mOptions);
  }

  bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const override
  {
    aDeviceRect = PathExtentsToMaxStrokeExtents(mStrokeOptions, mPath->GetBounds(aTransform), aTransform);
    return true;
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[Stroke path=" << mPath;
    aStream << " pattern=" << mPattern.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::STROKE;

private:
  RefPtr<Path> mPath;
  StoredPattern mPattern;
  DrawOptions mOptions;
};

class FillGlyphsCommand : public DrawingCommand
{
  friend class DrawTargetCaptureImpl;
public:
  FillGlyphsCommand(ScaledFont* aFont,
                    const GlyphBuffer& aBuffer,
                    const Pattern& aPattern,
                    const DrawOptions& aOptions)
    : DrawingCommand(FillGlyphsCommand::Type)
    , mFont(aFont)
    , mPattern(aPattern)
    , mOptions(aOptions)
  {
    mGlyphs.resize(aBuffer.mNumGlyphs);
    memcpy(&mGlyphs.front(), aBuffer.mGlyphs, sizeof(Glyph) * aBuffer.mNumGlyphs);
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    GlyphBuffer glyphs = {
      mGlyphs.data(),
      (uint32_t)mGlyphs.size(),
    };
    CLONE_INTO(FillGlyphsCommand)(mFont, glyphs, mPattern, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    GlyphBuffer buf;
    buf.mNumGlyphs = mGlyphs.size();
    buf.mGlyphs = &mGlyphs.front();
    aDT->FillGlyphs(mFont, buf, mPattern, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[FillGlyphs font=" << mFont;
    aStream << " glyphCount=" << mGlyphs.size();
    aStream << " pattern=" << mPattern.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::FILLGLYPHS;

private:
  RefPtr<ScaledFont> mFont;
  std::vector<Glyph> mGlyphs;
  StoredPattern mPattern;
  DrawOptions mOptions;
};

class StrokeGlyphsCommand : public StrokeOptionsCommand
{
  friend class DrawTargetCaptureImpl;
public:
  StrokeGlyphsCommand(ScaledFont* aFont,
                      const GlyphBuffer& aBuffer,
                      const Pattern& aPattern,
                      const StrokeOptions& aStrokeOptions,
                      const DrawOptions& aOptions)
    : StrokeOptionsCommand(StrokeGlyphsCommand::Type, aStrokeOptions)
    , mFont(aFont)
    , mPattern(aPattern)
    , mOptions(aOptions)
  {
    mGlyphs.resize(aBuffer.mNumGlyphs);
    memcpy(&mGlyphs.front(), aBuffer.mGlyphs, sizeof(Glyph) * aBuffer.mNumGlyphs);
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    GlyphBuffer glyphs = {
      mGlyphs.data(),
      (uint32_t)mGlyphs.size(),
    };
    CLONE_INTO(StrokeGlyphsCommand)(mFont, glyphs, mPattern, mStrokeOptions, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    GlyphBuffer buf;
    buf.mNumGlyphs = mGlyphs.size();
    buf.mGlyphs = &mGlyphs.front();
    aDT->StrokeGlyphs(mFont, buf, mPattern, mStrokeOptions, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[StrokeGlyphs font=" << mFont;
    aStream << " glyphCount=" << mGlyphs.size();
    aStream << " pattern=" << mPattern.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::STROKEGLYPHS;

private:
  RefPtr<ScaledFont> mFont;
  std::vector<Glyph> mGlyphs;
  StoredPattern mPattern;
  DrawOptions mOptions;
};

class MaskCommand : public DrawingCommand
{
public:
  MaskCommand(const Pattern& aSource,
              const Pattern& aMask,
              const DrawOptions& aOptions)
    : DrawingCommand(MaskCommand::Type)
    , mSource(aSource)
    , mMask(aMask)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(MaskCommand)(mSource, mMask, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->Mask(mSource, mMask, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[Mask source=" << mSource.Get();
    aStream << " mask=" << mMask.Get();
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::MASK;

private:
  StoredPattern mSource;
  StoredPattern mMask;
  DrawOptions mOptions;
};

class MaskSurfaceCommand : public DrawingCommand
{
public:
  MaskSurfaceCommand(const Pattern& aSource,
                     const SourceSurface* aMask,
                     const Point& aOffset,
                     const DrawOptions& aOptions)
    : DrawingCommand(MaskSurfaceCommand::Type)
    , mSource(aSource)
    , mMask(const_cast<SourceSurface*>(aMask))
    , mOffset(aOffset)
    , mOptions(aOptions)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(MaskSurfaceCommand)(mSource, mMask, mOffset, mOptions);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->MaskSurface(mSource, mMask, mOffset, mOptions);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[Mask source=" << mSource.Get();
    aStream << " mask=" << mMask;
    aStream << " offset=" << &mOffset;
    aStream << " opt=" << mOptions;
    aStream << "]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::MASKSURFACE;

private:
  StoredPattern mSource;
  RefPtr<SourceSurface> mMask;
  Point mOffset;
  DrawOptions mOptions;
};

class PushClipCommand : public DrawingCommand
{
public:
  explicit PushClipCommand(const Path* aPath)
    : DrawingCommand(PushClipCommand::Type)
    , mPath(const_cast<Path*>(aPath))
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(PushClipCommand)(mPath);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->PushClip(mPath);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[PushClip path=" << mPath << "]";
  }

  static const bool AffectsSnapshot = false;
  static const CommandType Type = CommandType::PUSHCLIP;

private:
  RefPtr<Path> mPath;
};

class PushClipRectCommand : public DrawingCommand
{
public:
  explicit PushClipRectCommand(const Rect& aRect)
    : DrawingCommand(PushClipRectCommand::Type)
    , mRect(aRect)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(PushClipRectCommand)(mRect);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->PushClipRect(mRect);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[PushClipRect rect=" << mRect << "]";
  }

  static const bool AffectsSnapshot = false;
  static const CommandType Type = CommandType::PUSHCLIPRECT;

private:
  Rect mRect;
};

class PushLayerCommand : public DrawingCommand
{
public:
  PushLayerCommand(const bool aOpaque,
                   const Float aOpacity,
                   SourceSurface* aMask,
                   const Matrix& aMaskTransform,
                   const IntRect& aBounds,
                   bool aCopyBackground)
    : DrawingCommand(PushLayerCommand::Type)
    , mOpaque(aOpaque)
    , mOpacity(aOpacity)
    , mMask(aMask)
    , mMaskTransform(aMaskTransform)
    , mBounds(aBounds)
    , mCopyBackground(aCopyBackground)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(PushLayerCommand)(mOpaque, mOpacity, mMask, mMaskTransform, mBounds, mCopyBackground);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->PushLayer(mOpaque, mOpacity, mMask,
                   mMaskTransform, mBounds, mCopyBackground);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[PushLayer opaque=" << mOpaque;
    aStream << " opacity=" << mOpacity;
    aStream << " mask=" << mMask;
    aStream << " maskTransform=" << mMaskTransform;
    aStream << " bounds=" << mBounds;
    aStream << " copyBackground=" << mCopyBackground;
    aStream << "]";
  }

  static const bool AffectsSnapshot = false;
  static const CommandType Type = CommandType::PUSHLAYER;

private:
  bool mOpaque;
  float mOpacity;
  RefPtr<SourceSurface> mMask;
  Matrix mMaskTransform;
  IntRect mBounds;
  bool mCopyBackground;
};

class PopClipCommand : public DrawingCommand
{
public:
  PopClipCommand()
    : DrawingCommand(PopClipCommand::Type)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(PopClipCommand)();
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->PopClip();
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[PopClip]";
  }

  static const bool AffectsSnapshot = false;
  static const CommandType Type = CommandType::POPCLIP;
};

class PopLayerCommand : public DrawingCommand
{
public:
  PopLayerCommand()
    : DrawingCommand(PopLayerCommand::Type)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(PopLayerCommand)();
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->PopLayer();
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[PopLayer]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::POPLAYER;
};

class SetTransformCommand : public DrawingCommand
{
  friend class DrawTargetCaptureImpl;
public:
  explicit SetTransformCommand(const Matrix& aTransform)
    : DrawingCommand(SetTransformCommand::Type)
    , mTransform(aTransform)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(SetTransformCommand)(mTransform);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aMatrix) const override
  {
    if (aMatrix) {
      aDT->SetTransform(mTransform * (*aMatrix));
    } else {
      aDT->SetTransform(mTransform);
    }
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[SetTransform transform=" << mTransform << "]";
  }

  static const bool AffectsSnapshot = false;
  static const CommandType Type = CommandType::SETTRANSFORM;

private:
  Matrix mTransform;
};

class SetPermitSubpixelAACommand : public DrawingCommand
{
  friend class DrawTargetCaptureImpl;
public:
  explicit SetPermitSubpixelAACommand(bool aPermitSubpixelAA)
    : DrawingCommand(SetPermitSubpixelAACommand::Type)
    , mPermitSubpixelAA(aPermitSubpixelAA)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(SetPermitSubpixelAACommand)(mPermitSubpixelAA);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aMatrix) const override
  {
    aDT->SetPermitSubpixelAA(mPermitSubpixelAA);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[SetPermitSubpixelAA permitSubpixelAA=" << mPermitSubpixelAA << "]";
  }

  static const bool AffectsSnapshot = false;
  static const CommandType Type = CommandType::SETPERMITSUBPIXELAA;

private:
  bool mPermitSubpixelAA;
};

class FlushCommand : public DrawingCommand
{
public:
  explicit FlushCommand()
    : DrawingCommand(FlushCommand::Type)
  {
  }

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(FlushCommand)();
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->Flush();
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[Flush]";
  }

  static const bool AffectsSnapshot = false;
  static const CommandType Type = CommandType::FLUSH;
};

class BlurCommand : public DrawingCommand
{
public:
  explicit BlurCommand(const AlphaBoxBlur& aBlur)
   : DrawingCommand(BlurCommand::Type)
   , mBlur(aBlur)
  {}

  void CloneInto(CaptureCommandList* aList) override
  {
    CLONE_INTO(BlurCommand)(mBlur);
  }

  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
  {
    aDT->Blur(mBlur);
  }

  void Log(TreeLog& aStream) const override
  {
    aStream << "[Blur]";
  }

  static const bool AffectsSnapshot = true;
  static const CommandType Type = CommandType::BLUR;

private:
  AlphaBoxBlur mBlur;
};

#undef CLONE_INTO

} // namespace gfx
} // namespace mozilla

#endif /* MOZILLA_GFX_DRAWCOMMANDS_H_ */