summaryrefslogtreecommitdiffstats
path: root/layout/svg/SVGFilterInstance.h
blob: 3c67db308f9bdf3b3e104d07913f879fa2a14386 (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
/* -*- 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 LAYOUT_SVG_SVGFILTERINSTANCE_H_
#define LAYOUT_SVG_SVGFILTERINSTANCE_H_

#include "gfxMatrix.h"
#include "gfxRect.h"
#include "SVGAnimatedNumber.h"
#include "SVGAnimatedNumberPair.h"
#include "SVGFilters.h"
#include "mozilla/ServoStyleConsts.h"

namespace mozilla {
class SVGFilterFrame;

namespace dom {
class SVGFilterElement;
}  // namespace dom

/**
 * This class helps FilterInstance 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 SVGFilterInstance {
  using Point3D = gfx::Point3D;
  using IntRect = gfx::IntRect;
  using SourceSurface = gfx::SourceSurface;
  using FilterPrimitiveDescription = gfx::FilterPrimitiveDescription;
  using SVGFilterPrimitiveElement = dom::SVGFilterPrimitiveElement;
  using UserSpaceMetrics = dom::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 SVGFilterInstance.
   * @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.
   */
  SVGFilterInstance(
      const StyleFilter& aFilter, SVGFilterFrame* aFilterFrame,
      nsIContent* aTargetContent, const UserSpaceMetrics& aMetrics,
      const gfxRect& aTargetBBox,
      const gfx::MatrixScalesDouble& aUserSpaceToFilterSpaceScale);

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

  float GetPrimitiveNumber(uint8_t aCtxType,
                           const SVGAnimatedNumber* aNumber) const {
    return GetPrimitiveNumber(aCtxType, aNumber->GetAnimValue());
  }
  float GetPrimitiveNumber(uint8_t aCtxType,
                           const SVGAnimatedNumberPair* aNumberPair,
                           SVGAnimatedNumberPair::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:
  /**
   * Computes the filter primitive subregion for the given primitive.
   */
  IntRect ComputeFilterPrimitiveSubregion(
      SVGFilterPrimitiveElement* 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;

  /**
   * 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(
      SVGFilterPrimitiveElement* aPrimitiveElement,
      nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
      const nsTHashMap<nsStringHashKey, int32_t>& aImageTable,
      nsTArray<int32_t>& aSourceIndices);

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

  /**
   * The SVG reference filter originally from the style system.
   */
  const StyleFilter& 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 dom::SVGFilterElement* mFilterElement;

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

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

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

  /**
   * The scale factors between user space and filter space.
   */
  gfx::MatrixScalesDouble mUserSpaceToFilterSpaceScale;

  /**
   * 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;
};

}  // namespace mozilla

#endif  // LAYOUT_SVG_SVGFILTERINSTANCE_H_