1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/svg/nsFilterInstance.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,322 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef __NS_FILTERINSTANCE_H__ 1.10 +#define __NS_FILTERINSTANCE_H__ 1.11 + 1.12 +#include "gfxMatrix.h" 1.13 +#include "gfxPoint.h" 1.14 +#include "gfxRect.h" 1.15 +#include "nsCOMPtr.h" 1.16 +#include "nsHashKeys.h" 1.17 +#include "nsPoint.h" 1.18 +#include "nsRect.h" 1.19 +#include "nsSize.h" 1.20 +#include "nsSVGFilters.h" 1.21 +#include "nsSVGNumber2.h" 1.22 +#include "nsSVGNumberPair.h" 1.23 +#include "nsTArray.h" 1.24 +#include "nsIFrame.h" 1.25 +#include "mozilla/gfx/2D.h" 1.26 + 1.27 +class gfxASurface; 1.28 +class nsIFrame; 1.29 +class nsSVGFilterPaintCallback; 1.30 + 1.31 +/** 1.32 + * This class performs all filter processing. 1.33 + * 1.34 + * We build a graph of the filter image data flow, essentially 1.35 + * converting the filter graph to SSA. This lets us easily propagate 1.36 + * analysis data (such as bounding-boxes) over the filter primitive graph. 1.37 + * 1.38 + * Definition of "filter space": filter space is a coordinate system that is 1.39 + * aligned with the user space of the filtered element, with its origin located 1.40 + * at the top left of the filter region, and with one unit equal in size to one 1.41 + * pixel of the offscreen surface into which the filter output would/will be 1.42 + * painted. 1.43 + * 1.44 + * The definition of "filter region" can be found here: 1.45 + * http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion 1.46 + */ 1.47 +class nsFilterInstance 1.48 +{ 1.49 + typedef mozilla::gfx::IntRect IntRect; 1.50 + typedef mozilla::gfx::SourceSurface SourceSurface; 1.51 + typedef mozilla::gfx::DrawTarget DrawTarget; 1.52 + typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription; 1.53 + 1.54 +public: 1.55 + /** 1.56 + * Paint the given filtered frame. 1.57 + * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's 1.58 + * frame space (i.e. relative to its origin, the top-left corner of its 1.59 + * border box). 1.60 + */ 1.61 + static nsresult PaintFilteredFrame(nsRenderingContext *aContext, 1.62 + nsIFrame *aFilteredFrame, 1.63 + nsSVGFilterPaintCallback *aPaintCallback, 1.64 + const nsRegion* aDirtyArea, 1.65 + nsIFrame* aTransformRoot = nullptr); 1.66 + 1.67 + /** 1.68 + * Returns the post-filter area that could be dirtied when the given 1.69 + * pre-filter area of aFilteredFrame changes. 1.70 + * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that has 1.71 + * changed, relative to aFilteredFrame, in app units. 1.72 + */ 1.73 + static nsRegion GetPostFilterDirtyArea(nsIFrame *aFilteredFrame, 1.74 + const nsRegion& aPreFilterDirtyRegion); 1.75 + 1.76 + /** 1.77 + * Returns the pre-filter area that is needed from aFilteredFrame when the 1.78 + * given post-filter area needs to be repainted. 1.79 + * @param aPostFilterDirtyRegion The post-filter area that is dirty, relative 1.80 + * to aFilteredFrame, in app units. 1.81 + */ 1.82 + static nsRegion GetPreFilterNeededArea(nsIFrame *aFilteredFrame, 1.83 + const nsRegion& aPostFilterDirtyRegion); 1.84 + 1.85 + /** 1.86 + * Returns the post-filter visual overflow rect (paint bounds) of 1.87 + * aFilteredFrame. 1.88 + * @param aOverrideBBox A user space rect, in user units, that should be used 1.89 + * as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null. 1.90 + * @param aPreFilterBounds The pre-filter visual overflow rect of 1.91 + * aFilteredFrame, if non-null. 1.92 + */ 1.93 + static nsRect GetPostFilterBounds(nsIFrame *aFilteredFrame, 1.94 + const gfxRect *aOverrideBBox = nullptr, 1.95 + const nsRect *aPreFilterBounds = nullptr); 1.96 + 1.97 + /** 1.98 + * @param aTargetFrame The frame of the filtered element under consideration. 1.99 + * @param aPaintCallback [optional] The callback that Render() should use to 1.100 + * paint. Only required if you will call Render(). 1.101 + * @param aPostFilterDirtyRegion [optional] The post-filter area 1.102 + * that has to be repainted, in app units. Only required if you will 1.103 + * call ComputeSourceNeededRect() or Render(). 1.104 + * @param aPreFilterDirtyRegion [optional] The pre-filter area of 1.105 + * the filtered element that changed, in app units. Only required if you 1.106 + * will call ComputePostFilterDirtyRegion(). 1.107 + * @param aOverridePreFilterVisualOverflowRect [optional] Use a different 1.108 + * visual overflow rect for the target element. 1.109 + * @param aOverrideBBox [optional] Use a different SVG bbox for the target 1.110 + * element. 1.111 + * @param aTransformRoot [optional] The transform root frame for painting. 1.112 + */ 1.113 + nsFilterInstance(nsIFrame *aTargetFrame, 1.114 + nsSVGFilterPaintCallback *aPaintCallback, 1.115 + const nsRegion *aPostFilterDirtyRegion = nullptr, 1.116 + const nsRegion *aPreFilterDirtyRegion = nullptr, 1.117 + const nsRect *aOverridePreFilterVisualOverflowRect = nullptr, 1.118 + const gfxRect *aOverrideBBox = nullptr, 1.119 + nsIFrame* aTransformRoot = nullptr); 1.120 + 1.121 + /** 1.122 + * Returns true if the filter instance was created successfully. 1.123 + */ 1.124 + bool IsInitialized() const { return mInitialized; } 1.125 + 1.126 + /** 1.127 + * Draws the filter output into aContext. The area that 1.128 + * needs to be painted must have been specified before calling this method 1.129 + * by passing it as the aPostFilterDirtyRegion argument to the 1.130 + * nsFilterInstance constructor. 1.131 + */ 1.132 + nsresult Render(gfxContext* aContext); 1.133 + 1.134 + /** 1.135 + * Sets the aPostFilterDirtyRegion outparam to the post-filter area in frame 1.136 + * space that would be dirtied by mTargetFrame when a given 1.137 + * pre-filter area of mTargetFrame is dirtied. The pre-filter area must have 1.138 + * been specified before calling this method by passing it as the 1.139 + * aPreFilterDirtyRegion argument to the nsFilterInstance constructor. 1.140 + */ 1.141 + nsresult ComputePostFilterDirtyRegion(nsRegion* aPostFilterDirtyRegion); 1.142 + 1.143 + /** 1.144 + * Sets the aPostFilterExtents outparam to the post-filter bounds in frame 1.145 + * space for the whole filter output. This is not necessarily equivalent to 1.146 + * the area that would be dirtied in the result when the entire pre-filter 1.147 + * area is dirtied, because some filter primitives can generate output 1.148 + * without any input. 1.149 + */ 1.150 + nsresult ComputePostFilterExtents(nsRect* aPostFilterExtents); 1.151 + 1.152 + /** 1.153 + * Sets the aDirty outparam to the pre-filter bounds in frame space of the 1.154 + * area of mTargetFrame that is needed in order to paint the filtered output 1.155 + * for a given post-filter dirtied area. The post-filter area must have been 1.156 + * specified before calling this method by passing it as the aPostFilterDirtyRegion 1.157 + * argument to the nsFilterInstance constructor. 1.158 + */ 1.159 + nsresult ComputeSourceNeededRect(nsRect* aDirty); 1.160 + 1.161 + 1.162 + /** 1.163 + * Returns the transform from filter space to outer-<svg> device space. 1.164 + */ 1.165 + gfxMatrix GetFilterSpaceToDeviceSpaceTransform() const { 1.166 + return mFilterSpaceToDeviceSpaceTransform; 1.167 + } 1.168 + 1.169 +private: 1.170 + struct SourceInfo { 1.171 + // Specifies which parts of the source need to be rendered. 1.172 + // Set by ComputeNeededBoxes(). 1.173 + nsIntRect mNeededBounds; 1.174 + 1.175 + // The surface that contains the input rendering. 1.176 + // Set by BuildSourceImage / BuildSourcePaint. 1.177 + mozilla::RefPtr<SourceSurface> mSourceSurface; 1.178 + 1.179 + // The position and size of mSourceSurface in filter space. 1.180 + // Set by BuildSourceImage / BuildSourcePaint. 1.181 + IntRect mSurfaceRect; 1.182 + }; 1.183 + 1.184 + /** 1.185 + * Creates a SourceSurface for either the FillPaint or StrokePaint graph 1.186 + * nodes 1.187 + */ 1.188 + nsresult BuildSourcePaint(SourceInfo *aPrimitive, 1.189 + gfxASurface* aTargetSurface, 1.190 + DrawTarget* aTargetDT); 1.191 + 1.192 + /** 1.193 + * Creates a SourceSurface for either the FillPaint and StrokePaint graph 1.194 + * nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and 1.195 + * mStrokePaint.mSourceSurface respectively. 1.196 + */ 1.197 + nsresult BuildSourcePaints(gfxASurface* aTargetSurface, 1.198 + DrawTarget* aTargetDT); 1.199 + 1.200 + /** 1.201 + * Creates the SourceSurface for the SourceGraphic graph node, paints its 1.202 + * contents, and assigns it to mSourceGraphic.mSourceSurface. 1.203 + */ 1.204 + nsresult BuildSourceImage(gfxASurface* aTargetSurface, 1.205 + DrawTarget* aTargetDT); 1.206 + 1.207 + /** 1.208 + * Build the list of FilterPrimitiveDescriptions that describes the filter's 1.209 + * filter primitives and their connections. This populates 1.210 + * mPrimitiveDescriptions and mInputImages. 1.211 + */ 1.212 + nsresult BuildPrimitives(); 1.213 + 1.214 + /** 1.215 + * Add to the list of FilterPrimitiveDescriptions for a particular SVG 1.216 + * reference filter or CSS filter. This populates mPrimitiveDescrs and 1.217 + * mInputImages. 1.218 + */ 1.219 + nsresult BuildPrimitivesForFilter(const nsStyleFilter& aFilter); 1.220 + 1.221 + /** 1.222 + * Computes the filter space bounds of the areas that we actually *need* from 1.223 + * the filter sources, based on the value of mPostFilterDirtyRegion. 1.224 + * This sets mNeededBounds on the corresponding SourceInfo structs. 1.225 + */ 1.226 + void ComputeNeededBoxes(); 1.227 + 1.228 + /** 1.229 + * Compute the scale factors between user space and filter space. 1.230 + */ 1.231 + nsresult ComputeUserSpaceToFilterSpaceScale(); 1.232 + 1.233 + /** 1.234 + * Transform a rect between user space and filter space. 1.235 + */ 1.236 + gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const; 1.237 + gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const; 1.238 + 1.239 + /** 1.240 + * Converts an nsRect or an nsRegion that is relative to a filtered frame's 1.241 + * origin (i.e. the top-left corner of its border box) into filter space, 1.242 + * rounding out. 1.243 + * Returns the entire filter region if aRect / aRegion is null, or if the 1.244 + * result is too large to be stored in an nsIntRect. 1.245 + */ 1.246 + nsIntRect FrameSpaceToFilterSpace(const nsRect* aRect) const; 1.247 + nsIntRegion FrameSpaceToFilterSpace(const nsRegion* aRegion) const; 1.248 + 1.249 + /** 1.250 + * Converts an nsIntRect or an nsIntRegion from filter space into the space 1.251 + * that is relative to a filtered frame's origin (i.e. the top-left corner 1.252 + * of its border box) in app units, rounding out. 1.253 + */ 1.254 + nsRect FilterSpaceToFrameSpace(const nsIntRect& aRect) const; 1.255 + nsRegion FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const; 1.256 + 1.257 + /** 1.258 + * Returns the transform from frame space to the coordinate space that 1.259 + * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the 1.260 + * top-left corner of its border box, aka the top left corner of its mRect. 1.261 + */ 1.262 + gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const; 1.263 + 1.264 + /** 1.265 + * The frame for the element that is currently being filtered. 1.266 + */ 1.267 + nsIFrame* mTargetFrame; 1.268 + 1.269 + nsSVGFilterPaintCallback* mPaintCallback; 1.270 + 1.271 + /** 1.272 + * The SVG bbox of the element that is being filtered, in user space. 1.273 + */ 1.274 + gfxRect mTargetBBox; 1.275 + 1.276 + /** 1.277 + * The transform from filter space to outer-<svg> device space. 1.278 + */ 1.279 + gfxMatrix mFilterSpaceToDeviceSpaceTransform; 1.280 + 1.281 + /** 1.282 + * Transform rects between filter space and frame space in CSS pixels. 1.283 + */ 1.284 + gfxMatrix mFilterSpaceToFrameSpaceInCSSPxTransform; 1.285 + gfxMatrix mFrameSpaceInCSSPxToFilterSpaceTransform; 1.286 + 1.287 + /** 1.288 + * The "filter region", in the filtered element's user space. 1.289 + */ 1.290 + gfxRect mUserSpaceBounds; 1.291 + nsIntRect mFilterSpaceBounds; 1.292 + 1.293 + /** 1.294 + * The scale factors between user space and filter space. 1.295 + */ 1.296 + gfxSize mUserSpaceToFilterSpaceScale; 1.297 + gfxSize mFilterSpaceToUserSpaceScale; 1.298 + 1.299 + /** 1.300 + * Pre-filter paint bounds of the element that is being filtered, in filter 1.301 + * space. 1.302 + */ 1.303 + nsIntRect mTargetBounds; 1.304 + 1.305 + /** 1.306 + * The dirty area that needs to be repainted, in filter space. 1.307 + */ 1.308 + nsIntRegion mPostFilterDirtyRegion; 1.309 + 1.310 + /** 1.311 + * The pre-filter area of the filtered element that changed, in filter space. 1.312 + */ 1.313 + nsIntRegion mPreFilterDirtyRegion; 1.314 + 1.315 + SourceInfo mSourceGraphic; 1.316 + SourceInfo mFillPaint; 1.317 + SourceInfo mStrokePaint; 1.318 + nsIFrame* mTransformRoot; 1.319 + nsTArray<mozilla::RefPtr<SourceSurface>> mInputImages; 1.320 + nsTArray<FilterPrimitiveDescription> mPrimitiveDescriptions; 1.321 + int32_t mAppUnitsPerCSSPx; 1.322 + bool mInitialized; 1.323 +}; 1.324 + 1.325 +#endif