|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef __NS_SVGFILTERINSTANCE_H__ |
|
7 #define __NS_SVGFILTERINSTANCE_H__ |
|
8 |
|
9 #include "gfxMatrix.h" |
|
10 #include "gfxRect.h" |
|
11 #include "nsSVGFilters.h" |
|
12 #include "nsSVGNumber2.h" |
|
13 #include "nsSVGNumberPair.h" |
|
14 #include "nsTArray.h" |
|
15 #include "nsIFrame.h" |
|
16 |
|
17 class nsIFrame; |
|
18 class nsSVGFilterFrame; |
|
19 class nsSVGFilterPaintCallback; |
|
20 |
|
21 namespace mozilla { |
|
22 namespace dom { |
|
23 class SVGFilterElement; |
|
24 } |
|
25 } |
|
26 |
|
27 /** |
|
28 * This class helps nsFilterInstance build its filter graph by processing a |
|
29 * single SVG reference filter. |
|
30 * |
|
31 * In BuildPrimitives, this class iterates through the referenced <filter> |
|
32 * element's primitive elements, creating a FilterPrimitiveDescription for |
|
33 * each one. |
|
34 * |
|
35 * This class uses several different coordinate spaces, defined as follows: |
|
36 * |
|
37 * "user space" |
|
38 * The filtered SVG element's user space or the filtered HTML element's |
|
39 * CSS pixel space. The origin for an HTML element is the top left corner of |
|
40 * its border box. |
|
41 * |
|
42 * "filter space" |
|
43 * User space scaled to device pixels. Shares the same origin as user space. |
|
44 * This space is the same across chained SVG and CSS filters. To compute the |
|
45 * overall filter space for a chain, we first need to build each filter's |
|
46 * FilterPrimitiveDescriptions in some common space. That space is |
|
47 * filter space. |
|
48 * |
|
49 * To understand the spaces better, let's take an example filter: |
|
50 * <filter id="f">...</filter> |
|
51 * |
|
52 * And apply the filter to a div element: |
|
53 * <div style="filter: url(#f); ...">...</div> |
|
54 * |
|
55 * And let's say there are 2 device pixels for every 1 CSS pixel. |
|
56 * |
|
57 * Finally, let's define an arbitrary point in user space: |
|
58 * "user space point" = (10, 10) |
|
59 * |
|
60 * The point will be inset 10 CSS pixels from both the top and left edges of the |
|
61 * div element's border box. |
|
62 * |
|
63 * Now, let's transform the point from user space to filter space: |
|
64 * "filter space point" = "user space point" * "device pixels per CSS pixel" |
|
65 * "filter space point" = (10, 10) * 2 |
|
66 * "filter space point" = (20, 20) |
|
67 */ |
|
68 class nsSVGFilterInstance |
|
69 { |
|
70 typedef mozilla::gfx::Point3D Point3D; |
|
71 typedef mozilla::gfx::IntRect IntRect; |
|
72 typedef mozilla::gfx::SourceSurface SourceSurface; |
|
73 typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription; |
|
74 |
|
75 public: |
|
76 /** |
|
77 * @param aFilter The SVG reference filter to process. |
|
78 * @param aTargetFrame The frame of the filtered element under consideration. |
|
79 * @param aTargetBBox The SVG bbox to use for the target frame, computed by |
|
80 * the caller. The caller may decide to override the actual SVG bbox. |
|
81 */ |
|
82 nsSVGFilterInstance(const nsStyleFilter& aFilter, |
|
83 nsIFrame *aTargetFrame, |
|
84 const gfxRect& aTargetBBox, |
|
85 const gfxSize& aUserSpaceToFilterSpaceScale, |
|
86 const gfxSize& aFilterSpaceToUserSpaceScale); |
|
87 |
|
88 /** |
|
89 * Returns true if the filter instance was created successfully. |
|
90 */ |
|
91 bool IsInitialized() const { return mInitialized; } |
|
92 |
|
93 /** |
|
94 * Iterates through the <filter> element's primitive elements, creating a |
|
95 * FilterPrimitiveDescription for each one. Appends the new |
|
96 * FilterPrimitiveDescription(s) to the aPrimitiveDescrs list. Also, appends |
|
97 * new images from feImage filter primitive elements to the aInputImages list. |
|
98 */ |
|
99 nsresult BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, |
|
100 nsTArray<mozilla::RefPtr<SourceSurface>>& aInputImages); |
|
101 |
|
102 /** |
|
103 * Returns the user specified "filter region", in the filtered element's user |
|
104 * space, after it has been adjusted out (if necessary) so that its edges |
|
105 * coincide with pixel boundaries of the offscreen surface into which the |
|
106 * filtered output would/will be painted. |
|
107 */ |
|
108 gfxRect GetFilterRegion() const { return mUserSpaceBounds; } |
|
109 |
|
110 /** |
|
111 * Returns the size of the user specified "filter region", in filter space. |
|
112 */ |
|
113 nsIntRect GetFilterSpaceBounds() const { return mFilterSpaceBounds; } |
|
114 |
|
115 float GetPrimitiveNumber(uint8_t aCtxType, const nsSVGNumber2 *aNumber) const |
|
116 { |
|
117 return GetPrimitiveNumber(aCtxType, aNumber->GetAnimValue()); |
|
118 } |
|
119 float GetPrimitiveNumber(uint8_t aCtxType, const nsSVGNumberPair *aNumberPair, |
|
120 nsSVGNumberPair::PairIndex aIndex) const |
|
121 { |
|
122 return GetPrimitiveNumber(aCtxType, aNumberPair->GetAnimValue(aIndex)); |
|
123 } |
|
124 |
|
125 /** |
|
126 * Converts a userSpaceOnUse/objectBoundingBoxUnits unitless point |
|
127 * into filter space, depending on the value of mPrimitiveUnits. (For |
|
128 * objectBoundingBoxUnits, the bounding box offset is applied to the point.) |
|
129 */ |
|
130 Point3D ConvertLocation(const Point3D& aPoint) const; |
|
131 |
|
132 /** |
|
133 * Transform a rect between user space and filter space. |
|
134 */ |
|
135 gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const; |
|
136 |
|
137 private: |
|
138 /** |
|
139 * Finds the filter frame associated with this SVG filter. |
|
140 */ |
|
141 nsSVGFilterFrame* GetFilterFrame(); |
|
142 |
|
143 /** |
|
144 * Computes the filter primitive subregion for the given primitive. |
|
145 */ |
|
146 IntRect ComputeFilterPrimitiveSubregion(nsSVGFE* aFilterElement, |
|
147 const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, |
|
148 const nsTArray<int32_t>& aInputIndices); |
|
149 |
|
150 /** |
|
151 * Takes the input indices of a filter primitive and returns for each input |
|
152 * whether the input's output is tainted. |
|
153 */ |
|
154 void GetInputsAreTainted(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, |
|
155 const nsTArray<int32_t>& aInputIndices, |
|
156 nsTArray<bool>& aOutInputsAreTainted); |
|
157 |
|
158 /** |
|
159 * Scales a numeric filter primitive length in the X, Y or "XY" directions |
|
160 * into a length in filter space (no offset is applied). |
|
161 */ |
|
162 float GetPrimitiveNumber(uint8_t aCtxType, float aValue) const; |
|
163 |
|
164 /** |
|
165 * Transform a rect between user space and filter space. |
|
166 */ |
|
167 gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const; |
|
168 |
|
169 /** |
|
170 * Returns the transform from frame space to the coordinate space that |
|
171 * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the |
|
172 * top-left corner of its border box, aka the top left corner of its mRect. |
|
173 */ |
|
174 gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const; |
|
175 |
|
176 /** |
|
177 * Finds the index in aPrimitiveDescrs of each input to aPrimitiveElement. |
|
178 * For example, if aPrimitiveElement is: |
|
179 * <feGaussianBlur in="another-primitive" .../> |
|
180 * Then, the resulting aSourceIndices will contain the index of the |
|
181 * FilterPrimitiveDescription representing "another-primitive". |
|
182 */ |
|
183 nsresult GetSourceIndices(nsSVGFE* aPrimitiveElement, |
|
184 const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, |
|
185 const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable, |
|
186 nsTArray<int32_t>& aSourceIndices); |
|
187 |
|
188 /** |
|
189 * Compute the filter region in user space, filter space, and filter |
|
190 * space. |
|
191 */ |
|
192 nsresult ComputeBounds(); |
|
193 |
|
194 /** |
|
195 * The SVG reference filter originally from the style system. |
|
196 */ |
|
197 const nsStyleFilter mFilter; |
|
198 |
|
199 /** |
|
200 * The frame for the element that is currently being filtered. |
|
201 */ |
|
202 nsIFrame* mTargetFrame; |
|
203 |
|
204 /** |
|
205 * The filter element referenced by mTargetFrame's element. |
|
206 */ |
|
207 const mozilla::dom::SVGFilterElement* mFilterElement; |
|
208 |
|
209 /** |
|
210 * The frame for the SVG filter element. |
|
211 */ |
|
212 nsSVGFilterFrame* mFilterFrame; |
|
213 |
|
214 /** |
|
215 * The SVG bbox of the element that is being filtered, in user space. |
|
216 */ |
|
217 gfxRect mTargetBBox; |
|
218 |
|
219 /** |
|
220 * The "filter region" in various spaces. |
|
221 */ |
|
222 gfxRect mUserSpaceBounds; |
|
223 nsIntRect mFilterSpaceBounds; |
|
224 |
|
225 /** |
|
226 * The scale factors between user space and filter space. |
|
227 */ |
|
228 gfxSize mUserSpaceToFilterSpaceScale; |
|
229 gfxSize mFilterSpaceToUserSpaceScale; |
|
230 |
|
231 /** |
|
232 * The 'primitiveUnits' attribute value (objectBoundingBox or userSpaceOnUse). |
|
233 */ |
|
234 uint16_t mPrimitiveUnits; |
|
235 |
|
236 /** |
|
237 * The index of the FilterPrimitiveDescription that this SVG filter should use |
|
238 * as its SourceGraphic, or the SourceGraphic keyword index if this is the |
|
239 * first filter in a chain. |
|
240 */ |
|
241 int32_t mSourceGraphicIndex; |
|
242 |
|
243 bool mInitialized; |
|
244 }; |
|
245 |
|
246 #endif |