Blame layout/svg/SVGContextPaint.h

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#ifndef MOZILLA_SVGCONTEXTPAINT_H_
Packit f0b94e
#define MOZILLA_SVGCONTEXTPAINT_H_
Packit f0b94e
Packit f0b94e
#include "DrawMode.h"
Packit f0b94e
#include "gfxMatrix.h"
Packit f0b94e
#include "gfxPattern.h"
Packit f0b94e
#include "gfxTypes.h"
Packit f0b94e
#include "gfxUtils.h"
Packit f0b94e
#include "mozilla/AlreadyAddRefed.h"
Packit f0b94e
#include "mozilla/Assertions.h"
Packit f0b94e
#include "mozilla/gfx/2D.h"
Packit f0b94e
#include "nsColor.h"
Packit f0b94e
#include "nsStyleStruct.h"
Packit f0b94e
#include "nsTArray.h"
Packit f0b94e
#include "ImgDrawResult.h"
Packit f0b94e
Packit f0b94e
class gfxContext;
Packit f0b94e
class nsIDocument;
Packit f0b94e
class nsSVGPaintServerFrame;
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
Packit f0b94e
/**
Packit f0b94e
 * This class is used to pass information about a context element through to
Packit f0b94e
 * SVG painting code in order to resolve the 'context-fill' and related
Packit f0b94e
 * keywords. See:
Packit f0b94e
 *
Packit f0b94e
 *   https://www.w3.org/TR/SVG2/painting.html#context-paint
Packit f0b94e
 *
Packit f0b94e
 * This feature allows the color in an SVG-in-OpenType glyph to come from the
Packit f0b94e
 * computed style for the text that is being drawn, for example, or for color
Packit f0b94e
 * in an SVG embedded by an  element to come from the embedding 
Packit f0b94e
 * element.
Packit f0b94e
 *
Packit f0b94e
 * This class is reference counted so that it can be shared among many similar
Packit f0b94e
 * SVGImageContext objects. (SVGImageContext objects are frequently
Packit f0b94e
 * copy-constructed with small modifications, and we'd like for those copies to
Packit f0b94e
 * be able to share their context-paint data cheaply.)  However, in most cases,
Packit f0b94e
 * SVGContextPaint instances are stored in a local RefPtr and only last for the
Packit f0b94e
 * duration of a function call.
Packit f0b94e
 * XXX Note: SVGImageContext doesn't actually have a SVGContextPaint member yet,
Packit f0b94e
 * but it will in a later patch in the patch series that added this comment.
Packit f0b94e
 */
Packit f0b94e
class SVGContextPaint : public RefCounted<SVGContextPaint> {
Packit f0b94e
 protected:
Packit f0b94e
  typedef mozilla::gfx::DrawTarget DrawTarget;
Packit f0b94e
  typedef mozilla::gfx::Float Float;
Packit f0b94e
  typedef mozilla::image::imgDrawingParams imgDrawingParams;
Packit f0b94e
Packit f0b94e
  SVGContextPaint() : mDashOffset(0.0f), mStrokeWidth(0.0f) {}
Packit f0b94e
Packit f0b94e
 public:
Packit f0b94e
  MOZ_DECLARE_REFCOUNTED_TYPENAME(SVGContextPaint)
Packit f0b94e
Packit f0b94e
  virtual ~SVGContextPaint() {}
Packit f0b94e
Packit f0b94e
  virtual already_AddRefed<gfxPattern> GetFillPattern(
Packit f0b94e
      const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM,
Packit f0b94e
      imgDrawingParams& aImgParams) = 0;
Packit f0b94e
  virtual already_AddRefed<gfxPattern> GetStrokePattern(
Packit f0b94e
      const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM,
Packit f0b94e
      imgDrawingParams& aImgParams) = 0;
Packit f0b94e
  virtual float GetFillOpacity() const = 0;
Packit f0b94e
  virtual float GetStrokeOpacity() const = 0;
Packit f0b94e
Packit f0b94e
  already_AddRefed<gfxPattern> GetFillPattern(const DrawTarget* aDrawTarget,
Packit f0b94e
                                              const gfxMatrix& aCTM,
Packit f0b94e
                                              imgDrawingParams& aImgParams) {
Packit f0b94e
    return GetFillPattern(aDrawTarget, GetFillOpacity(), aCTM, aImgParams);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  already_AddRefed<gfxPattern> GetStrokePattern(const DrawTarget* aDrawTarget,
Packit f0b94e
                                                const gfxMatrix& aCTM,
Packit f0b94e
                                                imgDrawingParams& aImgParams) {
Packit f0b94e
    return GetStrokePattern(aDrawTarget, GetStrokeOpacity(), aCTM, aImgParams);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  static SVGContextPaint* GetContextPaint(nsIContent* aContent);
Packit f0b94e
Packit f0b94e
  // XXX This gets the geometry params from the gfxContext.  We should get that
Packit f0b94e
  // information from the actual paint context!
Packit f0b94e
  void InitStrokeGeometry(gfxContext* aContext, float devUnitsPerSVGUnit);
Packit f0b94e
Packit f0b94e
  const FallibleTArray<Float>& GetStrokeDashArray() const { return mDashes; }
Packit f0b94e
Packit f0b94e
  Float GetStrokeDashOffset() const { return mDashOffset; }
Packit f0b94e
Packit f0b94e
  Float GetStrokeWidth() const { return mStrokeWidth; }
Packit f0b94e
Packit f0b94e
  virtual uint32_t Hash() const {
Packit f0b94e
    MOZ_ASSERT_UNREACHABLE(
Packit f0b94e
        "Only VectorImage needs to hash, and that should "
Packit f0b94e
        "only be operating on our SVGEmbeddingContextPaint "
Packit f0b94e
        "subclass");
Packit f0b94e
    return 0;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  /**
Packit f0b94e
   * Returns true if image context paint is allowed to be used in an image that
Packit f0b94e
   * has the given URI, else returns false.
Packit f0b94e
   */
Packit f0b94e
  static bool IsAllowedForImageFromURI(nsIURI* aURI);
Packit f0b94e
Packit f0b94e
 private:
Packit f0b94e
  // Member-vars are initialized in InitStrokeGeometry.
Packit f0b94e
  FallibleTArray<Float> mDashes;
Packit f0b94e
  MOZ_INIT_OUTSIDE_CTOR Float mDashOffset;
Packit f0b94e
  MOZ_INIT_OUTSIDE_CTOR Float mStrokeWidth;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
/**
Packit f0b94e
 * RAII class used to temporarily set and remove an SVGContextPaint while a
Packit f0b94e
 * piece of SVG is being painted.  The context paint is set on the SVG's owner
Packit f0b94e
 * document, as expected by SVGContextPaint::GetContextPaint.  Any pre-existing
Packit f0b94e
 * context paint is restored after this class removes the context paint that it
Packit f0b94e
 * set.
Packit f0b94e
 */
Packit f0b94e
class MOZ_RAII AutoSetRestoreSVGContextPaint {
Packit f0b94e
 public:
Packit f0b94e
  AutoSetRestoreSVGContextPaint(const SVGContextPaint* aContextPaint,
Packit f0b94e
                                nsIDocument* aSVGDocument);
Packit f0b94e
  ~AutoSetRestoreSVGContextPaint();
Packit f0b94e
Packit f0b94e
 private:
Packit f0b94e
  nsIDocument* mSVGDocument;
Packit f0b94e
  // The context paint that needs to be restored by our dtor after it removes
Packit f0b94e
  // aContextPaint:
Packit f0b94e
  void* mOuterContextPaint;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
/**
Packit f0b94e
 * This class should be flattened into SVGContextPaint once we get rid of the
Packit f0b94e
 * other sub-class (SimpleTextContextPaint).
Packit f0b94e
 */
Packit f0b94e
struct SVGContextPaintImpl : public SVGContextPaint {
Packit f0b94e
 protected:
Packit f0b94e
  typedef mozilla::gfx::DrawTarget DrawTarget;
Packit f0b94e
Packit f0b94e
 public:
Packit f0b94e
  DrawMode Init(const DrawTarget* aDrawTarget, const gfxMatrix& aContextMatrix,
Packit f0b94e
                nsIFrame* aFrame, SVGContextPaint* aOuterContextPaint,
Packit f0b94e
                imgDrawingParams& aImgParams);
Packit f0b94e
Packit f0b94e
  already_AddRefed<gfxPattern> GetFillPattern(
Packit f0b94e
      const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM,
Packit f0b94e
      imgDrawingParams& aImgParams) override;
Packit f0b94e
  already_AddRefed<gfxPattern> GetStrokePattern(
Packit f0b94e
      const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM,
Packit f0b94e
      imgDrawingParams& aImgParams) override;
Packit f0b94e
Packit f0b94e
  void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; }
Packit f0b94e
  float GetFillOpacity() const override { return mFillOpacity; }
Packit f0b94e
Packit f0b94e
  void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; }
Packit f0b94e
  float GetStrokeOpacity() const override { return mStrokeOpacity; }
Packit f0b94e
Packit f0b94e
  struct Paint {
Packit f0b94e
    Paint() : mPaintType(eStyleSVGPaintType_None) {}
Packit f0b94e
Packit f0b94e
    void SetPaintServer(nsIFrame* aFrame, const gfxMatrix& aContextMatrix,
Packit f0b94e
                        nsSVGPaintServerFrame* aPaintServerFrame) {
Packit f0b94e
      mPaintType = eStyleSVGPaintType_Server;
Packit f0b94e
      mPaintDefinition.mPaintServerFrame = aPaintServerFrame;
Packit f0b94e
      mFrame = aFrame;
Packit f0b94e
      mContextMatrix = aContextMatrix;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    void SetColor(const nscolor& aColor) {
Packit f0b94e
      mPaintType = eStyleSVGPaintType_Color;
Packit f0b94e
      mPaintDefinition.mColor = aColor;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    void SetContextPaint(SVGContextPaint* aContextPaint,
Packit f0b94e
                         nsStyleSVGPaintType aPaintType) {
Packit f0b94e
      NS_ASSERTION(aPaintType == eStyleSVGPaintType_ContextFill ||
Packit f0b94e
                       aPaintType == eStyleSVGPaintType_ContextStroke,
Packit f0b94e
                   "Invalid context paint type");
Packit f0b94e
      mPaintType = aPaintType;
Packit f0b94e
      mPaintDefinition.mContextPaint = aContextPaint;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    union {
Packit f0b94e
      nsSVGPaintServerFrame* mPaintServerFrame;
Packit f0b94e
      SVGContextPaint* mContextPaint;
Packit f0b94e
      nscolor mColor;
Packit f0b94e
    } mPaintDefinition;
Packit f0b94e
Packit f0b94e
    // Initialized (if needed) in SetPaintServer():
Packit f0b94e
    MOZ_INIT_OUTSIDE_CTOR nsIFrame* mFrame;
Packit f0b94e
    // CTM defining the user space for the pattern we will use.
Packit f0b94e
    gfxMatrix mContextMatrix;
Packit f0b94e
    nsStyleSVGPaintType mPaintType;
Packit f0b94e
Packit f0b94e
    // Device-space-to-pattern-space
Packit f0b94e
    gfxMatrix mPatternMatrix;
Packit f0b94e
    nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache;
Packit f0b94e
Packit f0b94e
    already_AddRefed<gfxPattern> GetPattern(
Packit f0b94e
        const DrawTarget* aDrawTarget, float aOpacity,
Packit f0b94e
        nsStyleSVGPaint nsStyleSVG::*aFillOrStroke, const gfxMatrix& aCTM,
Packit f0b94e
        imgDrawingParams& aImgParams);
Packit f0b94e
  };
Packit f0b94e
Packit f0b94e
  Paint mFillPaint;
Packit f0b94e
  Paint mStrokePaint;
Packit f0b94e
Packit f0b94e
  float mFillOpacity;
Packit f0b94e
  float mStrokeOpacity;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
/**
Packit f0b94e
 * This class is used to pass context paint to an SVG image when an element
Packit f0b94e
 * references that image (e.g. via HTML  or SVG <image>, or by referencing
Packit f0b94e
 * it from a CSS property such as 'background-image').  In this case we only
Packit f0b94e
 * support context colors and not paint servers.
Packit f0b94e
 */
Packit f0b94e
class SVGEmbeddingContextPaint : public SVGContextPaint {
Packit f0b94e
  typedef gfx::Color Color;
Packit f0b94e
Packit f0b94e
 public:
Packit f0b94e
  SVGEmbeddingContextPaint() : mFillOpacity(1.0f), mStrokeOpacity(1.0f) {}
Packit f0b94e
Packit f0b94e
  bool operator==(const SVGEmbeddingContextPaint& aOther) const {
Packit f0b94e
    MOZ_ASSERT(GetStrokeWidth() == aOther.GetStrokeWidth() &&
Packit f0b94e
                   GetStrokeDashOffset() == aOther.GetStrokeDashOffset() &&
Packit f0b94e
                   GetStrokeDashArray() == aOther.GetStrokeDashArray(),
Packit f0b94e
               "We don't currently include these in the context information "
Packit f0b94e
               "from an embedding element");
Packit f0b94e
    return mFill == aOther.mFill && mStroke == aOther.mStroke &&
Packit f0b94e
           mFillOpacity == aOther.mFillOpacity &&
Packit f0b94e
           mStrokeOpacity == aOther.mStrokeOpacity;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void SetFill(nscolor aFill) { mFill.emplace(gfx::ToDeviceColor(aFill)); }
Packit f0b94e
  const Maybe<Color>& GetFill() const { return mFill; }
Packit f0b94e
  void SetStroke(nscolor aStroke) {
Packit f0b94e
    mStroke.emplace(gfx::ToDeviceColor(aStroke));
Packit f0b94e
  }
Packit f0b94e
  const Maybe<Color>& GetStroke() const { return mStroke; }
Packit f0b94e
Packit f0b94e
  /**
Packit f0b94e
   * Returns a pattern of type PatternType::COLOR, or else nullptr.
Packit f0b94e
   */
Packit f0b94e
  already_AddRefed<gfxPattern> GetFillPattern(
Packit f0b94e
      const DrawTarget* aDrawTarget, float aFillOpacity, const gfxMatrix& aCTM,
Packit f0b94e
      imgDrawingParams& aImgParams) override;
Packit f0b94e
Packit f0b94e
  /**
Packit f0b94e
   * Returns a pattern of type PatternType::COLOR, or else nullptr.
Packit f0b94e
   */
Packit f0b94e
  already_AddRefed<gfxPattern> GetStrokePattern(
Packit f0b94e
      const DrawTarget* aDrawTarget, float aStrokeOpacity,
Packit f0b94e
      const gfxMatrix& aCTM, imgDrawingParams& aImgParams) override;
Packit f0b94e
Packit f0b94e
  void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; }
Packit f0b94e
  float GetFillOpacity() const override { return mFillOpacity; };
Packit f0b94e
Packit f0b94e
  void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; }
Packit f0b94e
  float GetStrokeOpacity() const override { return mStrokeOpacity; };
Packit f0b94e
Packit f0b94e
  uint32_t Hash() const override;
Packit f0b94e
Packit f0b94e
 private:
Packit f0b94e
  Maybe<Color> mFill;
Packit f0b94e
  Maybe<Color> mStroke;
Packit f0b94e
  float mFillOpacity;
Packit f0b94e
  float mStrokeOpacity;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
}  // namespace mozilla
Packit f0b94e
Packit f0b94e
#endif  // MOZILLA_SVGCONTEXTPAINT_H_