SVGFilterInstance.h (9826B)
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/. */ 6 7 #ifndef LAYOUT_SVG_SVGFILTERINSTANCE_H_ 8 #define LAYOUT_SVG_SVGFILTERINSTANCE_H_ 9 10 #include "SVGAnimatedNumber.h" 11 #include "SVGAnimatedNumberPair.h" 12 #include "SVGFilters.h" 13 #include "gfxMatrix.h" 14 #include "gfxRect.h" 15 #include "mozilla/ServoStyleConsts.h" 16 17 namespace mozilla { 18 class SVGFilterFrame; 19 20 namespace dom { 21 class SVGFilterElement; 22 } // namespace dom 23 24 /** 25 * This class helps FilterInstance build its filter graph by processing a 26 * single SVG reference filter. 27 * 28 * In BuildPrimitives, this class iterates through the referenced <filter> 29 * element's primitive elements, creating a FilterPrimitiveDescription for 30 * each one. 31 * 32 * This class uses several different coordinate spaces, defined as follows: 33 * 34 * "user space" 35 * The filtered SVG element's user space or the filtered HTML element's 36 * CSS pixel space. The origin for an HTML element is the top left corner of 37 * its border box. 38 * 39 * "filter space" 40 * User space scaled to device pixels. Shares the same origin as user space. 41 * This space is the same across chained SVG and CSS filters. To compute the 42 * overall filter space for a chain, we first need to build each filter's 43 * FilterPrimitiveDescriptions in some common space. That space is 44 * filter space. 45 * 46 * To understand the spaces better, let's take an example filter: 47 * <filter id="f">...</filter> 48 * 49 * And apply the filter to a div element: 50 * <div style="filter: url(#f); ...">...</div> 51 * 52 * And let's say there are 2 device pixels for every 1 CSS pixel. 53 * 54 * Finally, let's define an arbitrary point in user space: 55 * "user space point" = (10, 10) 56 * 57 * The point will be inset 10 CSS pixels from both the top and left edges of the 58 * div element's border box. 59 * 60 * Now, let's transform the point from user space to filter space: 61 * "filter space point" = "user space point" * "device pixels per CSS pixel" 62 * "filter space point" = (10, 10) * 2 63 * "filter space point" = (20, 20) 64 */ 65 class SVGFilterInstance { 66 using Point3D = gfx::Point3D; 67 using IntRect = gfx::IntRect; 68 using SourceSurface = gfx::SourceSurface; 69 using FilterPrimitiveDescription = gfx::FilterPrimitiveDescription; 70 using SVGFilterPrimitiveElement = dom::SVGFilterPrimitiveElement; 71 using UserSpaceMetrics = dom::UserSpaceMetrics; 72 73 public: 74 /** 75 * @param aFilter The SVG filter reference from the style system. This class 76 * stores aFilter by reference, so callers should avoid modifying or 77 * deleting aFilter during the lifetime of SVGFilterInstance. 78 * @param aTargetContent The filtered element. 79 * @param aTargetBBox The SVG bbox to use for the target frame, computed by 80 * the caller. The caller may decide to override the actual SVG bbox. 81 */ 82 SVGFilterInstance(const StyleFilter& aFilter, SVGFilterFrame* aFilterFrame, 83 nsIContent* aTargetContent, 84 const UserSpaceMetrics& aMetrics, 85 const gfxRect& aTargetBBox, 86 const gfx::MatrixScalesDouble& aUserSpaceToFilterSpaceScale, 87 gfxRect& aFilterSpaceBoundsNotSnapped); 88 89 /** 90 * Returns true if the filter instance was created successfully. 91 */ 92 bool IsInitialized() const { return mInitialized; } 93 94 /** 95 * Iterates through the <filter> element's primitive elements, creating a 96 * FilterPrimitiveDescription for each one. Appends the new 97 * FilterPrimitiveDescription(s) to the aPrimitiveDescrs list. Also, appends 98 * new images from feImage filter primitive elements to the aInputImages list. 99 * aInputIsTainted describes whether the input to this filter is tainted, i.e. 100 * whether it contains security-sensitive content. This is needed to propagate 101 * taintedness to the FilterPrimitive that take tainted inputs. Something 102 * being tainted means that it contains security sensitive content. The input 103 * to this filter is the previous filter's output, i.e. the last element in 104 * aPrimitiveDescrs, or the SourceGraphic input if this is the first filter in 105 * the filter chain. 106 */ 107 nsresult BuildPrimitives( 108 nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, 109 nsTArray<RefPtr<SourceSurface>>& aInputImages, bool aInputIsTainted); 110 111 float GetPrimitiveUserSpaceUnitValue(uint8_t aCtxType) const; 112 113 float GetPrimitiveNumber(uint8_t aCtxType, 114 const SVGAnimatedNumber* aNumber) const { 115 return GetPrimitiveNumber(aCtxType, aNumber->GetAnimValue()); 116 } 117 float GetPrimitiveNumber(uint8_t aCtxType, 118 const SVGAnimatedNumberPair* aNumberPair, 119 SVGAnimatedNumberPair::PairIndex aIndex) const { 120 return GetPrimitiveNumber(aCtxType, aNumberPair->GetAnimValue(aIndex)); 121 } 122 123 /** 124 * Converts a userSpaceOnUse/objectBoundingBoxUnits unitless point 125 * into filter space, depending on the value of mPrimitiveUnits. (For 126 * objectBoundingBoxUnits, the bounding box offset is applied to the point.) 127 */ 128 Point3D ConvertLocation(const Point3D& aPoint) const; 129 130 /* 131 * Transform a float in a particular direction between user space 132 * and filter space. 133 */ 134 float UserSpaceToFilterSpace(uint8_t aCtxType, float aValue) const; 135 136 /** 137 * Transform a rect between user space and filter space. 138 */ 139 gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const; 140 141 private: 142 /** 143 * Computes the filter primitive subregion for the given primitive. 144 */ 145 IntRect ComputeFilterPrimitiveSubregion( 146 SVGFilterPrimitiveElement* aFilterElement, 147 const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, 148 const nsTArray<int32_t>& aInputIndices); 149 150 /** 151 * Takes the input indices of a filter primitive and returns for each input 152 * whether the input's output is tainted. 153 */ 154 void GetInputsAreTainted( 155 const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, 156 const nsTArray<int32_t>& aInputIndices, bool aFilterInputIsTainted, 157 nsTArray<bool>& aOutInputsAreTainted); 158 159 /** 160 * Scales a numeric filter primitive length in the X, Y or "XY" directions 161 * into a length in filter space (no offset is applied). 162 */ 163 float GetPrimitiveNumber(uint8_t aCtxType, float aValue) const; 164 165 /** 166 * Returns the transform from frame space to the coordinate space that 167 * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the 168 * top-left corner of its border box, aka the top left corner of its mRect. 169 */ 170 gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const; 171 172 /** 173 * Appends a new FilterPrimitiveDescription to aPrimitiveDescrs that 174 * converts the FilterPrimitiveDescription at mSourceGraphicIndex into 175 * a SourceAlpha input for the next FilterPrimitiveDescription. 176 * 177 * The new FilterPrimitiveDescription zeros out the SourceGraphic's RGB 178 * channels and keeps the alpha channel intact. 179 */ 180 int32_t GetOrCreateSourceAlphaIndex( 181 nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs); 182 183 /** 184 * Finds the index in aPrimitiveDescrs of each input to aPrimitiveElement. 185 * For example, if aPrimitiveElement is: 186 * <feGaussianBlur in="another-primitive" .../> 187 * Then, the resulting aSourceIndices will contain the index of the 188 * FilterPrimitiveDescription representing "another-primitive". 189 */ 190 nsresult GetSourceIndices( 191 SVGFilterPrimitiveElement* aPrimitiveElement, 192 nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, 193 const nsTHashMap<nsStringHashKey, int32_t>& aImageTable, 194 nsTArray<int32_t>& aSourceIndices); 195 196 /** 197 * Compute the filter region in user space, filter space, and filter 198 * space. 199 */ 200 bool ComputeBounds(); 201 202 /** 203 * The SVG reference filter originally from the style system. 204 */ 205 const StyleFilter& mFilter; 206 207 /** 208 * The filtered element. 209 */ 210 nsIContent* mTargetContent; 211 212 /** 213 * The SVG user space metrics that SVG lengths are resolved against. 214 */ 215 const UserSpaceMetrics& mMetrics; 216 217 /** 218 * The filter element referenced by mTargetFrame's element. 219 */ 220 const dom::SVGFilterElement* mFilterElement; 221 222 /** 223 * The frame for the SVG filter element. 224 */ 225 SVGFilterFrame* mFilterFrame; 226 227 /** 228 * The SVG bbox of the element that is being filtered, in user space. 229 */ 230 gfxRect mTargetBBox; 231 232 /** 233 * The "filter region" in various spaces. 234 */ 235 nsIntRect mFilterSpaceBounds; 236 237 /** 238 * The bounds of the filter element itself, which may be non-integer. 239 */ 240 gfxRect mFilterSpaceBoundsNotSnapped; 241 242 /** 243 * The scale factors between user space and filter space. 244 */ 245 gfx::MatrixScalesDouble mUserSpaceToFilterSpaceScale; 246 247 /** 248 * The 'primitiveUnits' attribute value (objectBoundingBox or userSpaceOnUse). 249 */ 250 uint16_t mPrimitiveUnits; 251 252 /** 253 * The index of the FilterPrimitiveDescription that this SVG filter should use 254 * as its SourceGraphic, or the SourceGraphic keyword index if this is the 255 * first filter in a chain. Initialized in BuildPrimitives 256 */ 257 MOZ_INIT_OUTSIDE_CTOR int32_t mSourceGraphicIndex; 258 259 /** 260 * The index of the FilterPrimitiveDescription that this SVG filter should use 261 * as its SourceAlpha, or the SourceAlpha keyword index if this is the first 262 * filter in a chain. Initialized in BuildPrimitives 263 */ 264 MOZ_INIT_OUTSIDE_CTOR int32_t mSourceAlphaIndex; 265 266 /** 267 * SourceAlpha is available if GetOrCreateSourceAlphaIndex has been called. 268 */ 269 int32_t mSourceAlphaAvailable; 270 271 bool mInitialized; 272 }; 273 274 } // namespace mozilla 275 276 #endif // LAYOUT_SVG_SVGFILTERINSTANCE_H_