summaryrefslogtreecommitdiffstats
path: root/layout/svg/nsSVGFilterInstance.h
blob: a4001dbd4f1270e36c99d92bd48f924935bdabe9 (plain)
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/* -*- 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"

class nsSVGFilterFrame;
struct nsStyleFilter;

namespace mozilla {
namespace dom {
class SVGFilterElement;
} // namespace dom
} // namespace mozilla

/**
 * 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;
  typedef mozilla::dom::UserSpaceMetrics UserSpaceMetrics;

public:
  /**
   * @param aFilter The SVG filter reference from the style system. This class
   *   stores aFilter by reference, so callers should avoid modifying or
   *   deleting aFilter during the lifetime of nsSVGFilterInstance.
   * @param aTargetContent The filtered element.
   * @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,
                      nsIContent* aTargetContent,
                      const UserSpaceMetrics& aMetrics,
                      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.
   * aInputIsTainted describes whether the input to this filter is tainted, i.e.
   * whether it contains security-sensitive content. This is needed to propagate
   * taintedness to the FilterPrimitive that take tainted inputs. Something being
   * tainted means that it contains security sensitive content.
   * The input to this filter is the previous filter's output, i.e. the last
   * element in aPrimitiveDescrs, or the SourceGraphic input if this is the first
   * filter in the filter chain.
   */
  nsresult BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                           nsTArray<RefPtr<SourceSurface>>& aInputImages,
                           bool aInputIsTainted);

  /**
   * 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(nsIFrame* aTargetFrame);

  /**
   * 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,
                           bool aFilterInputIsTainted,
                           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;

  /**
   * Appends a new FilterPrimitiveDescription to aPrimitiveDescrs that
   * converts the FilterPrimitiveDescription at mSourceGraphicIndex into
   * a SourceAlpha input for the next FilterPrimitiveDescription.
   *
   * The new FilterPrimitiveDescription zeros out the SourceGraphic's RGB
   * channels and keeps the alpha channel intact.
   */
  int32_t GetOrCreateSourceAlphaIndex(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);

  /**
   * 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,
                            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 filtered element.
   */
  nsIContent* mTargetContent;

  /**
   * The SVG user space metrics that SVG lengths are resolved against.
   */
  const UserSpaceMetrics& mMetrics;

  /**
   * 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. Initialized in BuildPrimitives
   */
  MOZ_INIT_OUTSIDE_CTOR int32_t mSourceGraphicIndex;

  /**
   * The index of the FilterPrimitiveDescription that this SVG filter should use
   * as its SourceAlpha, or the SourceAlpha keyword index if this is the first
   * filter in a chain. Initialized in BuildPrimitives
   */
  MOZ_INIT_OUTSIDE_CTOR int32_t mSourceAlphaIndex;

  /**
   * SourceAlpha is available if GetOrCreateSourceAlphaIndex has been called.
   */
  int32_t mSourceAlphaAvailable;

  bool mInitialized;
};

#endif