|
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_FILTERINSTANCE_H__ |
|
7 #define __NS_FILTERINSTANCE_H__ |
|
8 |
|
9 #include "gfxMatrix.h" |
|
10 #include "gfxPoint.h" |
|
11 #include "gfxRect.h" |
|
12 #include "nsCOMPtr.h" |
|
13 #include "nsHashKeys.h" |
|
14 #include "nsPoint.h" |
|
15 #include "nsRect.h" |
|
16 #include "nsSize.h" |
|
17 #include "nsSVGFilters.h" |
|
18 #include "nsSVGNumber2.h" |
|
19 #include "nsSVGNumberPair.h" |
|
20 #include "nsTArray.h" |
|
21 #include "nsIFrame.h" |
|
22 #include "mozilla/gfx/2D.h" |
|
23 |
|
24 class gfxASurface; |
|
25 class nsIFrame; |
|
26 class nsSVGFilterPaintCallback; |
|
27 |
|
28 /** |
|
29 * This class performs all filter processing. |
|
30 * |
|
31 * We build a graph of the filter image data flow, essentially |
|
32 * converting the filter graph to SSA. This lets us easily propagate |
|
33 * analysis data (such as bounding-boxes) over the filter primitive graph. |
|
34 * |
|
35 * Definition of "filter space": filter space is a coordinate system that is |
|
36 * aligned with the user space of the filtered element, with its origin located |
|
37 * at the top left of the filter region, and with one unit equal in size to one |
|
38 * pixel of the offscreen surface into which the filter output would/will be |
|
39 * painted. |
|
40 * |
|
41 * The definition of "filter region" can be found here: |
|
42 * http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion |
|
43 */ |
|
44 class nsFilterInstance |
|
45 { |
|
46 typedef mozilla::gfx::IntRect IntRect; |
|
47 typedef mozilla::gfx::SourceSurface SourceSurface; |
|
48 typedef mozilla::gfx::DrawTarget DrawTarget; |
|
49 typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription; |
|
50 |
|
51 public: |
|
52 /** |
|
53 * Paint the given filtered frame. |
|
54 * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's |
|
55 * frame space (i.e. relative to its origin, the top-left corner of its |
|
56 * border box). |
|
57 */ |
|
58 static nsresult PaintFilteredFrame(nsRenderingContext *aContext, |
|
59 nsIFrame *aFilteredFrame, |
|
60 nsSVGFilterPaintCallback *aPaintCallback, |
|
61 const nsRegion* aDirtyArea, |
|
62 nsIFrame* aTransformRoot = nullptr); |
|
63 |
|
64 /** |
|
65 * Returns the post-filter area that could be dirtied when the given |
|
66 * pre-filter area of aFilteredFrame changes. |
|
67 * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that has |
|
68 * changed, relative to aFilteredFrame, in app units. |
|
69 */ |
|
70 static nsRegion GetPostFilterDirtyArea(nsIFrame *aFilteredFrame, |
|
71 const nsRegion& aPreFilterDirtyRegion); |
|
72 |
|
73 /** |
|
74 * Returns the pre-filter area that is needed from aFilteredFrame when the |
|
75 * given post-filter area needs to be repainted. |
|
76 * @param aPostFilterDirtyRegion The post-filter area that is dirty, relative |
|
77 * to aFilteredFrame, in app units. |
|
78 */ |
|
79 static nsRegion GetPreFilterNeededArea(nsIFrame *aFilteredFrame, |
|
80 const nsRegion& aPostFilterDirtyRegion); |
|
81 |
|
82 /** |
|
83 * Returns the post-filter visual overflow rect (paint bounds) of |
|
84 * aFilteredFrame. |
|
85 * @param aOverrideBBox A user space rect, in user units, that should be used |
|
86 * as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null. |
|
87 * @param aPreFilterBounds The pre-filter visual overflow rect of |
|
88 * aFilteredFrame, if non-null. |
|
89 */ |
|
90 static nsRect GetPostFilterBounds(nsIFrame *aFilteredFrame, |
|
91 const gfxRect *aOverrideBBox = nullptr, |
|
92 const nsRect *aPreFilterBounds = nullptr); |
|
93 |
|
94 /** |
|
95 * @param aTargetFrame The frame of the filtered element under consideration. |
|
96 * @param aPaintCallback [optional] The callback that Render() should use to |
|
97 * paint. Only required if you will call Render(). |
|
98 * @param aPostFilterDirtyRegion [optional] The post-filter area |
|
99 * that has to be repainted, in app units. Only required if you will |
|
100 * call ComputeSourceNeededRect() or Render(). |
|
101 * @param aPreFilterDirtyRegion [optional] The pre-filter area of |
|
102 * the filtered element that changed, in app units. Only required if you |
|
103 * will call ComputePostFilterDirtyRegion(). |
|
104 * @param aOverridePreFilterVisualOverflowRect [optional] Use a different |
|
105 * visual overflow rect for the target element. |
|
106 * @param aOverrideBBox [optional] Use a different SVG bbox for the target |
|
107 * element. |
|
108 * @param aTransformRoot [optional] The transform root frame for painting. |
|
109 */ |
|
110 nsFilterInstance(nsIFrame *aTargetFrame, |
|
111 nsSVGFilterPaintCallback *aPaintCallback, |
|
112 const nsRegion *aPostFilterDirtyRegion = nullptr, |
|
113 const nsRegion *aPreFilterDirtyRegion = nullptr, |
|
114 const nsRect *aOverridePreFilterVisualOverflowRect = nullptr, |
|
115 const gfxRect *aOverrideBBox = nullptr, |
|
116 nsIFrame* aTransformRoot = nullptr); |
|
117 |
|
118 /** |
|
119 * Returns true if the filter instance was created successfully. |
|
120 */ |
|
121 bool IsInitialized() const { return mInitialized; } |
|
122 |
|
123 /** |
|
124 * Draws the filter output into aContext. The area that |
|
125 * needs to be painted must have been specified before calling this method |
|
126 * by passing it as the aPostFilterDirtyRegion argument to the |
|
127 * nsFilterInstance constructor. |
|
128 */ |
|
129 nsresult Render(gfxContext* aContext); |
|
130 |
|
131 /** |
|
132 * Sets the aPostFilterDirtyRegion outparam to the post-filter area in frame |
|
133 * space that would be dirtied by mTargetFrame when a given |
|
134 * pre-filter area of mTargetFrame is dirtied. The pre-filter area must have |
|
135 * been specified before calling this method by passing it as the |
|
136 * aPreFilterDirtyRegion argument to the nsFilterInstance constructor. |
|
137 */ |
|
138 nsresult ComputePostFilterDirtyRegion(nsRegion* aPostFilterDirtyRegion); |
|
139 |
|
140 /** |
|
141 * Sets the aPostFilterExtents outparam to the post-filter bounds in frame |
|
142 * space for the whole filter output. This is not necessarily equivalent to |
|
143 * the area that would be dirtied in the result when the entire pre-filter |
|
144 * area is dirtied, because some filter primitives can generate output |
|
145 * without any input. |
|
146 */ |
|
147 nsresult ComputePostFilterExtents(nsRect* aPostFilterExtents); |
|
148 |
|
149 /** |
|
150 * Sets the aDirty outparam to the pre-filter bounds in frame space of the |
|
151 * area of mTargetFrame that is needed in order to paint the filtered output |
|
152 * for a given post-filter dirtied area. The post-filter area must have been |
|
153 * specified before calling this method by passing it as the aPostFilterDirtyRegion |
|
154 * argument to the nsFilterInstance constructor. |
|
155 */ |
|
156 nsresult ComputeSourceNeededRect(nsRect* aDirty); |
|
157 |
|
158 |
|
159 /** |
|
160 * Returns the transform from filter space to outer-<svg> device space. |
|
161 */ |
|
162 gfxMatrix GetFilterSpaceToDeviceSpaceTransform() const { |
|
163 return mFilterSpaceToDeviceSpaceTransform; |
|
164 } |
|
165 |
|
166 private: |
|
167 struct SourceInfo { |
|
168 // Specifies which parts of the source need to be rendered. |
|
169 // Set by ComputeNeededBoxes(). |
|
170 nsIntRect mNeededBounds; |
|
171 |
|
172 // The surface that contains the input rendering. |
|
173 // Set by BuildSourceImage / BuildSourcePaint. |
|
174 mozilla::RefPtr<SourceSurface> mSourceSurface; |
|
175 |
|
176 // The position and size of mSourceSurface in filter space. |
|
177 // Set by BuildSourceImage / BuildSourcePaint. |
|
178 IntRect mSurfaceRect; |
|
179 }; |
|
180 |
|
181 /** |
|
182 * Creates a SourceSurface for either the FillPaint or StrokePaint graph |
|
183 * nodes |
|
184 */ |
|
185 nsresult BuildSourcePaint(SourceInfo *aPrimitive, |
|
186 gfxASurface* aTargetSurface, |
|
187 DrawTarget* aTargetDT); |
|
188 |
|
189 /** |
|
190 * Creates a SourceSurface for either the FillPaint and StrokePaint graph |
|
191 * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and |
|
192 * mStrokePaint.mSourceSurface respectively. |
|
193 */ |
|
194 nsresult BuildSourcePaints(gfxASurface* aTargetSurface, |
|
195 DrawTarget* aTargetDT); |
|
196 |
|
197 /** |
|
198 * Creates the SourceSurface for the SourceGraphic graph node, paints its |
|
199 * contents, and assigns it to mSourceGraphic.mSourceSurface. |
|
200 */ |
|
201 nsresult BuildSourceImage(gfxASurface* aTargetSurface, |
|
202 DrawTarget* aTargetDT); |
|
203 |
|
204 /** |
|
205 * Build the list of FilterPrimitiveDescriptions that describes the filter's |
|
206 * filter primitives and their connections. This populates |
|
207 * mPrimitiveDescriptions and mInputImages. |
|
208 */ |
|
209 nsresult BuildPrimitives(); |
|
210 |
|
211 /** |
|
212 * Add to the list of FilterPrimitiveDescriptions for a particular SVG |
|
213 * reference filter or CSS filter. This populates mPrimitiveDescrs and |
|
214 * mInputImages. |
|
215 */ |
|
216 nsresult BuildPrimitivesForFilter(const nsStyleFilter& aFilter); |
|
217 |
|
218 /** |
|
219 * Computes the filter space bounds of the areas that we actually *need* from |
|
220 * the filter sources, based on the value of mPostFilterDirtyRegion. |
|
221 * This sets mNeededBounds on the corresponding SourceInfo structs. |
|
222 */ |
|
223 void ComputeNeededBoxes(); |
|
224 |
|
225 /** |
|
226 * Compute the scale factors between user space and filter space. |
|
227 */ |
|
228 nsresult ComputeUserSpaceToFilterSpaceScale(); |
|
229 |
|
230 /** |
|
231 * Transform a rect between user space and filter space. |
|
232 */ |
|
233 gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const; |
|
234 gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const; |
|
235 |
|
236 /** |
|
237 * Converts an nsRect or an nsRegion that is relative to a filtered frame's |
|
238 * origin (i.e. the top-left corner of its border box) into filter space, |
|
239 * rounding out. |
|
240 * Returns the entire filter region if aRect / aRegion is null, or if the |
|
241 * result is too large to be stored in an nsIntRect. |
|
242 */ |
|
243 nsIntRect FrameSpaceToFilterSpace(const nsRect* aRect) const; |
|
244 nsIntRegion FrameSpaceToFilterSpace(const nsRegion* aRegion) const; |
|
245 |
|
246 /** |
|
247 * Converts an nsIntRect or an nsIntRegion from filter space into the space |
|
248 * that is relative to a filtered frame's origin (i.e. the top-left corner |
|
249 * of its border box) in app units, rounding out. |
|
250 */ |
|
251 nsRect FilterSpaceToFrameSpace(const nsIntRect& aRect) const; |
|
252 nsRegion FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const; |
|
253 |
|
254 /** |
|
255 * Returns the transform from frame space to the coordinate space that |
|
256 * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the |
|
257 * top-left corner of its border box, aka the top left corner of its mRect. |
|
258 */ |
|
259 gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const; |
|
260 |
|
261 /** |
|
262 * The frame for the element that is currently being filtered. |
|
263 */ |
|
264 nsIFrame* mTargetFrame; |
|
265 |
|
266 nsSVGFilterPaintCallback* mPaintCallback; |
|
267 |
|
268 /** |
|
269 * The SVG bbox of the element that is being filtered, in user space. |
|
270 */ |
|
271 gfxRect mTargetBBox; |
|
272 |
|
273 /** |
|
274 * The transform from filter space to outer-<svg> device space. |
|
275 */ |
|
276 gfxMatrix mFilterSpaceToDeviceSpaceTransform; |
|
277 |
|
278 /** |
|
279 * Transform rects between filter space and frame space in CSS pixels. |
|
280 */ |
|
281 gfxMatrix mFilterSpaceToFrameSpaceInCSSPxTransform; |
|
282 gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform; |
|
283 |
|
284 /** |
|
285 * The "filter region", in the filtered element's user space. |
|
286 */ |
|
287 gfxRect mUserSpaceBounds; |
|
288 nsIntRect mFilterSpaceBounds; |
|
289 |
|
290 /** |
|
291 * The scale factors between user space and filter space. |
|
292 */ |
|
293 gfxSize mUserSpaceToFilterSpaceScale; |
|
294 gfxSize mFilterSpaceToUserSpaceScale; |
|
295 |
|
296 /** |
|
297 * Pre-filter paint bounds of the element that is being filtered, in filter |
|
298 * space. |
|
299 */ |
|
300 nsIntRect mTargetBounds; |
|
301 |
|
302 /** |
|
303 * The dirty area that needs to be repainted, in filter space. |
|
304 */ |
|
305 nsIntRegion mPostFilterDirtyRegion; |
|
306 |
|
307 /** |
|
308 * The pre-filter area of the filtered element that changed, in filter space. |
|
309 */ |
|
310 nsIntRegion mPreFilterDirtyRegion; |
|
311 |
|
312 SourceInfo mSourceGraphic; |
|
313 SourceInfo mFillPaint; |
|
314 SourceInfo mStrokePaint; |
|
315 nsIFrame* mTransformRoot; |
|
316 nsTArray<mozilla::RefPtr<SourceSurface>> mInputImages; |
|
317 nsTArray<FilterPrimitiveDescription> mPrimitiveDescriptions; |
|
318 int32_t mAppUnitsPerCSSPx; |
|
319 bool mInitialized; |
|
320 }; |
|
321 |
|
322 #endif |