Line data Source code
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 gfxContext;
25 : class nsIFrame;
26 : class nsSVGFilterPaintCallback;
27 :
28 : namespace mozilla {
29 : namespace dom {
30 : class UserSpaceMetrics;
31 : } // namespace dom
32 : } // namespace mozilla
33 :
34 : /**
35 : * This class performs all filter processing.
36 : *
37 : * We build a graph of the filter image data flow, essentially
38 : * converting the filter graph to SSA. This lets us easily propagate
39 : * analysis data (such as bounding-boxes) over the filter primitive graph.
40 : *
41 : * Definition of "filter space": filter space is a coordinate system that is
42 : * aligned with the user space of the filtered element, with its origin located
43 : * at the top left of the filter region, and with one unit equal in size to one
44 : * pixel of the offscreen surface into which the filter output would/will be
45 : * painted.
46 : *
47 : * The definition of "filter region" can be found here:
48 : * http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion
49 : */
50 0 : class nsFilterInstance
51 : {
52 : typedef mozilla::gfx::IntRect IntRect;
53 : typedef mozilla::gfx::SourceSurface SourceSurface;
54 : typedef mozilla::gfx::DrawTarget DrawTarget;
55 : typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
56 : typedef mozilla::gfx::FilterDescription FilterDescription;
57 : typedef mozilla::dom::UserSpaceMetrics UserSpaceMetrics;
58 : typedef mozilla::image::imgDrawingParams imgDrawingParams;
59 : public:
60 : /**
61 : * Create a FilterDescription for the supplied filter. All coordinates in
62 : * the description are in filter space.
63 : * @param aFilterInputIsTainted Describes whether the SourceImage / SourceAlpha
64 : * input is tainted. This affects whether feDisplacementMap will respect
65 : * the filter input as its map input, and it affects the IsTainted() state
66 : * on the filter primitives in the FilterDescription. "Tainted" is a term
67 : * from the filters spec and means security-sensitive content, i.e. pixels
68 : * that JS should not be able to read in any way.
69 : * @param aOutAdditionalImages Will contain additional images needed to
70 : * render the filter (from feImage primitives).
71 : * @return A FilterDescription describing the filter.
72 : */
73 : static FilterDescription GetFilterDescription(nsIContent* aFilteredElement,
74 : const nsTArray<nsStyleFilter>& aFilterChain,
75 : bool aFilterInputIsTainted,
76 : const UserSpaceMetrics& aMetrics,
77 : const gfxRect& aBBox,
78 : nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages);
79 :
80 : /**
81 : * Paint the given filtered frame.
82 : * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
83 : * frame space (i.e. relative to its origin, the top-left corner of its
84 : * border box).
85 : */
86 : static void PaintFilteredFrame(nsIFrame *aFilteredFrame,
87 : DrawTarget* aDrawTarget,
88 : const gfxMatrix& aTransform,
89 : nsSVGFilterPaintCallback *aPaintCallback,
90 : const nsRegion* aDirtyArea,
91 : imgDrawingParams& aImgParams);
92 :
93 : /**
94 : * Returns the post-filter area that could be dirtied when the given
95 : * pre-filter area of aFilteredFrame changes.
96 : * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that has
97 : * changed, relative to aFilteredFrame, in app units.
98 : */
99 : static nsRegion GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
100 : const nsRegion& aPreFilterDirtyRegion);
101 :
102 : /**
103 : * Returns the pre-filter area that is needed from aFilteredFrame when the
104 : * given post-filter area needs to be repainted.
105 : * @param aPostFilterDirtyRegion The post-filter area that is dirty, relative
106 : * to aFilteredFrame, in app units.
107 : */
108 : static nsRegion GetPreFilterNeededArea(nsIFrame *aFilteredFrame,
109 : const nsRegion& aPostFilterDirtyRegion);
110 :
111 : /**
112 : * Returns the post-filter visual overflow rect (paint bounds) of
113 : * aFilteredFrame.
114 : * @param aOverrideBBox A user space rect, in user units, that should be used
115 : * as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null.
116 : * @param aPreFilterBounds The pre-filter visual overflow rect of
117 : * aFilteredFrame, if non-null.
118 : */
119 : static nsRect GetPostFilterBounds(nsIFrame *aFilteredFrame,
120 : const gfxRect *aOverrideBBox = nullptr,
121 : const nsRect *aPreFilterBounds = nullptr);
122 :
123 : private:
124 : /**
125 : * @param aTargetFrame The frame of the filtered element under consideration,
126 : * may be null.
127 : * @param aTargetContent The filtered element itself.
128 : * @param aMetrics The metrics to resolve SVG lengths against.
129 : * @param aFilterChain The list of filters to apply.
130 : * @param aFilterInputIsTainted Describes whether the SourceImage / SourceAlpha
131 : * input is tainted. This affects whether feDisplacementMap will respect
132 : * the filter input as its map input.
133 : * @param aPaintCallback [optional] The callback that Render() should use to
134 : * paint. Only required if you will call Render().
135 : * @param aPaintTransform The transform to apply to convert to
136 : * aTargetFrame's SVG user space. Only used when painting.
137 : * @param aPostFilterDirtyRegion [optional] The post-filter area
138 : * that has to be repainted, in app units. Only required if you will
139 : * call ComputeSourceNeededRect() or Render().
140 : * @param aPreFilterDirtyRegion [optional] The pre-filter area of
141 : * the filtered element that changed, in app units. Only required if you
142 : * will call ComputePostFilterDirtyRegion().
143 : * @param aOverridePreFilterVisualOverflowRect [optional] Use a different
144 : * visual overflow rect for the target element.
145 : * @param aOverrideBBox [optional] Use a different SVG bbox for the target
146 : * element. Must be non-null if aTargetFrame is null.
147 : */
148 : nsFilterInstance(nsIFrame *aTargetFrame,
149 : nsIContent* aTargetContent,
150 : const UserSpaceMetrics& aMetrics,
151 : const nsTArray<nsStyleFilter>& aFilterChain,
152 : bool aFilterInputIsTainted,
153 : nsSVGFilterPaintCallback *aPaintCallback,
154 : const gfxMatrix& aPaintTransform,
155 : const nsRegion *aPostFilterDirtyRegion = nullptr,
156 : const nsRegion *aPreFilterDirtyRegion = nullptr,
157 : const nsRect *aOverridePreFilterVisualOverflowRect = nullptr,
158 : const gfxRect *aOverrideBBox = nullptr);
159 :
160 : /**
161 : * Returns true if the filter instance was created successfully.
162 : */
163 0 : bool IsInitialized() const { return mInitialized; }
164 :
165 : /**
166 : * Draws the filter output into aDrawTarget. The area that
167 : * needs to be painted must have been specified before calling this method
168 : * by passing it as the aPostFilterDirtyRegion argument to the
169 : * nsFilterInstance constructor.
170 : */
171 : void Render(DrawTarget* aDrawTarget, imgDrawingParams& aImgParams);
172 :
173 0 : const FilterDescription& ExtractDescriptionAndAdditionalImages(nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages)
174 : {
175 0 : mInputImages.SwapElements(aOutAdditionalImages);
176 0 : return mFilterDescription;
177 : }
178 :
179 : /**
180 : * Sets the aPostFilterDirtyRegion outparam to the post-filter area in frame
181 : * space that would be dirtied by mTargetFrame when a given
182 : * pre-filter area of mTargetFrame is dirtied. The pre-filter area must have
183 : * been specified before calling this method by passing it as the
184 : * aPreFilterDirtyRegion argument to the nsFilterInstance constructor.
185 : */
186 : nsRegion ComputePostFilterDirtyRegion();
187 :
188 : /**
189 : * Sets the aPostFilterExtents outparam to the post-filter bounds in frame
190 : * space for the whole filter output. This is not necessarily equivalent to
191 : * the area that would be dirtied in the result when the entire pre-filter
192 : * area is dirtied, because some filter primitives can generate output
193 : * without any input.
194 : */
195 : nsRect ComputePostFilterExtents();
196 :
197 : /**
198 : * Sets the aDirty outparam to the pre-filter bounds in frame space of the
199 : * area of mTargetFrame that is needed in order to paint the filtered output
200 : * for a given post-filter dirtied area. The post-filter area must have been
201 : * specified before calling this method by passing it as the aPostFilterDirtyRegion
202 : * argument to the nsFilterInstance constructor.
203 : */
204 : nsRect ComputeSourceNeededRect();
205 :
206 0 : struct SourceInfo {
207 : // Specifies which parts of the source need to be rendered.
208 : // Set by ComputeNeededBoxes().
209 : nsIntRect mNeededBounds;
210 :
211 : // The surface that contains the input rendering.
212 : // Set by BuildSourceImage / BuildSourcePaint.
213 : RefPtr<SourceSurface> mSourceSurface;
214 :
215 : // The position and size of mSourceSurface in filter space.
216 : // Set by BuildSourceImage / BuildSourcePaint.
217 : IntRect mSurfaceRect;
218 : };
219 :
220 : /**
221 : * Creates a SourceSurface for either the FillPaint or StrokePaint graph
222 : * nodes
223 : */
224 : void BuildSourcePaint(SourceInfo *aPrimitive, imgDrawingParams& aImgParams);
225 :
226 : /**
227 : * Creates a SourceSurface for either the FillPaint and StrokePaint graph
228 : * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and
229 : * mStrokePaint.mSourceSurface respectively.
230 : */
231 : void BuildSourcePaints(imgDrawingParams& aImgParams);
232 :
233 : /**
234 : * Creates the SourceSurface for the SourceGraphic graph node, paints its
235 : * contents, and assigns it to mSourceGraphic.mSourceSurface.
236 : */
237 : void BuildSourceImage(imgDrawingParams& aImgParams);
238 :
239 : /**
240 : * Build the list of FilterPrimitiveDescriptions that describes the filter's
241 : * filter primitives and their connections. This populates
242 : * mPrimitiveDescriptions and mInputImages. aFilterInputIsTainted describes
243 : * whether the SourceGraphic is tainted.
244 : */
245 : nsresult BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain,
246 : nsIFrame* aTargetFrame,
247 : bool aFilterInputIsTainted);
248 :
249 : /**
250 : * Add to the list of FilterPrimitiveDescriptions for a particular SVG
251 : * reference filter or CSS filter. This populates mPrimitiveDescriptions and
252 : * mInputImages. aInputIsTainted describes whether the input to aFilter is
253 : * tainted.
254 : */
255 : nsresult BuildPrimitivesForFilter(const nsStyleFilter& aFilter,
256 : nsIFrame* aTargetFrame,
257 : bool aInputIsTainted);
258 :
259 : /**
260 : * Computes the filter space bounds of the areas that we actually *need* from
261 : * the filter sources, based on the value of mPostFilterDirtyRegion.
262 : * This sets mNeededBounds on the corresponding SourceInfo structs.
263 : */
264 : void ComputeNeededBoxes();
265 :
266 : /**
267 : * Returns the output bounds of the final FilterPrimitiveDescription.
268 : */
269 : nsIntRect OutputFilterSpaceBounds() const;
270 :
271 : /**
272 : * Compute the scale factors between user space and filter space.
273 : */
274 : bool ComputeUserSpaceToFilterSpaceScale();
275 :
276 : /**
277 : * Transform a rect between user space and filter space.
278 : */
279 : gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const;
280 : gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const;
281 :
282 : /**
283 : * Converts an nsRect or an nsRegion that is relative to a filtered frame's
284 : * origin (i.e. the top-left corner of its border box) into filter space,
285 : * rounding out.
286 : * Returns the entire filter region if aRect / aRegion is null, or if the
287 : * result is too large to be stored in an nsIntRect.
288 : */
289 : nsIntRect FrameSpaceToFilterSpace(const nsRect* aRect) const;
290 : nsIntRegion FrameSpaceToFilterSpace(const nsRegion* aRegion) const;
291 :
292 : /**
293 : * Converts an nsIntRect or an nsIntRegion from filter space into the space
294 : * that is relative to a filtered frame's origin (i.e. the top-left corner
295 : * of its border box) in app units, rounding out.
296 : */
297 : nsRect FilterSpaceToFrameSpace(const nsIntRect& aRect) const;
298 : nsRegion FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const;
299 :
300 : /**
301 : * Returns the transform from frame space to the coordinate space that
302 : * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the
303 : * top-left corner of its border box, aka the top left corner of its mRect.
304 : */
305 : gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const;
306 :
307 : bool ComputeTargetBBoxInFilterSpace();
308 :
309 : /**
310 : * The frame for the element that is currently being filtered.
311 : */
312 : nsIFrame* mTargetFrame;
313 :
314 : /**
315 : * The filtered element.
316 : */
317 : nsIContent* mTargetContent;
318 :
319 : /**
320 : * The user space metrics of the filtered frame.
321 : */
322 : const UserSpaceMetrics& mMetrics;
323 :
324 : nsSVGFilterPaintCallback* mPaintCallback;
325 :
326 : /**
327 : * The SVG bbox of the element that is being filtered, in user space.
328 : */
329 : gfxRect mTargetBBox;
330 :
331 : /**
332 : * The SVG bbox of the element that is being filtered, in filter space.
333 : */
334 : nsIntRect mTargetBBoxInFilterSpace;
335 :
336 : /**
337 : * Transform rects between filter space and frame space in CSS pixels.
338 : */
339 : gfxMatrix mFilterSpaceToFrameSpaceInCSSPxTransform;
340 : gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform;
341 :
342 : /**
343 : * The scale factors between user space and filter space.
344 : */
345 : gfxSize mUserSpaceToFilterSpaceScale;
346 : gfxSize mFilterSpaceToUserSpaceScale;
347 :
348 : /**
349 : * Pre-filter paint bounds of the element that is being filtered, in filter
350 : * space.
351 : */
352 : nsIntRect mTargetBounds;
353 :
354 : /**
355 : * The dirty area that needs to be repainted, in filter space.
356 : */
357 : nsIntRegion mPostFilterDirtyRegion;
358 :
359 : /**
360 : * The pre-filter area of the filtered element that changed, in filter space.
361 : */
362 : nsIntRegion mPreFilterDirtyRegion;
363 :
364 : SourceInfo mSourceGraphic;
365 : SourceInfo mFillPaint;
366 : SourceInfo mStrokePaint;
367 :
368 : /**
369 : * The transform to the SVG user space of mTargetFrame.
370 : */
371 : gfxMatrix mPaintTransform;
372 :
373 : nsTArray<RefPtr<SourceSurface>> mInputImages;
374 : nsTArray<FilterPrimitiveDescription> mPrimitiveDescriptions;
375 : FilterDescription mFilterDescription;
376 : bool mInitialized;
377 : };
378 :
379 : #endif
|