DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (777e60ca8853)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
/* -*- Mode: C++; tab-width: 2; 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 __NS_SVGFILTERINSTANCE_H__
#define __NS_SVGFILTERINSTANCE_H__

#include "gfxMatrix.h"
#include "gfxRect.h"
#include "nsSVGFilters.h"
#include "nsSVGNumber2.h"
#include "nsSVGNumberPair.h"
#include "nsTArray.h"
#include "nsIFrame.h"

class nsIFrame;
class nsSVGFilterFrame;
class nsSVGFilterPaintCallback;

namespace mozilla {
namespace dom {
class SVGFilterElement;
}
}

/**
 * This class helps nsFilterInstance build its filter graph by processing a
 * single SVG reference filter.
 *
 * In BuildPrimitives, this class iterates through the referenced <filter>
 * element's primitive elements, creating a FilterPrimitiveDescription for
 * each one.
 *
 * This class uses several different coordinate spaces, defined as follows:
 *
 * "user space"
 *   The filtered SVG element's user space or the filtered HTML element's
 *   CSS pixel space. The origin for an HTML element is the top left corner of
 *   its border box.
 *
 * "filter space"
 *   User space scaled to device pixels. Shares the same origin as user space.
 *   This space is the same across chained SVG and CSS filters. To compute the
 *   overall filter space for a chain, we first need to build each filter's
 *   FilterPrimitiveDescriptions in some common space. That space is
 *   filter space.
 *
 * To understand the spaces better, let's take an example filter:
 *   <filter id="f">...</filter>
 *
 * And apply the filter to a div element:
 *   <div style="filter: url(#f); ...">...</div>
 *
 * And let's say there are 2 device pixels for every 1 CSS pixel.
 *
 * Finally, let's define an arbitrary point in user space:
 *   "user space point" = (10, 10)
 *
 * The point will be inset 10 CSS pixels from both the top and left edges of the
 * div element's border box.
 *
 * Now, let's transform the point from user space to filter space:
 *   "filter space point" = "user space point" * "device pixels per CSS pixel"
 *   "filter space point" = (10, 10) * 2
 *   "filter space point" = (20, 20)
 */
class nsSVGFilterInstance
{
  typedef mozilla::gfx::Point3D Point3D;
  typedef mozilla::gfx::IntRect IntRect;
  typedef mozilla::gfx::SourceSurface SourceSurface;
  typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;

public:
  /**
   * @param aFilter The SVG reference filter to process.
   * @param aTargetFrame The frame of the filtered element under consideration.
   * @param aTargetBBox The SVG bbox to use for the target frame, computed by
   *   the caller. The caller may decide to override the actual SVG bbox.
   */
  nsSVGFilterInstance(const nsStyleFilter& aFilter,
                      nsIFrame *aTargetFrame,
                      const gfxRect& aTargetBBox,
                      const gfxSize& aUserSpaceToFilterSpaceScale,
                      const gfxSize& aFilterSpaceToUserSpaceScale);

  /**
   * Returns true if the filter instance was created successfully.
   */
  bool IsInitialized() const { return mInitialized; }

  /**
   * Iterates through the <filter> element's primitive elements, creating a
   * FilterPrimitiveDescription for each one. Appends the new
   * FilterPrimitiveDescription(s) to the aPrimitiveDescrs list. Also, appends
   * new images from feImage filter primitive elements to the aInputImages list.
   */
  nsresult BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                           nsTArray<mozilla::RefPtr<SourceSurface>>& aInputImages);

  /**
   * Returns the user specified "filter region", in the filtered element's user
   * space, after it has been adjusted out (if necessary) so that its edges
   * coincide with pixel boundaries of the offscreen surface into which the
   * filtered output would/will be painted.
   */
  gfxRect GetFilterRegion() const { return mUserSpaceBounds; }

  /**
   * Returns the size of the user specified "filter region", in filter space.
   */
  nsIntRect GetFilterSpaceBounds() const { return mFilterSpaceBounds; }

  float GetPrimitiveNumber(uint8_t aCtxType, const nsSVGNumber2 *aNumber) const
  {
    return GetPrimitiveNumber(aCtxType, aNumber->GetAnimValue());
  }
  float GetPrimitiveNumber(uint8_t aCtxType, const nsSVGNumberPair *aNumberPair,
                           nsSVGNumberPair::PairIndex aIndex) const
  {
    return GetPrimitiveNumber(aCtxType, aNumberPair->GetAnimValue(aIndex));
  }

  /**
   * Converts a userSpaceOnUse/objectBoundingBoxUnits unitless point
   * into filter space, depending on the value of mPrimitiveUnits. (For
   * objectBoundingBoxUnits, the bounding box offset is applied to the point.)
   */
  Point3D ConvertLocation(const Point3D& aPoint) const;

  /**
   * Transform a rect between user space and filter space.
   */
  gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const;

private:
  /**
   * Finds the filter frame associated with this SVG filter.
   */
  nsSVGFilterFrame* GetFilterFrame();

  /**
   * Computes the filter primitive subregion for the given primitive.
   */
  IntRect ComputeFilterPrimitiveSubregion(nsSVGFE* aFilterElement,
                                          const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                                          const nsTArray<int32_t>& aInputIndices);

  /**
   * Takes the input indices of a filter primitive and returns for each input
   * whether the input's output is tainted.
   */
  void GetInputsAreTainted(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                           const nsTArray<int32_t>& aInputIndices,
                           nsTArray<bool>& aOutInputsAreTainted);

  /**
   * Scales a numeric filter primitive length in the X, Y or "XY" directions
   * into a length in filter space (no offset is applied).
   */
  float GetPrimitiveNumber(uint8_t aCtxType, float aValue) const;

  /**
   * Transform a rect between user space and filter space.
   */
  gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const;

  /**
   * Returns the transform from frame space to the coordinate space that
   * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the
   * top-left corner of its border box, aka the top left corner of its mRect.
   */
  gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const;

  /**
   * Finds the index in aPrimitiveDescrs of each input to aPrimitiveElement.
   * For example, if aPrimitiveElement is:
   *   <feGaussianBlur in="another-primitive" .../>
   * Then, the resulting aSourceIndices will contain the index of the
   * FilterPrimitiveDescription representing "another-primitive".
   */
  nsresult GetSourceIndices(nsSVGFE* aPrimitiveElement,
                            const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                            const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
                            nsTArray<int32_t>& aSourceIndices);

  /**
   * Compute the filter region in user space, filter space, and filter
   * space.
   */
  nsresult ComputeBounds();

  /**
   * The SVG reference filter originally from the style system.
   */
  const nsStyleFilter mFilter;

  /**
   * The frame for the element that is currently being filtered.
   */
  nsIFrame*               mTargetFrame;

  /**
   * The filter element referenced by mTargetFrame's element.
   */
  const mozilla::dom::SVGFilterElement* mFilterElement;

  /**
   * The frame for the SVG filter element.
   */
  nsSVGFilterFrame* mFilterFrame;

  /**
   * The SVG bbox of the element that is being filtered, in user space.
   */
  gfxRect                 mTargetBBox;

  /**
   * The "filter region" in various spaces.
   */
  gfxRect                 mUserSpaceBounds;
  nsIntRect               mFilterSpaceBounds;

  /**
   * The scale factors between user space and filter space.
   */
  gfxSize                 mUserSpaceToFilterSpaceScale;
  gfxSize                 mFilterSpaceToUserSpaceScale;

  /**
   * The 'primitiveUnits' attribute value (objectBoundingBox or userSpaceOnUse).
   */
  uint16_t                mPrimitiveUnits;

  /**
   * The index of the FilterPrimitiveDescription that this SVG filter should use
   * as its SourceGraphic, or the SourceGraphic keyword index if this is the
   * first filter in a chain.
   */
  int32_t mSourceGraphicIndex;

  bool                    mInitialized;
};

#endif