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

#ifndef _MOZILLA_GFX_2D_H
#define _MOZILLA_GFX_2D_H

#include "Types.h"
#include "Point.h"
#include "Rect.h"
#include "Matrix.h"
#include "Quaternion.h"
#include "UserData.h"

// GenericRefCountedBase allows us to hold on to refcounted objects of any type
// (contrary to RefCounted<T> which requires knowing the type T) and, in particular,
// without having a dependency on that type. This is used for DrawTargetSkia
// to be able to hold on to a GLContext.
#include "mozilla/GenericRefCounted.h"

// This RefPtr class isn't ideal for usage in Azure, as it doesn't allow T**
// outparams using the &-operator. But it will have to do as there's no easy
// solution.
#include "mozilla/RefPtr.h"

#include "mozilla/DebugOnly.h"

#ifdef MOZ_ENABLE_FREETYPE
#include <string>
#endif

#include "gfxPrefs.h"

struct _cairo_surface;
typedef _cairo_surface cairo_surface_t;

struct _cairo_scaled_font;
typedef _cairo_scaled_font cairo_scaled_font_t;

struct _FcPattern;
typedef _FcPattern FcPattern;

struct ID3D11Texture2D;
struct ID3D11Device;
struct ID2D1Device;
struct IDWriteFactory;
struct IDWriteRenderingParams;
struct IDWriteFontFace;

class GrContext;
class SkCanvas;
struct gfxFontStyle;

struct CGContext;
typedef struct CGContext *CGContextRef;

namespace mozilla {

namespace gfx {

class SourceSurface;
class DataSourceSurface;
class DrawTarget;
class DrawEventRecorder;
class FilterNode;
class LogForwarder;

struct NativeSurface {
  NativeSurfaceType mType;
  SurfaceFormat mFormat;
  gfx::IntSize mSize;
  void *mSurface;
};

struct NativeFont {
  NativeFontType mType;
  void *mFont;
};

/**
 * This structure is used to send draw options that are universal to all drawing
 * operations.
 */
struct DrawOptions {
  /// For constructor parameter description, see member data documentation.
  explicit DrawOptions(Float aAlpha = 1.0f,
                       CompositionOp aCompositionOp = CompositionOp::OP_OVER,
                       AntialiasMode aAntialiasMode = AntialiasMode::DEFAULT)
    : mAlpha(aAlpha)
    , mCompositionOp(aCompositionOp)
    , mAntialiasMode(aAntialiasMode)
  {}

  Float mAlpha;                 /**< Alpha value by which the mask generated by this
                                     operation is multiplied. */
  CompositionOp mCompositionOp; /**< The operator that indicates how the source and
                                     destination patterns are blended. */
  AntialiasMode mAntialiasMode; /**< The AntiAlias mode used for this drawing
                                     operation. */
};

/**
 * This structure is used to send stroke options that are used in stroking
 * operations.
 */
struct StrokeOptions {
  /// For constructor parameter description, see member data documentation.
  explicit StrokeOptions(Float aLineWidth = 1.0f,
                         JoinStyle aLineJoin = JoinStyle::MITER_OR_BEVEL,
                         CapStyle aLineCap = CapStyle::BUTT,
                         Float aMiterLimit = 10.0f,
                         size_t aDashLength = 0,
                         const Float* aDashPattern = 0,
                         Float aDashOffset = 0.f)
    : mLineWidth(aLineWidth)
    , mMiterLimit(aMiterLimit)
    , mDashPattern(aDashLength > 0 ? aDashPattern : 0)
    , mDashLength(aDashLength)
    , mDashOffset(aDashOffset)
    , mLineJoin(aLineJoin)
    , mLineCap(aLineCap)
  {
    MOZ_ASSERT(aDashLength == 0 || aDashPattern);
  }

  Float mLineWidth;          //!< Width of the stroke in userspace.
  Float mMiterLimit;         //!< Miter limit in units of linewidth
  const Float* mDashPattern; /**< Series of on/off userspace lengths defining dash.
                                  Owned by the caller; must live at least as long as
                                  this StrokeOptions.
                                  mDashPattern != null <=> mDashLength > 0. */
  size_t mDashLength;        //!< Number of on/off lengths in mDashPattern.
  Float mDashOffset;         /**< Userspace offset within mDashPattern at which
                                  stroking begins. */
  JoinStyle mLineJoin;       //!< Join style used for joining lines.
  CapStyle mLineCap;         //!< Cap style used for capping lines.
};

/**
 * This structure supplies additional options for calls to DrawSurface.
 */
struct DrawSurfaceOptions {
  /// For constructor parameter description, see member data documentation.
  explicit DrawSurfaceOptions(SamplingFilter aSamplingFilter = SamplingFilter::LINEAR,
                              SamplingBounds aSamplingBounds = SamplingBounds::UNBOUNDED)
    : mSamplingFilter(aSamplingFilter)
    , mSamplingBounds(aSamplingBounds)
  { }

  SamplingFilter mSamplingFilter; /**< SamplingFilter used when resampling source surface
                                       region to the destination region. */
  SamplingBounds mSamplingBounds; /**< This indicates whether the implementation is
                                       allowed to sample pixels outside the source
                                       rectangle as specified in DrawSurface on
                                       the surface. */

};

/**
 * This class is used to store gradient stops, it can only be used with a
 * matching DrawTarget. Not adhering to this condition will make a draw call
 * fail.
 */
class GradientStops : public RefCounted<GradientStops>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops)
  virtual ~GradientStops() {}

  virtual BackendType GetBackendType() const = 0;
  virtual bool IsValid() const { return true; }

protected:
  GradientStops() {}
};

/**
 * This is the base class for 'patterns'. Patterns describe the pixels used as
 * the source for a masked composition operation that is done by the different
 * drawing commands. These objects are not backend specific, however for
 * example the gradient stops on a gradient pattern can be backend specific.
 */
class Pattern
{
public:
  virtual ~Pattern() {}

  virtual PatternType GetType() const = 0;

protected:
  Pattern() {}
};

class ColorPattern : public Pattern
{
public:
  // Explicit because consumers should generally use ToDeviceColor when
  // creating a ColorPattern.
  explicit ColorPattern(const Color &aColor)
    : mColor(aColor)
  {}

  virtual PatternType GetType() const override
  {
    return PatternType::COLOR;
  }

  Color mColor;
};

/**
 * This class is used for Linear Gradient Patterns, the gradient stops are
 * stored in a separate object and are backend dependent. This class itself
 * may be used on the stack.
 */
class LinearGradientPattern : public Pattern
{
public:
  /// For constructor parameter description, see member data documentation.
  LinearGradientPattern(const Point &aBegin,
                        const Point &aEnd,
                        GradientStops *aStops,
                        const Matrix &aMatrix = Matrix())
    : mBegin(aBegin)
    , mEnd(aEnd)
    , mStops(aStops)
    , mMatrix(aMatrix)
  {
  }

  virtual PatternType GetType() const override
  {
    return PatternType::LINEAR_GRADIENT;
  }

  Point mBegin;                 //!< Start of the linear gradient
  Point mEnd;                   /**< End of the linear gradient - NOTE: In the case
                                     of a zero length gradient it will act as the
                                     color of the last stop. */
  RefPtr<GradientStops> mStops; /**< GradientStops object for this gradient, this
                                     should match the backend type of the draw
                                     target this pattern will be used with. */
  Matrix mMatrix;               /**< A matrix that transforms the pattern into
                                     user space */
};

/**
 * This class is used for Radial Gradient Patterns, the gradient stops are
 * stored in a separate object and are backend dependent. This class itself
 * may be used on the stack.
 */
class RadialGradientPattern : public Pattern
{
public:
  /// For constructor parameter description, see member data documentation.
  RadialGradientPattern(const Point &aCenter1,
                        const Point &aCenter2,
                        Float aRadius1,
                        Float aRadius2,
                        GradientStops *aStops,
                        const Matrix &aMatrix = Matrix())
    : mCenter1(aCenter1)
    , mCenter2(aCenter2)
    , mRadius1(aRadius1)
    , mRadius2(aRadius2)
    , mStops(aStops)
    , mMatrix(aMatrix)
  {
  }

  virtual PatternType GetType() const override
  {
    return PatternType::RADIAL_GRADIENT;
  }

  Point mCenter1; //!< Center of the inner (focal) circle.
  Point mCenter2; //!< Center of the outer circle.
  Float mRadius1; //!< Radius of the inner (focal) circle.
  Float mRadius2; //!< Radius of the outer circle.
  RefPtr<GradientStops> mStops; /**< GradientStops object for this gradient, this
                                     should match the backend type of the draw target
                                     this pattern will be used with. */
  Matrix mMatrix; //!< A matrix that transforms the pattern into user space
};

/**
 * This class is used for Surface Patterns, they wrap a surface and a
 * repetition mode for the surface. This may be used on the stack.
 */
class SurfacePattern : public Pattern
{
public:
  /// For constructor parameter description, see member data documentation.
  SurfacePattern(SourceSurface *aSourceSurface, ExtendMode aExtendMode,
                 const Matrix &aMatrix = Matrix(),
                 SamplingFilter aSamplingFilter = SamplingFilter::GOOD,
                 const IntRect &aSamplingRect = IntRect())
    : mSurface(aSourceSurface)
    , mExtendMode(aExtendMode)
    , mSamplingFilter(aSamplingFilter)
    , mMatrix(aMatrix)
    , mSamplingRect(aSamplingRect)
  {}

  virtual PatternType GetType() const override
  {
    return PatternType::SURFACE;
  }

  RefPtr<SourceSurface> mSurface; //!< Surface to use for drawing
  ExtendMode mExtendMode;         /**< This determines how the image is extended
                                       outside the bounds of the image */
  SamplingFilter mSamplingFilter; //!< Resampling filter for resampling the image.
  Matrix mMatrix;                 //!< Transforms the pattern into user space

  IntRect mSamplingRect;          /**< Rect that must not be sampled outside of,
                                       or an empty rect if none has been specified. */
};

class StoredPattern;
class DrawTargetCaptureImpl;

/**
 * This is the base class for source surfaces. These objects are surfaces
 * which may be used as a source in a SurfacePattern or a DrawSurface call.
 * They cannot be drawn to directly.
 *
 * Although SourceSurface has thread-safe refcount, some SourceSurface cannot
 * be used on random threads at the same time. Only DataSourceSurface can be
 * used on random threads now. This will be fixed in the future. Eventually
 * all SourceSurface should be thread-safe.
 */
class SourceSurface : public external::AtomicRefCounted<SourceSurface>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
  virtual ~SourceSurface() {}

  virtual SurfaceType GetType() const = 0;
  virtual IntSize GetSize() const = 0;
  virtual SurfaceFormat GetFormat() const = 0;

  /** This returns false if some event has made this source surface invalid for
   * usage with current DrawTargets. For example in the case of Direct2D this
   * could return false if we have switched devices since this surface was
   * created.
   */
  virtual bool IsValid() const { return true; }

  /**
   * This function will get a DataSourceSurface for this surface, a
   * DataSourceSurface's data can be accessed directly.
   */
  virtual already_AddRefed<DataSourceSurface> GetDataSurface() = 0;

  /** Tries to get this SourceSurface's native surface.  This will fail if aType
   * is not the type of this SourceSurface's native surface.
   */
  virtual void *GetNativeSurface(NativeSurfaceType aType) {
    return nullptr;
  }

  void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
    mUserData.Add(key, userData, destroy);
  }
  void *GetUserData(UserDataKey *key) {
    return mUserData.Get(key);
  }

protected:
  friend class DrawTargetCaptureImpl;
  friend class StoredPattern;

  // This is for internal use, it ensures the SourceSurface's data remains
  // valid during the lifetime of the SourceSurface.
  // @todo XXX - We need something better here :(. But we may be able to get rid
  // of CreateWrappingDataSourceSurface in the future.
  virtual void GuaranteePersistance() {}

  UserData mUserData;
};

class DataSourceSurface : public SourceSurface
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurface, override)
  DataSourceSurface()
    : mIsMapped(false)
  {
  }

#ifdef DEBUG
  virtual ~DataSourceSurface()
  {
    MOZ_ASSERT(!mIsMapped, "Someone forgot to call Unmap()");
  }
#endif

  struct MappedSurface {
    uint8_t *mData;
    int32_t mStride;
  };

  enum MapType {
    READ,
    WRITE,
    READ_WRITE
  };

  /**
   * This is a scoped version of Map(). Map() is called in the constructor and
   * Unmap() in the destructor. Use this for automatic unmapping of your data
   * surfaces.
   *
   * Use IsMapped() to verify whether Map() succeeded or not.
   */
  class ScopedMap {
  public:
    explicit ScopedMap(DataSourceSurface* aSurface, MapType aType)
      : mSurface(aSurface)
      , mIsMapped(aSurface->Map(aType, &mMap)) {}

    virtual ~ScopedMap()
    {
      if (mIsMapped) {
        mSurface->Unmap();
      }
    }

    uint8_t* GetData() const
    {
      MOZ_ASSERT(mIsMapped);
      return mMap.mData;
    }

    int32_t GetStride() const
    {
      MOZ_ASSERT(mIsMapped);
      return mMap.mStride;
    }

    const MappedSurface* GetMappedSurface() const
    {
      MOZ_ASSERT(mIsMapped);
      return &mMap;
    }

    bool IsMapped() const { return mIsMapped; }

  private:
    RefPtr<DataSourceSurface> mSurface;
    MappedSurface mMap;
    bool mIsMapped;
  };

  virtual SurfaceType GetType() const override { return SurfaceType::DATA; }
  /** @deprecated
   * Get the raw bitmap data of the surface.
   * Can return null if there was OOM allocating surface data.
   */
  virtual uint8_t *GetData() = 0;

  /** @deprecated
   * Stride of the surface, distance in bytes between the start of the image
   * data belonging to row y and row y+1. This may be negative.
   * Can return 0 if there was OOM allocating surface data.
   */
  virtual int32_t Stride() = 0;

  /**
   * The caller is responsible for ensuring aMappedSurface is not null.
   */
  virtual bool Map(MapType, MappedSurface *aMappedSurface)
  {
    aMappedSurface->mData = GetData();
    aMappedSurface->mStride = Stride();
    mIsMapped = !!aMappedSurface->mData;
    return mIsMapped;
  }

  virtual void Unmap()
  {
    MOZ_ASSERT(mIsMapped);
    mIsMapped = false;
  }

  /**
   * Returns a DataSourceSurface with the same data as this one, but
   * guaranteed to have surface->GetType() == SurfaceType::DATA.
   */
  virtual already_AddRefed<DataSourceSurface> GetDataSurface() override;

protected:
  bool mIsMapped;
};

/** This is an abstract object that accepts path segments. */
class PathSink : public RefCounted<PathSink>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathSink)
  virtual ~PathSink() {}

  /** Move the current point in the path, any figure currently being drawn will
   * be considered closed during fill operations, however when stroking the
   * closing line segment will not be drawn.
   */
  virtual void MoveTo(const Point &aPoint) = 0;
  /** Add a linesegment to the current figure */
  virtual void LineTo(const Point &aPoint) = 0;
  /** Add a cubic bezier curve to the current figure */
  virtual void BezierTo(const Point &aCP1,
                        const Point &aCP2,
                        const Point &aCP3) = 0;
  /** Add a quadratic bezier curve to the current figure */
  virtual void QuadraticBezierTo(const Point &aCP1,
                                 const Point &aCP2) = 0;
  /** Close the current figure, this will essentially generate a line segment
   * from the current point to the starting point for the current figure
   */
  virtual void Close() = 0;
  /** Add an arc to the current figure */
  virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle,
                   float aEndAngle, bool aAntiClockwise = false) = 0;
  /** Point the current subpath is at - or where the next subpath will start
   * if there is no active subpath.
   */
  virtual Point CurrentPoint() const = 0;
};

class PathBuilder;
class FlattenedPath;

/** The path class is used to create (sets of) figures of any shape that can be
 * filled or stroked to a DrawTarget
 */
class Path : public RefCounted<Path>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
  virtual ~Path();

  virtual BackendType GetBackendType() const = 0;

  /** This returns a PathBuilder object that contains a copy of the contents of
   * this path and is still writable.
   */
  inline already_AddRefed<PathBuilder> CopyToBuilder() const {
    return CopyToBuilder(GetFillRule());
  }
  inline already_AddRefed<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform) const {
    return TransformedCopyToBuilder(aTransform, GetFillRule());
  }
  /** This returns a PathBuilder object that contains a copy of the contents of
   * this path, converted to use the specified FillRule, and still writable.
   */
  virtual already_AddRefed<PathBuilder> CopyToBuilder(FillRule aFillRule) const = 0;
  virtual already_AddRefed<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
                                                             FillRule aFillRule) const = 0;

  /** This function checks if a point lies within a path. It allows passing a
   * transform that will transform the path to the coordinate space in which
   * aPoint is given.
   */
  virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const = 0;


  /** This function checks if a point lies within the stroke of a path using the
   * specified strokeoptions. It allows passing a transform that will transform
   * the path to the coordinate space in which aPoint is given.
   */
  virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
                                   const Point &aPoint,
                                   const Matrix &aTransform) const = 0;

  /** This functions gets the bounds of this path. These bounds are not
   * guaranteed to be tight. A transform may be specified that gives the bounds
   * after application of the transform.
   */
  virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const = 0;

  /** This function gets the bounds of the stroke of this path using the
   * specified strokeoptions. These bounds are not guaranteed to be tight.
   * A transform may be specified that gives the bounds after application of
   * the transform.
   */
  virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
                                const Matrix &aTransform = Matrix()) const = 0;

  /** Take the contents of this path and stream it to another sink, this works
   * regardless of the backend that might be used for the destination sink.
   */
  virtual void StreamToSink(PathSink *aSink) const = 0;

  /** This gets the fillrule this path's builder was created with. This is not
   * mutable.
   */
  virtual FillRule GetFillRule() const = 0;

  virtual Float ComputeLength();

  virtual Point ComputePointAtLength(Float aLength,
                                     Point* aTangent = nullptr);

protected:
  Path();
  void EnsureFlattenedPath();

  RefPtr<FlattenedPath> mFlattenedPath;
};

/** The PathBuilder class allows path creation. Once finish is called on the
 * pathbuilder it may no longer be written to.
 */
class PathBuilder : public PathSink
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilder)
  /** Finish writing to the path and return a Path object that can be used for
   * drawing. Future use of the builder results in a crash!
   */
  virtual already_AddRefed<Path> Finish() = 0;

  virtual BackendType GetBackendType() const = 0;
};

struct Glyph
{
  uint32_t mIndex;
  Point mPosition;
};

/** This class functions as a glyph buffer that can be drawn to a DrawTarget.
 * @todo XXX - This should probably contain the guts of gfxTextRun in the future as
 * roc suggested. But for now it's a simple container for a glyph vector.
 */
struct GlyphBuffer
{
  const Glyph *mGlyphs; //!< A pointer to a buffer of glyphs. Managed by the caller.
  uint32_t mNumGlyphs;  //!< Number of glyphs mGlyphs points to.
};

struct GlyphMetrics
{
  // Horizontal distance from the origin to the leftmost side of the bounding
  // box of the drawn glyph. This can be negative!
  Float mXBearing;
  // Horizontal distance from the origin of this glyph to the origin of the
  // next glyph.
  Float mXAdvance;
  // Vertical distance from the origin to the topmost side of the bounding box
  // of the drawn glyph.
  Float mYBearing;
  // Vertical distance from the origin of this glyph to the origin of the next
  // glyph, this is used when drawing vertically and will typically be 0.
  Float mYAdvance;
  // Width of the glyph's black box.
  Float mWidth;
  // Height of the glyph's black box.
  Float mHeight;
};

/** This class is an abstraction of a backend/platform specific font object
 * at a particular size. It is passed into text drawing calls to describe
 * the font used for the drawing call.
 */
class ScaledFont : public RefCounted<ScaledFont>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
  virtual ~ScaledFont() {}

  typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void *aBaton);
  typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton);
  typedef void (*FontDescriptorOutput)(const uint8_t *aData, uint32_t aLength, Float aFontSize, void *aBaton);

  virtual FontType GetType() const = 0;
  virtual AntialiasMode GetDefaultAAMode() {
    if (gfxPrefs::DisableAllTextAA()) {
      return AntialiasMode::NONE;
    }

    return AntialiasMode::DEFAULT;
  }

  /** This allows getting a path that describes the outline of a set of glyphs.
   * A target is passed in so that the guarantee is made the returned path
   * can be used with any DrawTarget that has the same backend as the one
   * passed in.
   */
  virtual already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) = 0;

  /** This copies the path describing the glyphs into a PathBuilder. We use this
   * API rather than a generic API to append paths because it allows easier
   * implementation in some backends, and more efficient implementation in
   * others.
   */
  virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint = nullptr) = 0;

  /* This gets the metrics of a set of glyphs for the current font face.
   */
  virtual void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics) = 0;

  virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; }

  virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; }

  virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; }

  void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
    mUserData.Add(key, userData, destroy);
  }
  void *GetUserData(UserDataKey *key) {
    return mUserData.Get(key);
  }

protected:
  ScaledFont() {}

  UserData mUserData;
};

/**
 * Derived classes hold a native font resource from which to create
 * ScaledFonts.
 */
class NativeFontResource : public RefCounted<NativeFontResource>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResource)

  /**
   * Creates a ScaledFont using the font corresponding to the index and
   * the given glyph size.
   *
   * @param aIndex index for the font within the resource.
   * @param aGlyphSize the size of ScaledFont required.
   * @param aInstanceData pointer to read-only buffer of any available instance data.
   * @param aInstanceDataLength the size of the instance data.
   * @return an already_addrefed ScaledFont, containing nullptr if failed.
   */
  virtual already_AddRefed<ScaledFont>
    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) = 0;

  virtual ~NativeFontResource() {};
};

/** This class is designed to allow passing additional glyph rendering
 * parameters to the glyph drawing functions. This is an empty wrapper class
 * merely used to allow holding on to and passing around platform specific
 * parameters. This is because different platforms have unique rendering
 * parameters.
 */
class GlyphRenderingOptions : public RefCounted<GlyphRenderingOptions>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions)
  virtual ~GlyphRenderingOptions() {}

  virtual FontType GetType() const = 0;

protected:
  GlyphRenderingOptions() {}
};

class DrawTargetCapture;

/** This is the main class used for all the drawing. It is created through the
 * factory and accepts drawing commands. The results of drawing to a target
 * may be used either through a Snapshot or by flushing the target and directly
 * accessing the backing store a DrawTarget was created with.
 */
class DrawTarget : public RefCounted<DrawTarget>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget)
  DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false) {}
  virtual ~DrawTarget() {}

  virtual bool IsValid() const { return true; };
  virtual DrawTargetType GetType() const = 0;

  virtual BackendType GetBackendType() const = 0;

  virtual bool IsRecording() const { return false; }

  /**
   * Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget.
   * Multiple calls to Snapshot() without any drawing operations in between will
   * normally return the same SourceSurface object.
   */
  virtual already_AddRefed<SourceSurface> Snapshot() = 0;
  virtual IntSize GetSize() = 0;

  /**
   * If possible returns the bits to this DrawTarget for direct manipulation. While
   * the bits is locked any modifications to this DrawTarget is forbidden.
   * Release takes the original data pointer for safety.
   */
  virtual bool LockBits(uint8_t** aData, IntSize* aSize,
                        int32_t* aStride, SurfaceFormat* aFormat,
                        IntPoint* aOrigin = nullptr) { return false; }
  virtual void ReleaseBits(uint8_t* aData) {}

  /** Ensure that the DrawTarget backend has flushed all drawing operations to
   * this draw target. This must be called before using the backing surface of
   * this draw target outside of GFX 2D code.
   */
  virtual void Flush() = 0;

  /**
   * Realize a DrawTargetCapture onto the draw target.
   *
   * @param aSource Capture DrawTarget to draw
   * @param aTransform Transform to apply when replaying commands
   */
  virtual void DrawCapturedDT(DrawTargetCapture *aCaptureDT,
                              const Matrix& aTransform);

  /**
   * Draw a surface to the draw target. Possibly doing partial drawing or
   * applying scaling. No sampling happens outside the source.
   *
   * @param aSurface Source surface to draw
   * @param aDest Destination rectangle that this drawing operation should draw to
   * @param aSource Source rectangle in aSurface coordinates, this area of aSurface
   *                will be stretched to the size of aDest.
   * @param aOptions General draw options that are applied to the operation
   * @param aSurfOptions DrawSurface options that are applied
   */
  virtual void DrawSurface(SourceSurface *aSurface,
                           const Rect &aDest,
                           const Rect &aSource,
                           const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
                           const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Draw the output of a FilterNode to the DrawTarget.
   *
   * @param aNode FilterNode to draw
   * @param aSourceRect Source rectangle in FilterNode space to draw
   * @param aDestPoint Destination point on the DrawTarget to draw the
   *                   SourceRectangle of the filter output to
   */
  virtual void DrawFilter(FilterNode *aNode,
                          const Rect &aSourceRect,
                          const Point &aDestPoint,
                          const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Blend a surface to the draw target with a shadow. The shadow is drawn as a
   * gaussian blur using a specified sigma. The shadow is clipped to the size
   * of the input surface, so the input surface should contain a transparent
   * border the size of the approximate coverage of the blur (3 * aSigma).
   * NOTE: This function works in device space!
   *
   * @param aSurface Source surface to draw.
   * @param aDest Destination point that this drawing operation should draw to.
   * @param aColor Color of the drawn shadow
   * @param aOffset Offset of the shadow
   * @param aSigma Sigma used for the guassian filter kernel
   * @param aOperator Composition operator used
   */
  virtual void DrawSurfaceWithShadow(SourceSurface *aSurface,
                                     const Point &aDest,
                                     const Color &aColor,
                                     const Point &aOffset,
                                     Float aSigma,
                                     CompositionOp aOperator) = 0;

  /**
   * Clear a rectangle on the draw target to transparent black. This will
   * respect the clipping region and transform.
   *
   * @param aRect Rectangle to clear
   */
  virtual void ClearRect(const Rect &aRect) = 0;

  /**
   * This is essentially a 'memcpy' between two surfaces. It moves a pixel
   * aligned area from the source surface unscaled directly onto the
   * drawtarget. This ignores both transform and clip.
   *
   * @param aSurface Surface to copy from
   * @param aSourceRect Source rectangle to be copied
   * @param aDest Destination point to copy the surface to
   */
  virtual void CopySurface(SourceSurface *aSurface,
                           const IntRect &aSourceRect,
                           const IntPoint &aDestination) = 0;

  /** @see CopySurface
   * Same as CopySurface, except uses itself as the source.
   *
   * Some backends may be able to optimize this better
   * than just taking a snapshot and using CopySurface.
   */
  virtual void CopyRect(const IntRect &aSourceRect,
                        const IntPoint &aDestination)
  {
    RefPtr<SourceSurface> source = Snapshot();
    CopySurface(source, aSourceRect, aDestination);
  }

  /**
   * Fill a rectangle on the DrawTarget with a certain source pattern.
   *
   * @param aRect Rectangle that forms the mask of this filling operation
   * @param aPattern Pattern that forms the source of this filling operation
   * @param aOptions Options that are applied to this operation
   */
  virtual void FillRect(const Rect &aRect,
                        const Pattern &aPattern,
                        const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Stroke a rectangle on the DrawTarget with a certain source pattern.
   *
   * @param aRect Rectangle that forms the mask of this stroking operation
   * @param aPattern Pattern that forms the source of this stroking operation
   * @param aOptions Options that are applied to this operation
   */
  virtual void StrokeRect(const Rect &aRect,
                          const Pattern &aPattern,
                          const StrokeOptions &aStrokeOptions = StrokeOptions(),
                          const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Stroke a line on the DrawTarget with a certain source pattern.
   *
   * @param aStart Starting point of the line
   * @param aEnd End point of the line
   * @param aPattern Pattern that forms the source of this stroking operation
   * @param aOptions Options that are applied to this operation
   */
  virtual void StrokeLine(const Point &aStart,
                          const Point &aEnd,
                          const Pattern &aPattern,
                          const StrokeOptions &aStrokeOptions = StrokeOptions(),
                          const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Stroke a path on the draw target with a certain source pattern.
   *
   * @param aPath Path that is to be stroked
   * @param aPattern Pattern that should be used for the stroke
   * @param aStrokeOptions Stroke options used for this operation
   * @param aOptions Draw options used for this operation
   */
  virtual void Stroke(const Path *aPath,
                      const Pattern &aPattern,
                      const StrokeOptions &aStrokeOptions = StrokeOptions(),
                      const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Fill a path on the draw target with a certain source pattern.
   *
   * @param aPath Path that is to be filled
   * @param aPattern Pattern that should be used for the fill
   * @param aOptions Draw options used for this operation
   */
  virtual void Fill(const Path *aPath,
                    const Pattern &aPattern,
                    const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Fill a series of clyphs on the draw target with a certain source pattern.
   */
  virtual void FillGlyphs(ScaledFont *aFont,
                          const GlyphBuffer &aBuffer,
                          const Pattern &aPattern,
                          const DrawOptions &aOptions = DrawOptions(),
                          const GlyphRenderingOptions *aRenderingOptions = nullptr) = 0;

  /**
   * This takes a source pattern and a mask, and composites the source pattern
   * onto the destination surface using the alpha channel of the mask pattern
   * as a mask for the operation.
   *
   * @param aSource Source pattern
   * @param aMask Mask pattern
   * @param aOptions Drawing options
   */
  virtual void Mask(const Pattern &aSource,
                    const Pattern &aMask,
                    const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * This takes a source pattern and a mask, and composites the source pattern
   * onto the destination surface using the alpha channel of the mask source.
   * The operation is bound by the extents of the mask.
   *
   * @param aSource Source pattern
   * @param aMask Mask surface
   * @param aOffset a transformed offset that the surface is masked at
   * @param aOptions Drawing options
   */
  virtual void MaskSurface(const Pattern &aSource,
                           SourceSurface *aMask,
                           Point aOffset,
                           const DrawOptions &aOptions = DrawOptions()) = 0;

  /**
   * Draw aSurface using the 3D transform aMatrix. The DrawTarget's transform
   * and clip are applied after the 3D transform.
   *
   * If the transform fails (i.e. because aMatrix is singular), false is returned and nothing is drawn.
   */
  virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
                                        const Matrix4x4& aMatrix);

  /**
   * Push a clip to the DrawTarget.
   *
   * @param aPath The path to clip to
   */
  virtual void PushClip(const Path *aPath) = 0;

  /**
   * Push an axis-aligned rectangular clip to the DrawTarget. This rectangle
   * is specified in user space.
   *
   * @param aRect The rect to clip to
   */
  virtual void PushClipRect(const Rect &aRect) = 0;

  /**
   * Push a clip region specifed by the union of axis-aligned rectangular
   * clips to the DrawTarget. These rectangles are specified in device space.
   * This must be balanced by a corresponding call to PopClip within a layer.
   *
   * @param aRects The rects to clip to
   * @param aCount The number of rectangles
   */
  virtual void PushDeviceSpaceClipRects(const IntRect* aRects, uint32_t aCount);

  /** Pop a clip from the DrawTarget. A pop without a corresponding push will
   * be ignored.
   */
  virtual void PopClip() = 0;

  /**
   * Push a 'layer' to the DrawTarget, a layer is a temporary surface that all
   * drawing will be redirected to, this is used for example to support group
   * opacity or the masking of groups. Clips must be balanced within a layer,
   * i.e. between a matching PushLayer/PopLayer pair there must be as many
   * PushClip(Rect) calls as there are PopClip calls.
   *
   * @param aOpaque Whether the layer will be opaque
   * @param aOpacity Opacity of the layer
   * @param aMask Mask applied to the layer
   * @param aMaskTransform Transform applied to the layer mask
   * @param aBounds Optional bounds in device space to which the layer is
   *                limited in size.
   * @param aCopyBackground Whether to copy the background into the layer, this
   *                        is only supported when aOpaque is true.
   */
  virtual void PushLayer(bool aOpaque, Float aOpacity,
                         SourceSurface* aMask,
                         const Matrix& aMaskTransform,
                         const IntRect& aBounds = IntRect(),
                         bool aCopyBackground = false) { MOZ_CRASH("GFX: PushLayer"); }

  /**
   * This balances a call to PushLayer and proceeds to blend the layer back
   * onto the background. This blend will blend the temporary surface back
   * onto the target in device space using POINT sampling and operator over.
   */
  virtual void PopLayer() { MOZ_CRASH("GFX: PopLayer"); }

  /**
   * Create a SourceSurface optimized for use with this DrawTarget from
   * existing bitmap data in memory.
   *
   * The SourceSurface does not take ownership of aData, and may be freed at any time.
   */
  virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
                                                                      const IntSize &aSize,
                                                                      int32_t aStride,
                                                                      SurfaceFormat aFormat) const = 0;

  /**
   * Create a SourceSurface optimized for use with this DrawTarget from an
   * arbitrary SourceSurface type supported by this backend. This may return
   * aSourceSurface or some other existing surface.
   */
  virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const = 0;
  virtual already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const {
    return OptimizeSourceSurface(aSurface);
  }

  /**
   * Create a SourceSurface for a type of NativeSurface. This may fail if the
   * draw target does not know how to deal with the type of NativeSurface passed
   * in. If this succeeds, the SourceSurface takes the ownersip of the NativeSurface.
   */
  virtual already_AddRefed<SourceSurface>
    CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const = 0;

  /**
   * Create a DrawTarget whose snapshot is optimized for use with this DrawTarget.
   */
  virtual already_AddRefed<DrawTarget>
    CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0;

  /**
   * Create a DrawTarget that captures the drawing commands and can be replayed
   * onto a compatible DrawTarget afterwards.
   *
   * @param aSize Size of the area this DT will capture.
   */
  virtual already_AddRefed<DrawTargetCapture> CreateCaptureDT(const IntSize& aSize);

  /**
   * Create a draw target optimized for drawing a shadow.
   *
   * Note that aSigma is the blur radius that must be used when we draw the
   * shadow. Also note that this doesn't affect the size of the allocated
   * surface, the caller is still responsible for including the shadow area in
   * its size.
   */
  virtual already_AddRefed<DrawTarget>
    CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
                           float aSigma) const
  {
    return CreateSimilarDrawTarget(aSize, aFormat);
  }

  /**
   * Create a path builder with the specified fillmode.
   *
   * We need the fill mode up front because of Direct2D.
   * ID2D1SimplifiedGeometrySink requires the fill mode
   * to be set before calling BeginFigure().
   */
  virtual already_AddRefed<PathBuilder> CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const = 0;

  /**
   * Create a GradientStops object that holds information about a set of
   * gradient stops, this object is required for linear or radial gradient
   * patterns to represent the color stops in the gradient.
   *
   * @param aStops An array of gradient stops
   * @param aNumStops Number of stops in the array aStops
   * @param aExtendNone This describes how to extend the stop color outside of the
   *                    gradient area.
   */
  virtual already_AddRefed<GradientStops>
    CreateGradientStops(GradientStop *aStops,
                        uint32_t aNumStops,
                        ExtendMode aExtendMode = ExtendMode::CLAMP) const = 0;

  /**
   * Create a FilterNode object that can be used to apply a filter to various
   * inputs.
   *
   * @param aType Type of filter node to be created.
   */
  virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) = 0;

  Matrix GetTransform() const { return mTransform; }

  /*
   * Get the metrics of a glyph, including any additional spacing that is taken
   * during rasterization to this backends (for example because of antialiasing
   * filters.
   *
   * aScaledFont The scaled font used when drawing.
   * aGlyphIndices An array of indices for the glyphs whose the metrics are wanted
   * aNumGlyphs The amount of elements in aGlyphIndices
   * aGlyphMetrics The glyph metrics
   */
  virtual void GetGlyphRasterizationMetrics(ScaledFont *aScaledFont, const uint16_t* aGlyphIndices,
                                            uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics)
  {
    aScaledFont->GetGlyphDesignMetrics(aGlyphIndices, aNumGlyphs, aGlyphMetrics);
  }

  /**
   * Set a transform on the surface, this transform is applied at drawing time
   * to both the mask and source of the operation.
   *
   * Performance note: For some backends it is expensive to change the current
   * transform (because transforms affect a lot of the parts of the pipeline,
   * so new transform change can result in a pipeline flush).  To get around
   * this, DrawTarget implementations buffer transform changes and try to only
   * set the current transform on the backend when required.  That tracking has
   * its own performance impact though, and ideally callers would be smart
   * enough not to require it.  At a future date this method may stop this
   * doing transform buffering so, if you're a consumer, please try to be smart
   * about calling this method as little as possible.  For example, instead of
   * concatenating a translation onto the current transform then calling
   * FillRect, try to integrate the translation into FillRect's aRect
   * argument's x/y offset.
   */
  virtual void SetTransform(const Matrix &aTransform)
    { mTransform = aTransform; mTransformDirty = true; }

  inline void ConcatTransform(const Matrix &aTransform)
    { SetTransform(aTransform * Matrix(GetTransform())); }

  SurfaceFormat GetFormat() const { return mFormat; }

  /** Tries to get a native surface for a DrawTarget, this may fail if the
   * draw target cannot convert to this surface type.
   */
  virtual void *GetNativeSurface(NativeSurfaceType aType) { return nullptr; }

  virtual bool IsDualDrawTarget() const { return false; }
  virtual bool IsTiledDrawTarget() const { return false; }
  virtual bool SupportsRegionClipping() const { return true; }

  void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
    mUserData.Add(key, userData, destroy);
  }
  void *GetUserData(UserDataKey *key) const {
    return mUserData.Get(key);
  }
  void *RemoveUserData(UserDataKey *key) {
    return mUserData.Remove(key);
  }

  /** Within this rectangle all pixels will be opaque by the time the result of
   * this DrawTarget is first used for drawing. Either by the underlying surface
   * being used as an input to external drawing, or Snapshot() being called.
   * This rectangle is specified in device space.
   */
  void SetOpaqueRect(const IntRect &aRect) {
    mOpaqueRect = aRect;
  }

  const IntRect &GetOpaqueRect() const {
    return mOpaqueRect;
  }

  virtual bool IsCurrentGroupOpaque() {
    return GetFormat() == SurfaceFormat::B8G8R8X8;
  }

  virtual void SetPermitSubpixelAA(bool aPermitSubpixelAA) {
    mPermitSubpixelAA = aPermitSubpixelAA;
  }

  bool GetPermitSubpixelAA() {
    return mPermitSubpixelAA;
  }

  /**
   * Ensures that no snapshot is still pointing to this DrawTarget's surface data.
   *
   * This can be useful if the DrawTarget is wrapped around data that it does not
   * own, and for some reason the owner of the data has to make it temporarily
   * unavailable without the DrawTarget knowing about it.
   * This can cause costly surface copies, so it should not be used without a
   * a good reason.
   */
  virtual void DetachAllSnapshots() = 0;

#ifdef USE_SKIA_GPU
  virtual bool InitWithGrContext(GrContext* aGrContext,
                                 const IntSize &aSize,
                                 SurfaceFormat aFormat)
  {
    MOZ_CRASH("GFX: InitWithGrContext");
  }
#endif

protected:
  UserData mUserData;
  Matrix mTransform;
  IntRect mOpaqueRect;
  bool mTransformDirty : 1;
  bool mPermitSubpixelAA : 1;

  SurfaceFormat mFormat;
};

class DrawTargetCapture : public DrawTarget
{
};

class DrawEventRecorder : public RefCounted<DrawEventRecorder>
{
public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder)
  virtual ~DrawEventRecorder() { }
};

struct Tile
{
  RefPtr<DrawTarget> mDrawTarget;
  IntPoint mTileOrigin;
};

struct TileSet
{
  Tile* mTiles;
  size_t mTileCount;
};

struct Config {
  LogForwarder* mLogForwarder;
  int32_t mMaxTextureSize;
  int32_t mMaxAllocSize;

  Config()
  : mLogForwarder(nullptr)
  , mMaxTextureSize(8192)
  , mMaxAllocSize(52000000)
  {}
};

class GFX2D_API Factory
{
public:
  static void Init(const Config& aConfig);
  static void ShutDown();

  static bool HasSSE2();

  /**
   * Returns false if any of the following are true:
   *
   *   - the width/height of |sz| are less than or equal to zero
   *   - the width/height of |sz| are greater than |limit|
   *   - the number of bytes that need to be allocated for the surface is too
   *     big to fit in an int32_t, or bigger than |allocLimit|, if specifed
   *
   * To calculate the number of bytes that need to be allocated for the surface
   * this function makes the conservative assumption that there need to be
   * 4 bytes-per-pixel, and the stride alignment is 16 bytes.
   *
   * The reason for using int32_t rather than uint32_t is again to be
   * conservative; some code has in the past and may in the future use signed
   * integers to store buffer lengths etc.
   */
  static bool CheckSurfaceSize(const IntSize &sz,
                               int32_t limit = 0,
                               int32_t allocLimit = 0);

  /**
   * Make sure that the given buffer size doesn't exceed the allocation limit.
   */
  static bool CheckBufferSize(int32_t bufSize);

  /** Make sure the given dimension satisfies the CheckSurfaceSize and is
   * within 8k limit.  The 8k value is chosen a bit randomly.
   */
  static bool ReasonableSurfaceSize(const IntSize &aSize);

  static bool AllowedSurfaceSize(const IntSize &aSize);

  static already_AddRefed<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);

  static already_AddRefed<SourceSurface> CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat);

  static already_AddRefed<DrawTarget>
    CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);

  static already_AddRefed<DrawTarget>
    CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT);

  static already_AddRefed<DrawTarget>
    CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false);

  static already_AddRefed<ScaledFont>
    CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize);

#ifdef MOZ_WIDGET_GTK
  static already_AddRefed<ScaledFont>
    CreateScaledFontForFontconfigFont(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern, Float aSize);
#endif

  /**
   * This creates a NativeFontResource from TrueType data.
   *
   * @param aData Pointer to the data
   * @param aSize Size of the TrueType data
   * @param aType Type of NativeFontResource that should be created.
   * @return a NativeFontResource of nullptr if failed.
   */
  static already_AddRefed<NativeFontResource>
    CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType);

  /**
   * This creates a scaled font with an associated cairo_scaled_font_t, and
   * must be used when using the Cairo backend. The NativeFont and
   * cairo_scaled_font_t* parameters must correspond to the same font.
   */
  static already_AddRefed<ScaledFont>
    CreateScaledFontWithCairo(const NativeFont &aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont);

  /**
   * This creates a simple data source surface for a certain size. It allocates
   * new memory for the surface. This memory is freed when the surface is
   * destroyed.  The caller is responsible for handing the case where nullptr
   * is returned. The surface is not zeroed unless requested.
   */
  static already_AddRefed<DataSourceSurface>
    CreateDataSourceSurface(const IntSize &aSize, SurfaceFormat aFormat, bool aZero = false);

  /**
   * This creates a simple data source surface for a certain size with a
   * specific stride, which must be large enough to fit all pixels.
   * It allocates new memory for the surface. This memory is freed when
   * the surface is destroyed.  The caller is responsible for handling the case
   * where nullptr is returned. The surface is not zeroed unless requested.
   */
  static already_AddRefed<DataSourceSurface>
    CreateDataSourceSurfaceWithStride(const IntSize &aSize, SurfaceFormat aFormat, int32_t aStride, bool aZero = false);

  typedef void (*SourceSurfaceDeallocator)(void* aClosure);

  /**
   * This creates a simple data source surface for some existing data. It will
   * wrap this data and the data for this source surface.
   *
   * We can provide a custom destroying function for |aData|. This will be
   * called in the surface dtor using |aDeallocator| and the |aClosure|. If
   * there are errors during construction(return a nullptr surface), the caller
   * is responsible for the deallocation.
   *
   * If there is no destroying function, the caller is responsible for
   * deallocating the aData memory only after destruction of this
   * DataSourceSurface.
   */
  static already_AddRefed<DataSourceSurface>
    CreateWrappingDataSourceSurface(uint8_t *aData,
                                    int32_t aStride,
                                    const IntSize &aSize,
                                    SurfaceFormat aFormat,
                                    SourceSurfaceDeallocator aDeallocator = nullptr,
                                    void* aClosure = nullptr);

  static void
    CopyDataSourceSurface(DataSourceSurface* aSource,
                          DataSourceSurface* aDest);


  static already_AddRefed<DrawEventRecorder>
    CreateEventRecorderForFile(const char *aFilename);

  static void SetGlobalEventRecorder(DrawEventRecorder *aRecorder);

  static uint32_t GetMaxSurfaceSize(BackendType aType);

  static LogForwarder* GetLogForwarder() { return sConfig ? sConfig->mLogForwarder : nullptr; }

private:
  static Config* sConfig;
public:

#ifdef USE_SKIA_GPU
  static already_AddRefed<DrawTarget>
    CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
                                      const IntSize &aSize,
                                      SurfaceFormat aFormat);
#endif

  static void PurgeAllCaches();

  static already_AddRefed<DrawTarget>
    CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB);

  /*
   * This creates a new tiled DrawTarget. When a tiled drawtarget is used the
   * drawing is distributed over number of tiles which may each hold an
   * individual offset. The tiles in the set must each have the same backend
   * and format.
   */
  static already_AddRefed<DrawTarget> CreateTiledDrawTarget(const TileSet& aTileSet);

  static bool DoesBackendSupportDataDrawtarget(BackendType aType);

#ifdef USE_SKIA
  static already_AddRefed<DrawTarget> CreateDrawTargetWithSkCanvas(SkCanvas* aCanvas);
#endif

#ifdef XP_DARWIN
  static already_AddRefed<GlyphRenderingOptions>
    CreateCGGlyphRenderingOptions(const Color &aFontSmoothingBackgroundColor);
#endif

#ifdef WIN32
  static already_AddRefed<DrawTarget> CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat);

  /*
   * Attempts to create and install a D2D1 device from the supplied Direct3D11 device.
   * Returns true on success, or false on failure and leaves the D2D1/Direct3D11 devices unset.
   */
  static bool SetDirect3D11Device(ID3D11Device *aDevice);
  static bool SetDWriteFactory(IDWriteFactory *aFactory);
  static ID3D11Device *GetDirect3D11Device();
  static ID2D1Device *GetD2D1Device();
  static IDWriteFactory *GetDWriteFactory();
  static bool SupportsD2D1();

  static already_AddRefed<GlyphRenderingOptions>
    CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams);

  static uint64_t GetD2DVRAMUsageDrawTarget();
  static uint64_t GetD2DVRAMUsageSourceSurface();
  static void D2DCleanup();

  static already_AddRefed<ScaledFont>
    CreateScaledFontForDWriteFont(IDWriteFontFace* aFontFace,
                                  const gfxFontStyle* aStyle,
                                  Float aSize,
                                  bool aUseEmbeddedBitmap,
                                  bool aForceGDIMode);

private:
  static ID2D1Device *mD2D1Device;
  static ID3D11Device *mD3D11Device;
  static IDWriteFactory *mDWriteFactory;
#endif

  static DrawEventRecorder *mRecorder;
};

} // namespace gfx
} // namespace mozilla

#endif // _MOZILLA_GFX_2D_H
