no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / layout / svg / FilterInstance.h
blob6b23bace2e1ea4d86a748ac1304f2353f9f7449f
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"
11 #include "gfxPoint.h"
12 #include "gfxRect.h"
13 #include "nsCOMPtr.h"
14 #include "FilterDescription.h"
15 #include "nsHashKeys.h"
16 #include "nsPoint.h"
17 #include "nsRect.h"
18 #include "nsSize.h"
19 #include "nsTArray.h"
20 #include "mozilla/gfx/2D.h"
21 #include "mozilla/webrender/WebRenderTypes.h"
22 #include "mozilla/ServoStyleConsts.h"
23 #include "mozilla/SVGIntegrationUtils.h"
25 class gfxContext;
26 class nsIContent;
27 class nsIFrame;
28 struct WrFiltersHolder;
30 namespace mozilla {
31 class SVGFilterFrame;
33 namespace dom {
34 class UserSpaceMetrics;
35 } // namespace dom
37 namespace image {
38 struct imgDrawingParams;
41 /**
42 * This class performs all filter processing.
44 * We build a graph of the filter image data flow, essentially
45 * converting the filter graph to SSA. This lets us easily propagate
46 * analysis data (such as bounding-boxes) over the filter primitive graph.
48 * Definition of "filter space": filter space is a coordinate system that is
49 * aligned with the user space of the filtered element, with its origin located
50 * at the top left of the filter region, and with one unit equal in size to one
51 * pixel of the offscreen surface into which the filter output would/will be
52 * painted.
54 * The definition of "filter region" can be found here:
55 * http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion
57 class FilterInstance {
58 using IntRect = gfx::IntRect;
59 using SourceSurface = gfx::SourceSurface;
60 using DrawTarget = gfx::DrawTarget;
61 using FilterPrimitiveDescription = gfx::FilterPrimitiveDescription;
62 using FilterDescription = gfx::FilterDescription;
63 using UserSpaceMetrics = dom::UserSpaceMetrics;
64 using imgDrawingParams = image::imgDrawingParams;
65 using SVGFilterPaintCallback = SVGIntegrationUtils::SVGFilterPaintCallback;
67 public:
68 /**
69 * Create a FilterDescription for the supplied filter. All coordinates in
70 * the description are in filter space.
71 * @param aFilterInputIsTainted Describes whether the SourceImage /
72 * SourceAlpha input is tainted. This affects whether feDisplacementMap
73 * will respect the filter input as its map input, and it affects the
74 * IsTainted() state on the filter primitives in the FilterDescription.
75 * "Tainted" is a term from the filters spec and means security-sensitive
76 * content, i.e. pixels that JS should not be able to read in any way.
77 * @param aOutAdditionalImages Will contain additional images needed to
78 * render the filter (from feImage primitives).
79 * @return A FilterDescription describing the filter.
81 static FilterDescription GetFilterDescription(
82 nsIContent* aFilteredElement, Span<const StyleFilter> aFilterChain,
83 nsISupports* aFiltersObserverList, bool aFilterInputIsTainted,
84 const UserSpaceMetrics& aMetrics, const gfxRect& aBBox,
85 nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages);
87 /**
88 * Paint the given filtered frame.
89 * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
90 * frame space (i.e. relative to its origin, the top-left corner of its
91 * border box).
93 static void PaintFilteredFrame(
94 nsIFrame* aFilteredFrame, Span<const StyleFilter> aFilterChain,
95 const nsTArray<SVGFilterFrame*>& aFilterFrames, gfxContext* aCtx,
96 const SVGFilterPaintCallback& aPaintCallback, const nsRegion* aDirtyArea,
97 imgDrawingParams& aImgParams, float aOpacity = 1.0f,
98 const gfxRect* aOverrideBBox = nullptr);
101 * Returns the post-filter area that could be dirtied when the given
102 * pre-filter area of aFilteredFrame changes.
103 * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that
104 * has changed, relative to aFilteredFrame, in app units.
106 static nsRegion GetPostFilterDirtyArea(nsIFrame* aFilteredFrame,
107 const nsRegion& aPreFilterDirtyRegion);
110 * Returns the pre-filter area that is needed from aFilteredFrame when the
111 * given post-filter area needs to be repainted.
112 * @param aPostFilterDirtyRegion The post-filter area that is dirty, relative
113 * to aFilteredFrame, in app units.
115 static nsRegion GetPreFilterNeededArea(
116 nsIFrame* aFilteredFrame, const nsTArray<SVGFilterFrame*>& aFilterFrames,
117 const nsRegion& aPostFilterDirtyRegion);
120 * Returns the post-filter ink overflow rect (paint bounds) of
121 * aFilteredFrame.
122 * @param aOverrideBBox A user space rect, in user units, that should be used
123 * as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null.
124 * @param aPreFilterBounds The pre-filter ink overflow rect of
125 * aFilteredFrame, if non-null.
127 static Maybe<nsRect> GetPostFilterBounds(
128 nsIFrame* aFilteredFrame, const nsTArray<SVGFilterFrame*>& aFilterFrames,
129 const gfxRect* aOverrideBBox = nullptr,
130 const nsRect* aPreFilterBounds = nullptr);
133 * Try to build WebRender filters for a frame if the filters applied to it are
134 * supported. aInitialized is set to true if the filter has been initialized
135 * and false otherwise (e.g. a bad url). If aInitialized is false the filter
136 * the filter contents should not be drawn.
138 static bool BuildWebRenderFilters(
139 nsIFrame* aFilteredFrame,
140 mozilla::Span<const mozilla::StyleFilter> aFilters,
141 StyleFilterType aStyleFilterType, WrFiltersHolder& aWrFilters,
142 bool& aInitialized);
144 private:
146 * @param aTargetFrame The frame of the filtered element under consideration,
147 * may be null.
148 * @param aTargetContent The filtered element itself.
149 * @param aMetrics The metrics to resolve SVG lengths against.
150 * @param aFilterChain The list of filters to apply.
151 * @param aFilterFrames The frames for the filters in the chain.
152 * @param aFilterInputIsTainted Describes whether the SourceImage /
153 * SourceAlpha input is tainted. This affects whether feDisplacementMap
154 * will respect the filter input as its map input.
155 * @param aPaintCallback [optional] The callback that Render() should use to
156 * paint. Only required if you will call Render().
157 * @param aPaintTransform The transform to apply to convert to
158 * aTargetFrame's SVG user space. Only used when painting.
159 * @param aPostFilterDirtyRegion [optional] The post-filter area
160 * that has to be repainted, in app units. Only required if you will
161 * call ComputeSourceNeededRect() or Render().
162 * @param aPreFilterDirtyRegion [optional] The pre-filter area of
163 * the filtered element that changed, in app units. Only required if you
164 * will call ComputePostFilterDirtyRegion().
165 * @param aPreFilterInkOverflowRectOverride [optional] Use a different
166 * ink overflow rect for the target element.
167 * @param aOverrideBBox [optional] Use a different SVG bbox for the target
168 * element. Must be non-null if aTargetFrame is null.
170 FilterInstance(
171 nsIFrame* aTargetFrame, nsIContent* aTargetContent,
172 const UserSpaceMetrics& aMetrics, Span<const StyleFilter> aFilterChain,
173 const nsTArray<SVGFilterFrame*>& aFilterFrames,
174 bool aFilterInputIsTainted,
175 const SVGIntegrationUtils::SVGFilterPaintCallback& aPaintCallback,
176 const gfxMatrix& aPaintTransform,
177 const nsRegion* aPostFilterDirtyRegion = nullptr,
178 const nsRegion* aPreFilterDirtyRegion = nullptr,
179 const nsRect* aPreFilterInkOverflowRectOverride = nullptr,
180 const gfxRect* aOverrideBBox = nullptr);
182 static bool BuildWebRenderFiltersImpl(
183 nsIFrame* aFilteredFrame,
184 mozilla::Span<const mozilla::StyleFilter> aFilters,
185 StyleFilterType aStyleFilterType, WrFiltersHolder& aWrFilters,
186 bool& aInitialized);
189 * Returns true if the filter instance was created successfully.
191 bool IsInitialized() const { return mInitialized; }
194 * Draws the filter output into aDrawTarget. The area that
195 * needs to be painted must have been specified before calling this method
196 * by passing it as the aPostFilterDirtyRegion argument to the
197 * FilterInstance constructor.
199 void Render(gfxContext* aCtx, imgDrawingParams& aImgParams,
200 float aOpacity = 1.0f);
202 const FilterDescription& ExtractDescriptionAndAdditionalImages(
203 nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages) {
204 aOutAdditionalImages = std::move(mInputImages);
205 return mFilterDescription;
209 * Sets the aPostFilterDirtyRegion outparam to the post-filter area in frame
210 * space that would be dirtied by mTargetFrame when a given
211 * pre-filter area of mTargetFrame is dirtied. The pre-filter area must have
212 * been specified before calling this method by passing it as the
213 * aPreFilterDirtyRegion argument to the FilterInstance constructor.
215 nsRegion ComputePostFilterDirtyRegion();
218 * Sets the aPostFilterExtents outparam to the post-filter bounds in frame
219 * space for the whole filter output. This is not necessarily equivalent to
220 * the area that would be dirtied in the result when the entire pre-filter
221 * area is dirtied, because some filter primitives can generate output
222 * without any input.
224 nsRect ComputePostFilterExtents();
227 * Sets the aDirty outparam to the pre-filter bounds in frame space of the
228 * area of mTargetFrame that is needed in order to paint the filtered output
229 * for a given post-filter dirtied area. The post-filter area must have been
230 * specified before calling this method by passing it as the
231 * aPostFilterDirtyRegion argument to the FilterInstance constructor.
233 nsRect ComputeSourceNeededRect();
235 struct SourceInfo {
236 // Specifies which parts of the source need to be rendered.
237 // Set by ComputeNeededBoxes().
238 nsIntRect mNeededBounds;
240 // The surface that contains the input rendering.
241 // Set by BuildSourceImage / BuildSourcePaint.
242 RefPtr<SourceSurface> mSourceSurface;
244 // The position and size of mSourceSurface in filter space.
245 // Set by BuildSourceImage / BuildSourcePaint.
246 IntRect mSurfaceRect;
250 * Creates a SourceSurface for either the FillPaint or StrokePaint graph
251 * nodes
253 void BuildSourcePaint(SourceInfo* aSource, imgDrawingParams& aImgParams);
256 * Creates a SourceSurface for either the FillPaint and StrokePaint graph
257 * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and
258 * mStrokePaint.mSourceSurface respectively.
260 void BuildSourcePaints(imgDrawingParams& aImgParams);
263 * Creates the SourceSurface for the SourceGraphic graph node, paints its
264 * contents, and assigns it to mSourceGraphic.mSourceSurface.
266 void BuildSourceImage(DrawTarget* aDest, imgDrawingParams& aImgParams,
267 mozilla::gfx::FilterNode* aFilter,
268 mozilla::gfx::FilterNode* aSource,
269 const mozilla::gfx::Rect& aSourceRect);
272 * Build the list of FilterPrimitiveDescriptions that describes the filter's
273 * filter primitives and their connections. This populates
274 * mPrimitiveDescriptions and mInputImages. aFilterInputIsTainted describes
275 * whether the SourceGraphic is tainted.
277 nsresult BuildPrimitives(Span<const StyleFilter> aFilterChain,
278 const nsTArray<SVGFilterFrame*>& aFilterFrames,
279 bool aFilterInputIsTainted);
282 * Add to the list of FilterPrimitiveDescriptions for a particular SVG
283 * reference filter or CSS filter. This populates mPrimitiveDescriptions and
284 * mInputImages. aInputIsTainted describes whether the input to aFilter is
285 * tainted.
287 nsresult BuildPrimitivesForFilter(
288 const StyleFilter& aFilter, SVGFilterFrame* aFilterFrame,
289 bool aInputIsTainted,
290 nsTArray<FilterPrimitiveDescription>& aPrimitiveDescriptions);
293 * Computes the filter space bounds of the areas that we actually *need* from
294 * the filter sources, based on the value of mPostFilterDirtyRegion.
295 * This sets mNeededBounds on the corresponding SourceInfo structs.
297 void ComputeNeededBoxes();
300 * Returns the output bounds of the final FilterPrimitiveDescription.
302 nsIntRect OutputFilterSpaceBounds() const;
305 * Compute the scale factors between user space and filter space.
307 bool ComputeUserSpaceToFilterSpaceScale();
310 * Transform a rect between user space and filter space.
312 gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const;
313 gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const;
316 * Converts an nsRect or an nsRegion that is relative to a filtered frame's
317 * origin (i.e. the top-left corner of its border box) into filter space,
318 * rounding out.
319 * Returns the entire filter region if aRect / aRegion is null, or if the
320 * result is too large to be stored in an nsIntRect.
322 nsIntRect FrameSpaceToFilterSpace(const nsRect* aRect) const;
323 nsIntRegion FrameSpaceToFilterSpace(const nsRegion* aRegion) const;
326 * Converts an nsIntRect or an nsIntRegion from filter space into the space
327 * that is relative to a filtered frame's origin (i.e. the top-left corner
328 * of its border box) in app units, rounding out.
330 nsRect FilterSpaceToFrameSpace(const nsIntRect& aRect) const;
331 nsRegion FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const;
334 * Returns the transform from frame space to the coordinate space that
335 * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the
336 * top-left corner of its border box, aka the top left corner of its mRect.
338 gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const;
340 bool ComputeTargetBBoxInFilterSpace();
343 * The frame for the element that is currently being filtered.
345 nsIFrame* mTargetFrame;
348 * The filtered element.
350 nsIContent* mTargetContent;
353 * The user space metrics of the filtered frame.
355 const UserSpaceMetrics& mMetrics;
357 const SVGFilterPaintCallback& mPaintCallback;
360 * The SVG bbox of the element that is being filtered, in user space.
362 gfxRect mTargetBBox;
365 * The SVG bbox of the element that is being filtered, in filter space.
367 nsIntRect mTargetBBoxInFilterSpace;
370 * Transform rects between filter space and frame space in CSS pixels.
372 gfxMatrix mFilterSpaceToFrameSpaceInCSSPxTransform;
373 gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform;
376 * The scale factors between user space and filter space.
378 gfx::MatrixScalesDouble mUserSpaceToFilterSpaceScale;
379 gfx::MatrixScalesDouble mFilterSpaceToUserSpaceScale;
382 * Pre-filter paint bounds of the element that is being filtered, in filter
383 * space.
385 nsIntRect mTargetBounds;
388 * The dirty area that needs to be repainted, in filter space.
390 nsIntRegion mPostFilterDirtyRegion;
393 * The pre-filter area of the filtered element that changed, in filter space.
395 nsIntRegion mPreFilterDirtyRegion;
397 SourceInfo mSourceGraphic;
398 SourceInfo mFillPaint;
399 SourceInfo mStrokePaint;
402 * The transform to the SVG user space of mTargetFrame.
404 gfxMatrix mPaintTransform;
406 nsTArray<RefPtr<SourceSurface>> mInputImages;
407 FilterDescription mFilterDescription;
408 bool mInitialized;
411 } // namespace mozilla
413 #endif // LAYOUT_SVG_FILTERINSTANCE_H_