1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef LAYOUT_SVG_FILTERINSTANCE_H_
8 #define LAYOUT_SVG_FILTERINSTANCE_H_
10 #include "gfxMatrix.h"
14 #include "FilterDescription.h"
15 #include "nsHashKeys.h"
20 #include "mozilla/gfx/2D.h"
21 #include "mozilla/webrender/WebRenderTypes.h"
22 #include "mozilla/ServoStyleConsts.h"
23 #include "mozilla/SVGIntegrationUtils.h"
28 struct WrFiltersHolder
;
33 class UserSpaceMetrics
;
37 struct imgDrawingParams
;
41 * This class performs all filter processing.
43 * We build a graph of the filter image data flow, essentially
44 * converting the filter graph to SSA. This lets us easily propagate
45 * analysis data (such as bounding-boxes) over the filter primitive graph.
47 * Definition of "filter space": filter space is a coordinate system that is
48 * aligned with the user space of the filtered element, with its origin located
49 * at the top left of the filter region, and with one unit equal in size to one
50 * pixel of the offscreen surface into which the filter output would/will be
53 * The definition of "filter region" can be found here:
54 * http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion
56 class FilterInstance
{
57 using IntRect
= gfx::IntRect
;
58 using SourceSurface
= gfx::SourceSurface
;
59 using DrawTarget
= gfx::DrawTarget
;
60 using FilterPrimitiveDescription
= gfx::FilterPrimitiveDescription
;
61 using FilterDescription
= gfx::FilterDescription
;
62 using UserSpaceMetrics
= dom::UserSpaceMetrics
;
63 using imgDrawingParams
= image::imgDrawingParams
;
64 using SVGFilterPaintCallback
= SVGIntegrationUtils::SVGFilterPaintCallback
;
68 * Create a FilterDescription for the supplied filter. All coordinates in
69 * the description are in filter space.
70 * @param aFilterInputIsTainted Describes whether the SourceImage /
71 * SourceAlpha input is tainted. This affects whether feDisplacementMap
72 * will respect the filter input as its map input, and it affects the
73 * IsTainted() state on the filter primitives in the FilterDescription.
74 * "Tainted" is a term from the filters spec and means security-sensitive
75 * content, i.e. pixels that JS should not be able to read in any way.
76 * @param aOutAdditionalImages Will contain additional images needed to
77 * render the filter (from feImage primitives).
78 * @return A FilterDescription describing the filter.
80 static FilterDescription
GetFilterDescription(
81 nsIContent
* aFilteredElement
, Span
<const StyleFilter
> aFilterChain
,
82 bool aFilterInputIsTainted
, const UserSpaceMetrics
& aMetrics
,
84 nsTArray
<RefPtr
<SourceSurface
>>& aOutAdditionalImages
);
87 * Paint the given filtered frame.
88 * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
89 * frame space (i.e. relative to its origin, the top-left corner of its
92 static void PaintFilteredFrame(
93 nsIFrame
* aFilteredFrame
, Span
<const StyleFilter
> aFilterChain
,
94 gfxContext
* aCtx
, const SVGFilterPaintCallback
& aPaintCallback
,
95 const nsRegion
* aDirtyArea
, imgDrawingParams
& aImgParams
,
96 float aOpacity
= 1.0f
, const gfxRect
* aOverrideBBox
= nullptr);
99 * Returns the post-filter area that could be dirtied when the given
100 * pre-filter area of aFilteredFrame changes.
101 * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that
102 * has changed, relative to aFilteredFrame, in app units.
104 static nsRegion
GetPostFilterDirtyArea(nsIFrame
* aFilteredFrame
,
105 const nsRegion
& aPreFilterDirtyRegion
);
108 * Returns the pre-filter area that is needed from aFilteredFrame when the
109 * given post-filter area needs to be repainted.
110 * @param aPostFilterDirtyRegion The post-filter area that is dirty, relative
111 * to aFilteredFrame, in app units.
113 static nsRegion
GetPreFilterNeededArea(
114 nsIFrame
* aFilteredFrame
, const nsRegion
& aPostFilterDirtyRegion
);
117 * Returns the post-filter ink overflow rect (paint bounds) of
119 * @param aOverrideBBox A user space rect, in user units, that should be used
120 * as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null.
121 * @param aPreFilterBounds The pre-filter ink overflow rect of
122 * aFilteredFrame, if non-null.
124 static Maybe
<nsRect
> GetPostFilterBounds(
125 nsIFrame
* aFilteredFrame
, const gfxRect
* aOverrideBBox
= nullptr,
126 const nsRect
* aPreFilterBounds
= nullptr);
129 * Try to build WebRender filters for a frame if the filters applied to it are
130 * supported. aInitialized is set to true if the filter has been initialized
131 * and false otherwise (e.g. a bad url). If aInitialized is false the filter
132 * the filter contents should not be drawn.
134 static bool BuildWebRenderFilters(
135 nsIFrame
* aFilteredFrame
,
136 mozilla::Span
<const mozilla::StyleFilter
> aFilters
,
137 WrFiltersHolder
& aWrFilters
, bool& aInitialized
);
141 * @param aTargetFrame The frame of the filtered element under consideration,
143 * @param aTargetContent The filtered element itself.
144 * @param aMetrics The metrics to resolve SVG lengths against.
145 * @param aFilterChain The list of filters to apply.
146 * @param aFilterInputIsTainted Describes whether the SourceImage /
147 * SourceAlpha input is tainted. This affects whether feDisplacementMap
148 * will respect the filter input as its map input.
149 * @param aPaintCallback [optional] The callback that Render() should use to
150 * paint. Only required if you will call Render().
151 * @param aPaintTransform The transform to apply to convert to
152 * aTargetFrame's SVG user space. Only used when painting.
153 * @param aPostFilterDirtyRegion [optional] The post-filter area
154 * that has to be repainted, in app units. Only required if you will
155 * call ComputeSourceNeededRect() or Render().
156 * @param aPreFilterDirtyRegion [optional] The pre-filter area of
157 * the filtered element that changed, in app units. Only required if you
158 * will call ComputePostFilterDirtyRegion().
159 * @param aPreFilterInkOverflowRectOverride [optional] Use a different
160 * ink overflow rect for the target element.
161 * @param aOverrideBBox [optional] Use a different SVG bbox for the target
162 * element. Must be non-null if aTargetFrame is null.
165 nsIFrame
* aTargetFrame
, nsIContent
* aTargetContent
,
166 const UserSpaceMetrics
& aMetrics
, Span
<const StyleFilter
> aFilterChain
,
167 bool aFilterInputIsTainted
,
168 const SVGIntegrationUtils::SVGFilterPaintCallback
& aPaintCallback
,
169 const gfxMatrix
& aPaintTransform
,
170 const nsRegion
* aPostFilterDirtyRegion
= nullptr,
171 const nsRegion
* aPreFilterDirtyRegion
= nullptr,
172 const nsRect
* aPreFilterInkOverflowRectOverride
= nullptr,
173 const gfxRect
* aOverrideBBox
= nullptr);
175 static bool BuildWebRenderFiltersImpl(
176 nsIFrame
* aFilteredFrame
,
177 mozilla::Span
<const mozilla::StyleFilter
> aFilters
,
178 WrFiltersHolder
& aWrFilters
, bool& aInitialized
);
181 * Returns true if the filter instance was created successfully.
183 bool IsInitialized() const { return mInitialized
; }
186 * Draws the filter output into aDrawTarget. The area that
187 * needs to be painted must have been specified before calling this method
188 * by passing it as the aPostFilterDirtyRegion argument to the
189 * FilterInstance constructor.
191 void Render(gfxContext
* aCtx
, imgDrawingParams
& aImgParams
,
192 float aOpacity
= 1.0f
);
194 const FilterDescription
& ExtractDescriptionAndAdditionalImages(
195 nsTArray
<RefPtr
<SourceSurface
>>& aOutAdditionalImages
) {
196 aOutAdditionalImages
= std::move(mInputImages
);
197 return mFilterDescription
;
201 * Sets the aPostFilterDirtyRegion outparam to the post-filter area in frame
202 * space that would be dirtied by mTargetFrame when a given
203 * pre-filter area of mTargetFrame is dirtied. The pre-filter area must have
204 * been specified before calling this method by passing it as the
205 * aPreFilterDirtyRegion argument to the FilterInstance constructor.
207 nsRegion
ComputePostFilterDirtyRegion();
210 * Sets the aPostFilterExtents outparam to the post-filter bounds in frame
211 * space for the whole filter output. This is not necessarily equivalent to
212 * the area that would be dirtied in the result when the entire pre-filter
213 * area is dirtied, because some filter primitives can generate output
216 nsRect
ComputePostFilterExtents();
219 * Sets the aDirty outparam to the pre-filter bounds in frame space of the
220 * area of mTargetFrame that is needed in order to paint the filtered output
221 * for a given post-filter dirtied area. The post-filter area must have been
222 * specified before calling this method by passing it as the
223 * aPostFilterDirtyRegion argument to the FilterInstance constructor.
225 nsRect
ComputeSourceNeededRect();
228 // Specifies which parts of the source need to be rendered.
229 // Set by ComputeNeededBoxes().
230 nsIntRect mNeededBounds
;
232 // The surface that contains the input rendering.
233 // Set by BuildSourceImage / BuildSourcePaint.
234 RefPtr
<SourceSurface
> mSourceSurface
;
236 // The position and size of mSourceSurface in filter space.
237 // Set by BuildSourceImage / BuildSourcePaint.
238 IntRect mSurfaceRect
;
242 * Creates a SourceSurface for either the FillPaint or StrokePaint graph
245 void BuildSourcePaint(SourceInfo
* aSource
, imgDrawingParams
& aImgParams
);
248 * Creates a SourceSurface for either the FillPaint and StrokePaint graph
249 * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and
250 * mStrokePaint.mSourceSurface respectively.
252 void BuildSourcePaints(imgDrawingParams
& aImgParams
);
255 * Creates the SourceSurface for the SourceGraphic graph node, paints its
256 * contents, and assigns it to mSourceGraphic.mSourceSurface.
258 void BuildSourceImage(DrawTarget
* aDest
, imgDrawingParams
& aImgParams
,
259 mozilla::gfx::FilterNode
* aFilter
,
260 mozilla::gfx::FilterNode
* aSource
,
261 const mozilla::gfx::Rect
& aSourceRect
);
264 * Build the list of FilterPrimitiveDescriptions that describes the filter's
265 * filter primitives and their connections. This populates
266 * mPrimitiveDescriptions and mInputImages. aFilterInputIsTainted describes
267 * whether the SourceGraphic is tainted.
269 nsresult
BuildPrimitives(Span
<const StyleFilter
> aFilterChain
,
270 nsIFrame
* aTargetFrame
, bool aFilterInputIsTainted
);
273 * Add to the list of FilterPrimitiveDescriptions for a particular SVG
274 * reference filter or CSS filter. This populates mPrimitiveDescriptions and
275 * mInputImages. aInputIsTainted describes whether the input to aFilter is
278 nsresult
BuildPrimitivesForFilter(
279 const StyleFilter
& aFilter
, nsIFrame
* aTargetFrame
, bool aInputIsTainted
,
280 nsTArray
<FilterPrimitiveDescription
>& aPrimitiveDescriptions
);
283 * Computes the filter space bounds of the areas that we actually *need* from
284 * the filter sources, based on the value of mPostFilterDirtyRegion.
285 * This sets mNeededBounds on the corresponding SourceInfo structs.
287 void ComputeNeededBoxes();
290 * Returns the output bounds of the final FilterPrimitiveDescription.
292 nsIntRect
OutputFilterSpaceBounds() const;
295 * Compute the scale factors between user space and filter space.
297 bool ComputeUserSpaceToFilterSpaceScale();
300 * Transform a rect between user space and filter space.
302 gfxRect
UserSpaceToFilterSpace(const gfxRect
& aUserSpace
) const;
303 gfxRect
FilterSpaceToUserSpace(const gfxRect
& aFilterSpaceRect
) const;
306 * Converts an nsRect or an nsRegion that is relative to a filtered frame's
307 * origin (i.e. the top-left corner of its border box) into filter space,
309 * Returns the entire filter region if aRect / aRegion is null, or if the
310 * result is too large to be stored in an nsIntRect.
312 nsIntRect
FrameSpaceToFilterSpace(const nsRect
* aRect
) const;
313 nsIntRegion
FrameSpaceToFilterSpace(const nsRegion
* aRegion
) const;
316 * Converts an nsIntRect or an nsIntRegion from filter space into the space
317 * that is relative to a filtered frame's origin (i.e. the top-left corner
318 * of its border box) in app units, rounding out.
320 nsRect
FilterSpaceToFrameSpace(const nsIntRect
& aRect
) const;
321 nsRegion
FilterSpaceToFrameSpace(const nsIntRegion
& aRegion
) const;
324 * Returns the transform from frame space to the coordinate space that
325 * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the
326 * top-left corner of its border box, aka the top left corner of its mRect.
328 gfxMatrix
GetUserSpaceToFrameSpaceInCSSPxTransform() const;
330 bool ComputeTargetBBoxInFilterSpace();
333 * The frame for the element that is currently being filtered.
335 nsIFrame
* mTargetFrame
;
338 * The filtered element.
340 nsIContent
* mTargetContent
;
343 * The user space metrics of the filtered frame.
345 const UserSpaceMetrics
& mMetrics
;
347 const SVGFilterPaintCallback
& mPaintCallback
;
350 * The SVG bbox of the element that is being filtered, in user space.
355 * The SVG bbox of the element that is being filtered, in filter space.
357 nsIntRect mTargetBBoxInFilterSpace
;
360 * Transform rects between filter space and frame space in CSS pixels.
362 gfxMatrix mFilterSpaceToFrameSpaceInCSSPxTransform
;
363 gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform
;
366 * The scale factors between user space and filter space.
368 gfx::MatrixScalesDouble mUserSpaceToFilterSpaceScale
;
369 gfx::MatrixScalesDouble mFilterSpaceToUserSpaceScale
;
372 * Pre-filter paint bounds of the element that is being filtered, in filter
375 nsIntRect mTargetBounds
;
378 * The dirty area that needs to be repainted, in filter space.
380 nsIntRegion mPostFilterDirtyRegion
;
383 * The pre-filter area of the filtered element that changed, in filter space.
385 nsIntRegion mPreFilterDirtyRegion
;
387 SourceInfo mSourceGraphic
;
388 SourceInfo mFillPaint
;
389 SourceInfo mStrokePaint
;
392 * The transform to the SVG user space of mTargetFrame.
394 gfxMatrix mPaintTransform
;
396 nsTArray
<RefPtr
<SourceSurface
>> mInputImages
;
397 FilterDescription mFilterDescription
;
401 } // namespace mozilla
403 #endif // LAYOUT_SVG_FILTERINSTANCE_H_