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/. */
6 #include "FilterSupport.h"
8 #include "mozilla/gfx/2D.h"
9 #include "mozilla/gfx/Filters.h"
10 #include "mozilla/PodOperations.h"
12 #include "gfxContext.h"
13 #include "gfxPattern.h"
14 #include "gfxPlatform.h"
15 #include "gfx2DGlue.h"
20 // c <= 0.0031308f ? c * 12.92f : 1.055f * powf(c, 1 / 2.4f) - 0.055f
21 static const float glinearRGBTosRGBMap
[256] = {
22 0.000f
, 0.050f
, 0.085f
, 0.111f
, 0.132f
, 0.150f
, 0.166f
, 0.181f
,
23 0.194f
, 0.207f
, 0.219f
, 0.230f
, 0.240f
, 0.250f
, 0.260f
, 0.269f
,
24 0.278f
, 0.286f
, 0.295f
, 0.303f
, 0.310f
, 0.318f
, 0.325f
, 0.332f
,
25 0.339f
, 0.346f
, 0.352f
, 0.359f
, 0.365f
, 0.371f
, 0.378f
, 0.383f
,
26 0.389f
, 0.395f
, 0.401f
, 0.406f
, 0.412f
, 0.417f
, 0.422f
, 0.427f
,
27 0.433f
, 0.438f
, 0.443f
, 0.448f
, 0.452f
, 0.457f
, 0.462f
, 0.466f
,
28 0.471f
, 0.476f
, 0.480f
, 0.485f
, 0.489f
, 0.493f
, 0.498f
, 0.502f
,
29 0.506f
, 0.510f
, 0.514f
, 0.518f
, 0.522f
, 0.526f
, 0.530f
, 0.534f
,
30 0.538f
, 0.542f
, 0.546f
, 0.549f
, 0.553f
, 0.557f
, 0.561f
, 0.564f
,
31 0.568f
, 0.571f
, 0.575f
, 0.579f
, 0.582f
, 0.586f
, 0.589f
, 0.592f
,
32 0.596f
, 0.599f
, 0.603f
, 0.606f
, 0.609f
, 0.613f
, 0.616f
, 0.619f
,
33 0.622f
, 0.625f
, 0.629f
, 0.632f
, 0.635f
, 0.638f
, 0.641f
, 0.644f
,
34 0.647f
, 0.650f
, 0.653f
, 0.656f
, 0.659f
, 0.662f
, 0.665f
, 0.668f
,
35 0.671f
, 0.674f
, 0.677f
, 0.680f
, 0.683f
, 0.685f
, 0.688f
, 0.691f
,
36 0.694f
, 0.697f
, 0.699f
, 0.702f
, 0.705f
, 0.708f
, 0.710f
, 0.713f
,
37 0.716f
, 0.718f
, 0.721f
, 0.724f
, 0.726f
, 0.729f
, 0.731f
, 0.734f
,
38 0.737f
, 0.739f
, 0.742f
, 0.744f
, 0.747f
, 0.749f
, 0.752f
, 0.754f
,
39 0.757f
, 0.759f
, 0.762f
, 0.764f
, 0.767f
, 0.769f
, 0.772f
, 0.774f
,
40 0.776f
, 0.779f
, 0.781f
, 0.784f
, 0.786f
, 0.788f
, 0.791f
, 0.793f
,
41 0.795f
, 0.798f
, 0.800f
, 0.802f
, 0.805f
, 0.807f
, 0.809f
, 0.812f
,
42 0.814f
, 0.816f
, 0.818f
, 0.821f
, 0.823f
, 0.825f
, 0.827f
, 0.829f
,
43 0.832f
, 0.834f
, 0.836f
, 0.838f
, 0.840f
, 0.843f
, 0.845f
, 0.847f
,
44 0.849f
, 0.851f
, 0.853f
, 0.855f
, 0.857f
, 0.860f
, 0.862f
, 0.864f
,
45 0.866f
, 0.868f
, 0.870f
, 0.872f
, 0.874f
, 0.876f
, 0.878f
, 0.880f
,
46 0.882f
, 0.884f
, 0.886f
, 0.888f
, 0.890f
, 0.892f
, 0.894f
, 0.896f
,
47 0.898f
, 0.900f
, 0.902f
, 0.904f
, 0.906f
, 0.908f
, 0.910f
, 0.912f
,
48 0.914f
, 0.916f
, 0.918f
, 0.920f
, 0.922f
, 0.924f
, 0.926f
, 0.928f
,
49 0.930f
, 0.931f
, 0.933f
, 0.935f
, 0.937f
, 0.939f
, 0.941f
, 0.943f
,
50 0.945f
, 0.946f
, 0.948f
, 0.950f
, 0.952f
, 0.954f
, 0.956f
, 0.957f
,
51 0.959f
, 0.961f
, 0.963f
, 0.965f
, 0.967f
, 0.968f
, 0.970f
, 0.972f
,
52 0.974f
, 0.975f
, 0.977f
, 0.979f
, 0.981f
, 0.983f
, 0.984f
, 0.986f
,
53 0.988f
, 0.990f
, 0.991f
, 0.993f
, 0.995f
, 0.997f
, 0.998f
, 1.000f
57 // c <= 0.04045f ? c / 12.92f : powf((c + 0.055f) / 1.055f, 2.4f)
58 static const float gsRGBToLinearRGBMap
[256] = {
59 0.000f
, 0.000f
, 0.001f
, 0.001f
, 0.001f
, 0.002f
, 0.002f
, 0.002f
,
60 0.002f
, 0.003f
, 0.003f
, 0.003f
, 0.004f
, 0.004f
, 0.004f
, 0.005f
,
61 0.005f
, 0.006f
, 0.006f
, 0.007f
, 0.007f
, 0.007f
, 0.008f
, 0.009f
,
62 0.009f
, 0.010f
, 0.010f
, 0.011f
, 0.012f
, 0.012f
, 0.013f
, 0.014f
,
63 0.014f
, 0.015f
, 0.016f
, 0.017f
, 0.018f
, 0.019f
, 0.019f
, 0.020f
,
64 0.021f
, 0.022f
, 0.023f
, 0.024f
, 0.025f
, 0.026f
, 0.027f
, 0.028f
,
65 0.030f
, 0.031f
, 0.032f
, 0.033f
, 0.034f
, 0.036f
, 0.037f
, 0.038f
,
66 0.040f
, 0.041f
, 0.042f
, 0.044f
, 0.045f
, 0.047f
, 0.048f
, 0.050f
,
67 0.051f
, 0.053f
, 0.054f
, 0.056f
, 0.058f
, 0.060f
, 0.061f
, 0.063f
,
68 0.065f
, 0.067f
, 0.068f
, 0.070f
, 0.072f
, 0.074f
, 0.076f
, 0.078f
,
69 0.080f
, 0.082f
, 0.084f
, 0.087f
, 0.089f
, 0.091f
, 0.093f
, 0.095f
,
70 0.098f
, 0.100f
, 0.102f
, 0.105f
, 0.107f
, 0.109f
, 0.112f
, 0.114f
,
71 0.117f
, 0.120f
, 0.122f
, 0.125f
, 0.127f
, 0.130f
, 0.133f
, 0.136f
,
72 0.138f
, 0.141f
, 0.144f
, 0.147f
, 0.150f
, 0.153f
, 0.156f
, 0.159f
,
73 0.162f
, 0.165f
, 0.168f
, 0.171f
, 0.175f
, 0.178f
, 0.181f
, 0.184f
,
74 0.188f
, 0.191f
, 0.195f
, 0.198f
, 0.202f
, 0.205f
, 0.209f
, 0.212f
,
75 0.216f
, 0.220f
, 0.223f
, 0.227f
, 0.231f
, 0.235f
, 0.238f
, 0.242f
,
76 0.246f
, 0.250f
, 0.254f
, 0.258f
, 0.262f
, 0.266f
, 0.270f
, 0.275f
,
77 0.279f
, 0.283f
, 0.287f
, 0.292f
, 0.296f
, 0.301f
, 0.305f
, 0.309f
,
78 0.314f
, 0.319f
, 0.323f
, 0.328f
, 0.332f
, 0.337f
, 0.342f
, 0.347f
,
79 0.352f
, 0.356f
, 0.361f
, 0.366f
, 0.371f
, 0.376f
, 0.381f
, 0.386f
,
80 0.392f
, 0.397f
, 0.402f
, 0.407f
, 0.413f
, 0.418f
, 0.423f
, 0.429f
,
81 0.434f
, 0.440f
, 0.445f
, 0.451f
, 0.456f
, 0.462f
, 0.468f
, 0.474f
,
82 0.479f
, 0.485f
, 0.491f
, 0.497f
, 0.503f
, 0.509f
, 0.515f
, 0.521f
,
83 0.527f
, 0.533f
, 0.539f
, 0.546f
, 0.552f
, 0.558f
, 0.565f
, 0.571f
,
84 0.578f
, 0.584f
, 0.591f
, 0.597f
, 0.604f
, 0.610f
, 0.617f
, 0.624f
,
85 0.631f
, 0.638f
, 0.644f
, 0.651f
, 0.658f
, 0.665f
, 0.672f
, 0.680f
,
86 0.687f
, 0.694f
, 0.701f
, 0.708f
, 0.716f
, 0.723f
, 0.730f
, 0.738f
,
87 0.745f
, 0.753f
, 0.761f
, 0.768f
, 0.776f
, 0.784f
, 0.791f
, 0.799f
,
88 0.807f
, 0.815f
, 0.823f
, 0.831f
, 0.839f
, 0.847f
, 0.855f
, 0.863f
,
89 0.871f
, 0.880f
, 0.888f
, 0.896f
, 0.905f
, 0.913f
, 0.922f
, 0.930f
,
90 0.939f
, 0.947f
, 0.956f
, 0.965f
, 0.973f
, 0.982f
, 0.991f
, 1.000f
96 // Some convenience FilterNode creation functions.
98 namespace FilterWrappers
{
100 static TemporaryRef
<FilterNode
>
101 Unpremultiply(DrawTarget
* aDT
, FilterNode
* aInput
)
103 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::UNPREMULTIPLY
);
104 filter
->SetInput(IN_UNPREMULTIPLY_IN
, aInput
);
108 static TemporaryRef
<FilterNode
>
109 Premultiply(DrawTarget
* aDT
, FilterNode
* aInput
)
111 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::PREMULTIPLY
);
112 filter
->SetInput(IN_PREMULTIPLY_IN
, aInput
);
116 static TemporaryRef
<FilterNode
>
117 LinearRGBToSRGB(DrawTarget
* aDT
, FilterNode
* aInput
)
119 RefPtr
<FilterNode
> transfer
= aDT
->CreateFilter(FilterType::DISCRETE_TRANSFER
);
120 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R
, false);
121 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R
, glinearRGBTosRGBMap
, 256);
122 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G
, false);
123 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G
, glinearRGBTosRGBMap
, 256);
124 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B
, false);
125 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B
, glinearRGBTosRGBMap
, 256);
126 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A
, true);
127 transfer
->SetInput(IN_DISCRETE_TRANSFER_IN
, aInput
);
131 static TemporaryRef
<FilterNode
>
132 SRGBToLinearRGB(DrawTarget
* aDT
, FilterNode
* aInput
)
134 RefPtr
<FilterNode
> transfer
= aDT
->CreateFilter(FilterType::DISCRETE_TRANSFER
);
135 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R
, false);
136 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R
, gsRGBToLinearRGBMap
, 256);
137 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G
, false);
138 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G
, gsRGBToLinearRGBMap
, 256);
139 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B
, false);
140 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B
, gsRGBToLinearRGBMap
, 256);
141 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A
, true);
142 transfer
->SetInput(IN_DISCRETE_TRANSFER_IN
, aInput
);
146 static TemporaryRef
<FilterNode
>
147 Crop(DrawTarget
* aDT
, FilterNode
* aInputFilter
, const IntRect
& aRect
)
149 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::CROP
);
150 filter
->SetAttribute(ATT_CROP_RECT
, Rect(aRect
));
151 filter
->SetInput(IN_CROP_IN
, aInputFilter
);
155 static TemporaryRef
<FilterNode
>
156 Offset(DrawTarget
* aDT
, FilterNode
* aInputFilter
, const IntPoint
& aOffset
)
158 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::TRANSFORM
);
159 filter
->SetAttribute(ATT_TRANSFORM_MATRIX
, Matrix::Translation(aOffset
.x
, aOffset
.y
));
160 filter
->SetInput(IN_TRANSFORM_IN
, aInputFilter
);
164 static TemporaryRef
<FilterNode
>
165 GaussianBlur(DrawTarget
* aDT
, FilterNode
* aInputFilter
, const Size
& aStdDeviation
)
167 float stdX
= float(std::min(aStdDeviation
.width
, kMaxStdDeviation
));
168 float stdY
= float(std::min(aStdDeviation
.height
, kMaxStdDeviation
));
170 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::GAUSSIAN_BLUR
);
171 filter
->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION
, stdX
);
172 filter
->SetInput(IN_GAUSSIAN_BLUR_IN
, aInputFilter
);
175 RefPtr
<FilterNode
> filterH
= aDT
->CreateFilter(FilterType::DIRECTIONAL_BLUR
);
176 RefPtr
<FilterNode
> filterV
= aDT
->CreateFilter(FilterType::DIRECTIONAL_BLUR
);
177 filterH
->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION
, (uint32_t)BLUR_DIRECTION_X
);
178 filterH
->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION
, stdX
);
179 filterV
->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION
, (uint32_t)BLUR_DIRECTION_Y
);
180 filterV
->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION
, stdY
);
181 filterH
->SetInput(IN_DIRECTIONAL_BLUR_IN
, aInputFilter
);
182 filterV
->SetInput(IN_DIRECTIONAL_BLUR_IN
, filterH
);
186 static TemporaryRef
<FilterNode
>
187 Clear(DrawTarget
* aDT
)
189 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::FLOOD
);
190 filter
->SetAttribute(ATT_FLOOD_COLOR
, Color(0,0,0,0));
194 static TemporaryRef
<FilterNode
>
195 ForSurface(DrawTarget
* aDT
, SourceSurface
* aSurface
,
196 const IntPoint
& aSurfacePosition
)
198 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::TRANSFORM
);
199 filter
->SetAttribute(ATT_TRANSFORM_MATRIX
,
200 Matrix::Translation(aSurfacePosition
.x
, aSurfacePosition
.y
));
201 filter
->SetInput(IN_TRANSFORM_IN
, aSurface
);
205 static TemporaryRef
<FilterNode
>
206 ToAlpha(DrawTarget
* aDT
, FilterNode
* aInput
)
209 RefPtr
<FilterNode
> transfer
= aDT
->CreateFilter(FilterType::DISCRETE_TRANSFER
);
210 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R
, false);
211 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R
, &zero
, 1);
212 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G
, false);
213 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G
, &zero
, 1);
214 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B
, false);
215 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B
, &zero
, 1);
216 transfer
->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A
, true);
217 transfer
->SetInput(IN_DISCRETE_TRANSFER_IN
, aInput
);
223 // A class that wraps a FilterNode and handles conversion between different
224 // color models. Create FilterCachedColorModels with your original filter and
225 // the color model that this filter outputs in natively, and then call
226 // ->ForColorModel(colorModel) in order to get a FilterNode which outputs to
227 // the specified colorModel.
228 // Internally, this is achieved by wrapping the original FilterNode with
229 // conversion FilterNodes. These filter nodes are cached in such a way that no
230 // repeated or back-and-forth conversions happen.
231 class FilterCachedColorModels
234 NS_INLINE_DECL_REFCOUNTING(FilterCachedColorModels
)
235 // aFilter can be null. In that case, ForColorModel will return a non-null
236 // completely transparent filter for all color models.
237 FilterCachedColorModels(DrawTarget
* aDT
,
239 ColorModel aOriginalColorModel
);
241 // Get a FilterNode for the specified color model, guaranteed to be non-null.
242 TemporaryRef
<FilterNode
> ForColorModel(ColorModel aColorModel
);
244 AlphaModel
OriginalAlphaModel() const { return mOriginalColorModel
.mAlphaModel
; }
247 // Create the required FilterNode that will be cached by ForColorModel.
248 TemporaryRef
<FilterNode
> WrapForColorModel(ColorModel aColorModel
);
250 RefPtr
<DrawTarget
> mDT
;
251 ColorModel mOriginalColorModel
;
253 // This array is indexed by ColorModel::ToIndex.
254 RefPtr
<FilterNode
> mFilterForColorModel
[4];
256 ~FilterCachedColorModels() {}
259 FilterCachedColorModels::FilterCachedColorModels(DrawTarget
* aDT
,
261 ColorModel aOriginalColorModel
)
263 , mOriginalColorModel(aOriginalColorModel
)
266 mFilterForColorModel
[aOriginalColorModel
.ToIndex()] = aFilter
;
268 RefPtr
<FilterNode
> clear
= FilterWrappers::Clear(aDT
);
269 mFilterForColorModel
[0] = clear
;
270 mFilterForColorModel
[1] = clear
;
271 mFilterForColorModel
[2] = clear
;
272 mFilterForColorModel
[3] = clear
;
276 TemporaryRef
<FilterNode
>
277 FilterCachedColorModels::ForColorModel(ColorModel aColorModel
)
279 if (!mFilterForColorModel
[aColorModel
.ToIndex()]) {
280 mFilterForColorModel
[aColorModel
.ToIndex()] = WrapForColorModel(aColorModel
);
282 return mFilterForColorModel
[aColorModel
.ToIndex()];
285 TemporaryRef
<FilterNode
>
286 FilterCachedColorModels::WrapForColorModel(ColorModel aColorModel
)
288 // Convert one aspect at a time and recurse.
289 // Conversions between premultiplied / unpremultiplied color channels for the
290 // same color space can happen directly.
291 // Conversions between different color spaces can only happen on
292 // unpremultiplied color channels.
294 if (aColorModel
.mAlphaModel
== AlphaModel::Premultiplied
) {
295 RefPtr
<FilterNode
> unpre
=
296 ForColorModel(ColorModel(aColorModel
.mColorSpace
, AlphaModel::Unpremultiplied
));
297 return FilterWrappers::Premultiply(mDT
, unpre
);
300 MOZ_ASSERT(aColorModel
.mAlphaModel
== AlphaModel::Unpremultiplied
);
301 if (aColorModel
.mColorSpace
== mOriginalColorModel
.mColorSpace
) {
302 RefPtr
<FilterNode
> premultiplied
=
303 ForColorModel(ColorModel(aColorModel
.mColorSpace
, AlphaModel::Premultiplied
));
304 return FilterWrappers::Unpremultiply(mDT
, premultiplied
);
307 RefPtr
<FilterNode
> unpremultipliedOriginal
=
308 ForColorModel(ColorModel(mOriginalColorModel
.mColorSpace
, AlphaModel::Unpremultiplied
));
309 if (aColorModel
.mColorSpace
== ColorSpace::LinearRGB
) {
310 return FilterWrappers::SRGBToLinearRGB(mDT
, unpremultipliedOriginal
);
312 return FilterWrappers::LinearRGBToSRGB(mDT
, unpremultipliedOriginal
);
315 // Create a 4x5 color matrix for the different ways to specify color matrices
318 ComputeColorMatrix(uint32_t aColorMatrixType
, const nsTArray
<float>& aValues
,
319 float aOutMatrix
[20])
321 static const float identityMatrix
[] =
327 static const float luminanceToAlphaMatrix
[] =
331 0.2125f
, 0.7154f
, 0.0721f
, 0, 0 };
333 switch (aColorMatrixType
) {
335 case SVG_FECOLORMATRIX_TYPE_MATRIX
:
337 if (aValues
.Length() != 20)
338 return NS_ERROR_FAILURE
;
340 PodCopy(aOutMatrix
, aValues
.Elements(), 20);
344 case SVG_FECOLORMATRIX_TYPE_SATURATE
:
346 if (aValues
.Length() != 1)
347 return NS_ERROR_FAILURE
;
349 float s
= aValues
[0];
352 return NS_ERROR_FAILURE
;
354 PodCopy(aOutMatrix
, identityMatrix
, 20);
356 aOutMatrix
[0] = 0.213f
+ 0.787f
* s
;
357 aOutMatrix
[1] = 0.715f
- 0.715f
* s
;
358 aOutMatrix
[2] = 0.072f
- 0.072f
* s
;
360 aOutMatrix
[5] = 0.213f
- 0.213f
* s
;
361 aOutMatrix
[6] = 0.715f
+ 0.285f
* s
;
362 aOutMatrix
[7] = 0.072f
- 0.072f
* s
;
364 aOutMatrix
[10] = 0.213f
- 0.213f
* s
;
365 aOutMatrix
[11] = 0.715f
- 0.715f
* s
;
366 aOutMatrix
[12] = 0.072f
+ 0.928f
* s
;
371 case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE
:
373 if (aValues
.Length() != 1)
374 return NS_ERROR_FAILURE
;
376 PodCopy(aOutMatrix
, identityMatrix
, 20);
378 float hueRotateValue
= aValues
[0];
380 float c
= static_cast<float>(cos(hueRotateValue
* M_PI
/ 180));
381 float s
= static_cast<float>(sin(hueRotateValue
* M_PI
/ 180));
383 aOutMatrix
[0] = 0.213f
+ 0.787f
* c
- 0.213f
* s
;
384 aOutMatrix
[1] = 0.715f
- 0.715f
* c
- 0.715f
* s
;
385 aOutMatrix
[2] = 0.072f
- 0.072f
* c
+ 0.928f
* s
;
387 aOutMatrix
[5] = 0.213f
- 0.213f
* c
+ 0.143f
* s
;
388 aOutMatrix
[6] = 0.715f
+ 0.285f
* c
+ 0.140f
* s
;
389 aOutMatrix
[7] = 0.072f
- 0.072f
* c
- 0.283f
* s
;
391 aOutMatrix
[10] = 0.213f
- 0.213f
* c
- 0.787f
* s
;
392 aOutMatrix
[11] = 0.715f
- 0.715f
* c
+ 0.715f
* s
;
393 aOutMatrix
[12] = 0.072f
+ 0.928f
* c
+ 0.072f
* s
;
398 case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA
:
400 PodCopy(aOutMatrix
, luminanceToAlphaMatrix
, 20);
404 case SVG_FECOLORMATRIX_TYPE_SEPIA
:
406 if (aValues
.Length() != 1)
407 return NS_ERROR_FAILURE
;
409 float amount
= aValues
[0];
411 if (amount
< 0 || amount
> 1)
412 return NS_ERROR_FAILURE
;
414 PodCopy(aOutMatrix
, identityMatrix
, 20);
416 float s
= 1 - amount
;
418 aOutMatrix
[0] = 0.393f
+ 0.607f
* s
;
419 aOutMatrix
[1] = 0.769f
- 0.769f
* s
;
420 aOutMatrix
[2] = 0.189f
- 0.189f
* s
;
422 aOutMatrix
[5] = 0.349f
- 0.349f
* s
;
423 aOutMatrix
[6] = 0.686f
+ 0.314f
* s
;
424 aOutMatrix
[7] = 0.168f
- 0.168f
* s
;
426 aOutMatrix
[10] = 0.272f
- 0.272f
* s
;
427 aOutMatrix
[11] = 0.534f
- 0.534f
* s
;
428 aOutMatrix
[12] = 0.131f
+ 0.869f
* s
;
434 return NS_ERROR_FAILURE
;
442 DisableAllTransfers(FilterNode
* aTransferFilterNode
)
444 aTransferFilterNode
->SetAttribute(ATT_TRANSFER_DISABLE_R
, true);
445 aTransferFilterNode
->SetAttribute(ATT_TRANSFER_DISABLE_G
, true);
446 aTransferFilterNode
->SetAttribute(ATT_TRANSFER_DISABLE_B
, true);
447 aTransferFilterNode
->SetAttribute(ATT_TRANSFER_DISABLE_A
, true);
450 // Called for one channel at a time.
451 // This function creates the required FilterNodes on demand and tries to
452 // merge conversions of different channels into the same FilterNode if
454 // There's a mismatch between the way SVG and the Moz2D API handle transfer
455 // functions: In SVG, it's possible to specify a different transfer function
456 // type for each color channel, but in Moz2D, a given transfer function type
457 // applies to all color channels.
459 // @param aFunctionAttributes The attributes of the transfer function for this
461 // @param aChannel The color channel that this function applies to, where
462 // 0 = red, 1 = green, 2 = blue, 3 = alpha
463 // @param aDT The DrawTarget that the FilterNodes should be created for.
464 // @param aTableTransfer Existing FilterNode holders (which may still be
465 // null) that the resulting FilterNodes from this
466 // function will be stored in.
469 ConvertComponentTransferFunctionToFilter(const AttributeMap
& aFunctionAttributes
,
472 RefPtr
<FilterNode
>& aTableTransfer
,
473 RefPtr
<FilterNode
>& aDiscreteTransfer
,
474 RefPtr
<FilterNode
>& aLinearTransfer
,
475 RefPtr
<FilterNode
>& aGammaTransfer
)
477 static const TransferAtts disableAtt
[4] = {
478 ATT_TRANSFER_DISABLE_R
,
479 ATT_TRANSFER_DISABLE_G
,
480 ATT_TRANSFER_DISABLE_B
,
481 ATT_TRANSFER_DISABLE_A
484 RefPtr
<FilterNode
> filter
;
486 uint32_t type
= aFunctionAttributes
.GetUint(eComponentTransferFunctionType
);
489 case SVG_FECOMPONENTTRANSFER_TYPE_TABLE
:
491 const nsTArray
<float>& tableValues
=
492 aFunctionAttributes
.GetFloats(eComponentTransferFunctionTableValues
);
493 if (tableValues
.Length() < 2)
496 if (!aTableTransfer
) {
497 aTableTransfer
= aDT
->CreateFilter(FilterType::TABLE_TRANSFER
);
498 DisableAllTransfers(aTableTransfer
);
500 filter
= aTableTransfer
;
501 static const TableTransferAtts tableAtt
[4] = {
502 ATT_TABLE_TRANSFER_TABLE_R
,
503 ATT_TABLE_TRANSFER_TABLE_G
,
504 ATT_TABLE_TRANSFER_TABLE_B
,
505 ATT_TABLE_TRANSFER_TABLE_A
507 filter
->SetAttribute(disableAtt
[aChannel
], false);
508 filter
->SetAttribute(tableAtt
[aChannel
], &tableValues
[0], tableValues
.Length());
512 case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE
:
514 const nsTArray
<float>& tableValues
=
515 aFunctionAttributes
.GetFloats(eComponentTransferFunctionTableValues
);
516 if (tableValues
.Length() < 1)
519 if (!aDiscreteTransfer
) {
520 aDiscreteTransfer
= aDT
->CreateFilter(FilterType::DISCRETE_TRANSFER
);
521 DisableAllTransfers(aDiscreteTransfer
);
523 filter
= aDiscreteTransfer
;
524 static const DiscreteTransferAtts tableAtt
[4] = {
525 ATT_DISCRETE_TRANSFER_TABLE_R
,
526 ATT_DISCRETE_TRANSFER_TABLE_G
,
527 ATT_DISCRETE_TRANSFER_TABLE_B
,
528 ATT_DISCRETE_TRANSFER_TABLE_A
530 filter
->SetAttribute(disableAtt
[aChannel
], false);
531 filter
->SetAttribute(tableAtt
[aChannel
], &tableValues
[0], tableValues
.Length());
536 case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR
:
538 static const LinearTransferAtts slopeAtt
[4] = {
539 ATT_LINEAR_TRANSFER_SLOPE_R
,
540 ATT_LINEAR_TRANSFER_SLOPE_G
,
541 ATT_LINEAR_TRANSFER_SLOPE_B
,
542 ATT_LINEAR_TRANSFER_SLOPE_A
544 static const LinearTransferAtts interceptAtt
[4] = {
545 ATT_LINEAR_TRANSFER_INTERCEPT_R
,
546 ATT_LINEAR_TRANSFER_INTERCEPT_G
,
547 ATT_LINEAR_TRANSFER_INTERCEPT_B
,
548 ATT_LINEAR_TRANSFER_INTERCEPT_A
550 if (!aLinearTransfer
) {
551 aLinearTransfer
= aDT
->CreateFilter(FilterType::LINEAR_TRANSFER
);
552 DisableAllTransfers(aLinearTransfer
);
554 filter
= aLinearTransfer
;
555 filter
->SetAttribute(disableAtt
[aChannel
], false);
556 float slope
= aFunctionAttributes
.GetFloat(eComponentTransferFunctionSlope
);
557 float intercept
= aFunctionAttributes
.GetFloat(eComponentTransferFunctionIntercept
);
558 filter
->SetAttribute(slopeAtt
[aChannel
], slope
);
559 filter
->SetAttribute(interceptAtt
[aChannel
], intercept
);
563 case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA
:
565 static const GammaTransferAtts amplitudeAtt
[4] = {
566 ATT_GAMMA_TRANSFER_AMPLITUDE_R
,
567 ATT_GAMMA_TRANSFER_AMPLITUDE_G
,
568 ATT_GAMMA_TRANSFER_AMPLITUDE_B
,
569 ATT_GAMMA_TRANSFER_AMPLITUDE_A
571 static const GammaTransferAtts exponentAtt
[4] = {
572 ATT_GAMMA_TRANSFER_EXPONENT_R
,
573 ATT_GAMMA_TRANSFER_EXPONENT_G
,
574 ATT_GAMMA_TRANSFER_EXPONENT_B
,
575 ATT_GAMMA_TRANSFER_EXPONENT_A
577 static const GammaTransferAtts offsetAtt
[4] = {
578 ATT_GAMMA_TRANSFER_OFFSET_R
,
579 ATT_GAMMA_TRANSFER_OFFSET_G
,
580 ATT_GAMMA_TRANSFER_OFFSET_B
,
581 ATT_GAMMA_TRANSFER_OFFSET_A
583 if (!aGammaTransfer
) {
584 aGammaTransfer
= aDT
->CreateFilter(FilterType::GAMMA_TRANSFER
);
585 DisableAllTransfers(aGammaTransfer
);
587 filter
= aGammaTransfer
;
588 filter
->SetAttribute(disableAtt
[aChannel
], false);
589 float amplitude
= aFunctionAttributes
.GetFloat(eComponentTransferFunctionAmplitude
);
590 float exponent
= aFunctionAttributes
.GetFloat(eComponentTransferFunctionExponent
);
591 float offset
= aFunctionAttributes
.GetFloat(eComponentTransferFunctionOffset
);
592 filter
->SetAttribute(amplitudeAtt
[aChannel
], amplitude
);
593 filter
->SetAttribute(exponentAtt
[aChannel
], exponent
);
594 filter
->SetAttribute(offsetAtt
[aChannel
], offset
);
598 case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY
:
604 const int32_t kMorphologyMaxRadius
= 100000;
606 // Handle the different primitive description types and create the necessary
607 // FilterNode(s) for each.
608 // Returns nullptr for invalid filter primitives. This should be interpreted as
609 // transparent black by the caller.
610 // aSourceRegions contains the filter primitive subregions of the source
611 // primitives; only needed for eTile primitives.
612 // aInputImages carries additional surfaces that are used by eImage primitives.
613 static TemporaryRef
<FilterNode
>
614 FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription
& aDescription
,
616 nsTArray
<RefPtr
<FilterNode
> >& aSources
,
617 nsTArray
<IntRect
>& aSourceRegions
,
618 nsTArray
<RefPtr
<SourceSurface
>>& aInputImages
)
620 const AttributeMap
& atts
= aDescription
.Attributes();
621 switch (aDescription
.Type()) {
623 case PrimitiveType::Empty
:
626 case PrimitiveType::Blend
:
628 uint32_t mode
= atts
.GetUint(eBlendBlendmode
);
629 RefPtr
<FilterNode
> filter
;
630 if (mode
== SVG_FEBLEND_MODE_UNKNOWN
) {
633 if (mode
== SVG_FEBLEND_MODE_NORMAL
) {
634 filter
= aDT
->CreateFilter(FilterType::COMPOSITE
);
635 filter
->SetInput(IN_COMPOSITE_IN_START
, aSources
[1]);
636 filter
->SetInput(IN_COMPOSITE_IN_START
+ 1, aSources
[0]);
638 filter
= aDT
->CreateFilter(FilterType::BLEND
);
639 static const uint8_t blendModes
[SVG_FEBLEND_MODE_LIGHTEN
+ 1] = {
647 filter
->SetAttribute(ATT_BLEND_BLENDMODE
, (uint32_t)blendModes
[mode
]);
648 filter
->SetInput(IN_BLEND_IN
, aSources
[0]);
649 filter
->SetInput(IN_BLEND_IN2
, aSources
[1]);
654 case PrimitiveType::ColorMatrix
:
656 float colorMatrix
[20];
657 uint32_t type
= atts
.GetUint(eColorMatrixType
);
658 const nsTArray
<float>& values
= atts
.GetFloats(eColorMatrixValues
);
659 if (NS_FAILED(ComputeColorMatrix(type
, values
, colorMatrix
))) {
662 Matrix5x4
matrix(colorMatrix
[0], colorMatrix
[5], colorMatrix
[10], colorMatrix
[15],
663 colorMatrix
[1], colorMatrix
[6], colorMatrix
[11], colorMatrix
[16],
664 colorMatrix
[2], colorMatrix
[7], colorMatrix
[12], colorMatrix
[17],
665 colorMatrix
[3], colorMatrix
[8], colorMatrix
[13], colorMatrix
[18],
666 colorMatrix
[4], colorMatrix
[9], colorMatrix
[14], colorMatrix
[19]);
667 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::COLOR_MATRIX
);
668 filter
->SetAttribute(ATT_COLOR_MATRIX_MATRIX
, matrix
);
669 filter
->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE
, (uint32_t)ALPHA_MODE_STRAIGHT
);
670 filter
->SetInput(IN_COLOR_MATRIX_IN
, aSources
[0]);
674 case PrimitiveType::Morphology
:
676 Size radii
= atts
.GetSize(eMorphologyRadii
);
677 int32_t rx
= radii
.width
;
678 int32_t ry
= radii
.height
;
679 if (rx
< 0 || ry
< 0) {
680 // XXX SVGContentUtils::ReportToConsole()
683 if (rx
== 0 && ry
== 0) {
687 // Clamp radii to prevent completely insane values:
688 rx
= std::min(rx
, kMorphologyMaxRadius
);
689 ry
= std::min(ry
, kMorphologyMaxRadius
);
691 MorphologyOperator op
= atts
.GetUint(eMorphologyOperator
) == SVG_OPERATOR_ERODE
?
692 MORPHOLOGY_OPERATOR_ERODE
: MORPHOLOGY_OPERATOR_DILATE
;
694 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::MORPHOLOGY
);
695 filter
->SetAttribute(ATT_MORPHOLOGY_RADII
, IntSize(rx
, ry
));
696 filter
->SetAttribute(ATT_MORPHOLOGY_OPERATOR
, (uint32_t)op
);
697 filter
->SetInput(IN_MORPHOLOGY_IN
, aSources
[0]);
701 case PrimitiveType::Flood
:
703 Color color
= atts
.GetColor(eFloodColor
);
704 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::FLOOD
);
705 filter
->SetAttribute(ATT_FLOOD_COLOR
, color
);
709 case PrimitiveType::Tile
:
711 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::TILE
);
712 filter
->SetAttribute(ATT_TILE_SOURCE_RECT
, aSourceRegions
[0]);
713 filter
->SetInput(IN_TILE_IN
, aSources
[0]);
717 case PrimitiveType::ComponentTransfer
:
719 RefPtr
<FilterNode
> filters
[4]; // one for each FILTER_*_TRANSFER type
720 static const AttributeName componentFunctionNames
[4] = {
721 eComponentTransferFunctionR
,
722 eComponentTransferFunctionG
,
723 eComponentTransferFunctionB
,
724 eComponentTransferFunctionA
726 for (int32_t i
= 0; i
< 4; i
++) {
727 AttributeMap functionAttributes
=
728 atts
.GetAttributeMap(componentFunctionNames
[i
]);
729 ConvertComponentTransferFunctionToFilter(functionAttributes
, i
, aDT
,
730 filters
[0], filters
[1], filters
[2], filters
[3]);
733 // Connect all used filters nodes.
734 RefPtr
<FilterNode
> lastFilter
= aSources
[0];
735 for (int32_t i
= 0; i
< 4; i
++) {
737 filters
[i
]->SetInput(0, lastFilter
);
738 lastFilter
= filters
[i
];
745 case PrimitiveType::ConvolveMatrix
:
747 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::CONVOLVE_MATRIX
);
748 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE
, atts
.GetIntSize(eConvolveMatrixKernelSize
));
749 const nsTArray
<float>& matrix
= atts
.GetFloats(eConvolveMatrixKernelMatrix
);
750 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX
,
751 matrix
.Elements(), matrix
.Length());
752 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR
,
753 atts
.GetFloat(eConvolveMatrixDivisor
));
754 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS
,
755 atts
.GetFloat(eConvolveMatrixBias
));
756 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET
,
757 atts
.GetIntPoint(eConvolveMatrixTarget
));
758 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT
,
760 uint32_t edgeMode
= atts
.GetUint(eConvolveMatrixEdgeMode
);
761 static const uint8_t edgeModes
[SVG_EDGEMODE_NONE
+1] = {
762 EDGE_MODE_NONE
, // SVG_EDGEMODE_UNKNOWN
763 EDGE_MODE_DUPLICATE
, // SVG_EDGEMODE_DUPLICATE
764 EDGE_MODE_WRAP
, // SVG_EDGEMODE_WRAP
765 EDGE_MODE_NONE
// SVG_EDGEMODE_NONE
767 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE
, (uint32_t)edgeModes
[edgeMode
]);
768 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH
,
769 atts
.GetSize(eConvolveMatrixKernelUnitLength
));
770 filter
->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA
,
771 atts
.GetBool(eConvolveMatrixPreserveAlpha
));
772 filter
->SetInput(IN_CONVOLVE_MATRIX_IN
, aSources
[0]);
776 case PrimitiveType::Offset
:
778 return FilterWrappers::Offset(aDT
, aSources
[0],
779 atts
.GetIntPoint(eOffsetOffset
));
782 case PrimitiveType::DisplacementMap
:
784 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::DISPLACEMENT_MAP
);
785 filter
->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE
,
786 atts
.GetFloat(eDisplacementMapScale
));
787 static const uint8_t channel
[SVG_CHANNEL_A
+1] = {
788 COLOR_CHANNEL_R
, // SVG_CHANNEL_UNKNOWN
789 COLOR_CHANNEL_R
, // SVG_CHANNEL_R
790 COLOR_CHANNEL_G
, // SVG_CHANNEL_G
791 COLOR_CHANNEL_B
, // SVG_CHANNEL_B
792 COLOR_CHANNEL_A
// SVG_CHANNEL_A
794 filter
->SetAttribute(ATT_DISPLACEMENT_MAP_X_CHANNEL
,
795 (uint32_t)channel
[atts
.GetUint(eDisplacementMapXChannel
)]);
796 filter
->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL
,
797 (uint32_t)channel
[atts
.GetUint(eDisplacementMapYChannel
)]);
798 filter
->SetInput(IN_DISPLACEMENT_MAP_IN
, aSources
[0]);
799 filter
->SetInput(IN_DISPLACEMENT_MAP_IN2
, aSources
[1]);
803 case PrimitiveType::Turbulence
:
805 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::TURBULENCE
);
806 filter
->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY
,
807 atts
.GetSize(eTurbulenceBaseFrequency
));
808 filter
->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES
,
809 atts
.GetUint(eTurbulenceNumOctaves
));
810 filter
->SetAttribute(ATT_TURBULENCE_STITCHABLE
,
811 atts
.GetBool(eTurbulenceStitchable
));
812 filter
->SetAttribute(ATT_TURBULENCE_SEED
,
813 (uint32_t)atts
.GetFloat(eTurbulenceSeed
));
814 static const uint8_t type
[SVG_TURBULENCE_TYPE_TURBULENCE
+1] = {
815 TURBULENCE_TYPE_FRACTAL_NOISE
, // SVG_TURBULENCE_TYPE_UNKNOWN
816 TURBULENCE_TYPE_FRACTAL_NOISE
, // SVG_TURBULENCE_TYPE_FRACTALNOISE
817 TURBULENCE_TYPE_TURBULENCE
// SVG_TURBULENCE_TYPE_TURBULENCE
819 filter
->SetAttribute(ATT_TURBULENCE_TYPE
,
820 (uint32_t)type
[atts
.GetUint(eTurbulenceType
)]);
821 filter
->SetAttribute(ATT_TURBULENCE_RECT
,
822 aDescription
.PrimitiveSubregion() - atts
.GetIntPoint(eTurbulenceOffset
));
823 return FilterWrappers::Offset(aDT
, filter
, atts
.GetIntPoint(eTurbulenceOffset
));
826 case PrimitiveType::Composite
:
828 RefPtr
<FilterNode
> filter
;
829 uint32_t op
= atts
.GetUint(eCompositeOperator
);
830 if (op
== SVG_FECOMPOSITE_OPERATOR_ARITHMETIC
) {
831 filter
= aDT
->CreateFilter(FilterType::ARITHMETIC_COMBINE
);
832 const nsTArray
<float>& coefficients
= atts
.GetFloats(eCompositeCoefficients
);
833 filter
->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS
,
834 coefficients
.Elements(), coefficients
.Length());
835 filter
->SetInput(IN_ARITHMETIC_COMBINE_IN
, aSources
[0]);
836 filter
->SetInput(IN_ARITHMETIC_COMBINE_IN2
, aSources
[1]);
838 filter
= aDT
->CreateFilter(FilterType::COMPOSITE
);
839 static const uint8_t operators
[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC
] = {
840 COMPOSITE_OPERATOR_OVER
, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
841 COMPOSITE_OPERATOR_OVER
, // SVG_FECOMPOSITE_OPERATOR_OVER
842 COMPOSITE_OPERATOR_IN
, // SVG_FECOMPOSITE_OPERATOR_IN
843 COMPOSITE_OPERATOR_OUT
, // SVG_FECOMPOSITE_OPERATOR_OUT
844 COMPOSITE_OPERATOR_ATOP
, // SVG_FECOMPOSITE_OPERATOR_ATOP
845 COMPOSITE_OPERATOR_XOR
// SVG_FECOMPOSITE_OPERATOR_XOR
847 filter
->SetAttribute(ATT_COMPOSITE_OPERATOR
, (uint32_t)operators
[op
]);
848 filter
->SetInput(IN_COMPOSITE_IN_START
, aSources
[1]);
849 filter
->SetInput(IN_COMPOSITE_IN_START
+ 1, aSources
[0]);
854 case PrimitiveType::Merge
:
856 if (aSources
.Length() == 0) {
859 if (aSources
.Length() == 1) {
862 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::COMPOSITE
);
863 filter
->SetAttribute(ATT_COMPOSITE_OPERATOR
, (uint32_t)COMPOSITE_OPERATOR_OVER
);
864 for (size_t i
= 0; i
< aSources
.Length(); i
++) {
865 filter
->SetInput(IN_COMPOSITE_IN_START
+ i
, aSources
[i
]);
870 case PrimitiveType::GaussianBlur
:
872 return FilterWrappers::GaussianBlur(aDT
, aSources
[0],
873 atts
.GetSize(eGaussianBlurStdDeviation
));
876 case PrimitiveType::DropShadow
:
878 RefPtr
<FilterNode
> alpha
= FilterWrappers::ToAlpha(aDT
, aSources
[0]);
879 RefPtr
<FilterNode
> blur
= FilterWrappers::GaussianBlur(aDT
, alpha
,
880 atts
.GetSize(eDropShadowStdDeviation
));
881 RefPtr
<FilterNode
> offsetBlur
= FilterWrappers::Offset(aDT
, blur
,
882 atts
.GetIntPoint(eDropShadowOffset
));
883 RefPtr
<FilterNode
> flood
= aDT
->CreateFilter(FilterType::FLOOD
);
884 Color color
= atts
.GetColor(eDropShadowColor
);
885 if (aDescription
.InputColorSpace(0) == ColorSpace::LinearRGB
) {
886 color
= Color(gsRGBToLinearRGBMap
[uint8_t(color
.r
* 255)],
887 gsRGBToLinearRGBMap
[uint8_t(color
.g
* 255)],
888 gsRGBToLinearRGBMap
[uint8_t(color
.b
* 255)],
891 flood
->SetAttribute(ATT_FLOOD_COLOR
, color
);
893 RefPtr
<FilterNode
> composite
= aDT
->CreateFilter(FilterType::COMPOSITE
);
894 composite
->SetAttribute(ATT_COMPOSITE_OPERATOR
, (uint32_t)COMPOSITE_OPERATOR_IN
);
895 composite
->SetInput(IN_COMPOSITE_IN_START
, offsetBlur
);
896 composite
->SetInput(IN_COMPOSITE_IN_START
+ 1, flood
);
898 RefPtr
<FilterNode
> filter
= aDT
->CreateFilter(FilterType::COMPOSITE
);
899 filter
->SetAttribute(ATT_COMPOSITE_OPERATOR
, (uint32_t)COMPOSITE_OPERATOR_OVER
);
900 filter
->SetInput(IN_COMPOSITE_IN_START
, composite
);
901 filter
->SetInput(IN_COMPOSITE_IN_START
+ 1, aSources
[0]);
905 case PrimitiveType::DiffuseLighting
:
906 case PrimitiveType::SpecularLighting
:
909 aDescription
.Type() == PrimitiveType::SpecularLighting
;
911 AttributeMap lightAttributes
= atts
.GetAttributeMap(eLightingLight
);
913 if (lightAttributes
.GetUint(eLightType
) == eLightTypeNone
) {
917 enum { POINT
= 0, SPOT
, DISTANT
} lightType
= POINT
;
919 switch (lightAttributes
.GetUint(eLightType
)) {
920 case eLightTypePoint
: lightType
= POINT
; break;
921 case eLightTypeSpot
: lightType
= SPOT
; break;
922 case eLightTypeDistant
: lightType
= DISTANT
; break;
925 static const FilterType filterType
[2][DISTANT
+1] = {
926 { FilterType::POINT_DIFFUSE
, FilterType::SPOT_DIFFUSE
, FilterType::DISTANT_DIFFUSE
},
927 { FilterType::POINT_SPECULAR
, FilterType::SPOT_SPECULAR
, FilterType::DISTANT_SPECULAR
}
929 RefPtr
<FilterNode
> filter
=
930 aDT
->CreateFilter(filterType
[isSpecular
][lightType
]);
932 filter
->SetAttribute(ATT_LIGHTING_COLOR
,
933 atts
.GetColor(eLightingColor
));
934 filter
->SetAttribute(ATT_LIGHTING_SURFACE_SCALE
,
935 atts
.GetFloat(eLightingSurfaceScale
));
936 filter
->SetAttribute(ATT_LIGHTING_KERNEL_UNIT_LENGTH
,
937 atts
.GetSize(eLightingKernelUnitLength
));
940 filter
->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT
,
941 atts
.GetFloat(eSpecularLightingSpecularConstant
));
942 filter
->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT
,
943 atts
.GetFloat(eSpecularLightingSpecularExponent
));
945 filter
->SetAttribute(ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT
,
946 atts
.GetFloat(eDiffuseLightingDiffuseConstant
));
951 filter
->SetAttribute(ATT_POINT_LIGHT_POSITION
,
952 lightAttributes
.GetPoint3D(ePointLightPosition
));
955 filter
->SetAttribute(ATT_SPOT_LIGHT_POSITION
,
956 lightAttributes
.GetPoint3D(eSpotLightPosition
));
957 filter
->SetAttribute(ATT_SPOT_LIGHT_POINTS_AT
,
958 lightAttributes
.GetPoint3D(eSpotLightPointsAt
));
959 filter
->SetAttribute(ATT_SPOT_LIGHT_FOCUS
,
960 lightAttributes
.GetFloat(eSpotLightFocus
));
961 filter
->SetAttribute(ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE
,
962 lightAttributes
.GetFloat(eSpotLightLimitingConeAngle
));
965 filter
->SetAttribute(ATT_DISTANT_LIGHT_AZIMUTH
,
966 lightAttributes
.GetFloat(eDistantLightAzimuth
));
967 filter
->SetAttribute(ATT_DISTANT_LIGHT_ELEVATION
,
968 lightAttributes
.GetFloat(eDistantLightElevation
));
972 filter
->SetInput(IN_LIGHTING_IN
, aSources
[0]);
977 case PrimitiveType::Image
:
979 Matrix TM
= atts
.GetMatrix(eImageTransform
);
980 if (!TM
.Determinant()) {
984 // Pull the image from the additional image list using the index that's
985 // stored in the primitive description.
986 RefPtr
<SourceSurface
> inputImage
=
987 aInputImages
[atts
.GetUint(eImageInputIndex
)];
989 RefPtr
<FilterNode
> transform
= aDT
->CreateFilter(FilterType::TRANSFORM
);
990 transform
->SetInput(IN_TRANSFORM_IN
, inputImage
);
991 transform
->SetAttribute(ATT_TRANSFORM_MATRIX
, TM
);
992 transform
->SetAttribute(ATT_TRANSFORM_FILTER
, atts
.GetUint(eImageFilter
));
996 case PrimitiveType::ToAlpha
:
998 return FilterWrappers::ToAlpha(aDT
, aSources
[0]);
1006 template<typename T
>
1008 ElementForIndex(int32_t aIndex
,
1009 const nsTArray
<T
>& aPrimitiveElements
,
1010 const T
& aSourceGraphicElement
,
1011 const T
& aFillPaintElement
,
1012 const T
& aStrokePaintElement
)
1015 case FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic
:
1016 case FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha
:
1017 return aSourceGraphicElement
;
1018 case FilterPrimitiveDescription::kPrimitiveIndexFillPaint
:
1019 return aFillPaintElement
;
1020 case FilterPrimitiveDescription::kPrimitiveIndexStrokePaint
:
1021 return aStrokePaintElement
;
1023 MOZ_ASSERT(aIndex
>= 0, "bad index");
1024 return aPrimitiveElements
[aIndex
];
1029 InputAlphaModelForPrimitive(const FilterPrimitiveDescription
& aDescr
,
1030 int32_t aInputIndex
,
1031 AlphaModel aOriginalAlphaModel
)
1033 switch (aDescr
.Type()) {
1034 case PrimitiveType::Tile
:
1035 case PrimitiveType::Offset
:
1036 case PrimitiveType::ToAlpha
:
1037 return aOriginalAlphaModel
;
1039 case PrimitiveType::ColorMatrix
:
1040 case PrimitiveType::ComponentTransfer
:
1041 return AlphaModel::Unpremultiplied
;
1043 case PrimitiveType::DisplacementMap
:
1044 return aInputIndex
== 0 ?
1045 AlphaModel::Premultiplied
: AlphaModel::Unpremultiplied
;
1047 case PrimitiveType::ConvolveMatrix
:
1048 return aDescr
.Attributes().GetBool(eConvolveMatrixPreserveAlpha
) ?
1049 AlphaModel::Unpremultiplied
: AlphaModel::Premultiplied
;
1052 return AlphaModel::Premultiplied
;
1057 OutputAlphaModelForPrimitive(const FilterPrimitiveDescription
& aDescr
,
1058 const nsTArray
<AlphaModel
>& aInputAlphaModels
)
1060 if (aInputAlphaModels
.Length()) {
1061 // For filters with inputs, the output is premultiplied if and only if the
1062 // first input is premultiplied.
1063 return InputAlphaModelForPrimitive(aDescr
, 0, aInputAlphaModels
[0]);
1066 // All filters without inputs produce premultiplied alpha.
1067 return AlphaModel::Premultiplied
;
1070 // Returns the output FilterNode, in premultiplied sRGB space.
1071 static TemporaryRef
<FilterNode
>
1072 FilterNodeGraphFromDescription(DrawTarget
* aDT
,
1073 const FilterDescription
& aFilter
,
1074 const Rect
& aResultNeededRect
,
1075 SourceSurface
* aSourceGraphic
,
1076 const IntRect
& aSourceGraphicRect
,
1077 SourceSurface
* aFillPaint
,
1078 const IntRect
& aFillPaintRect
,
1079 SourceSurface
* aStrokePaint
,
1080 const IntRect
& aStrokePaintRect
,
1081 nsTArray
<RefPtr
<SourceSurface
>>& aAdditionalImages
)
1083 const nsTArray
<FilterPrimitiveDescription
>& primitives
= aFilter
.mPrimitives
;
1085 Rect
resultNeededRect(aResultNeededRect
);
1086 resultNeededRect
.RoundOut();
1088 RefPtr
<FilterCachedColorModels
> sourceFilters
[4];
1089 nsTArray
<RefPtr
<FilterCachedColorModels
> > primitiveFilters
;
1091 for (size_t i
= 0; i
< primitives
.Length(); ++i
) {
1092 const FilterPrimitiveDescription
& descr
= primitives
[i
];
1094 nsTArray
<RefPtr
<FilterNode
> > inputFilterNodes
;
1095 nsTArray
<IntRect
> inputSourceRects
;
1096 nsTArray
<AlphaModel
> inputAlphaModels
;
1098 for (size_t j
= 0; j
< descr
.NumberOfInputs(); j
++) {
1100 int32_t inputIndex
= descr
.InputPrimitiveIndex(j
);
1101 if (inputIndex
< 0) {
1102 inputSourceRects
.AppendElement(descr
.FilterSpaceBounds());
1104 inputSourceRects
.AppendElement(primitives
[inputIndex
].PrimitiveSubregion());
1107 RefPtr
<FilterCachedColorModels
> inputFilter
;
1108 if (inputIndex
>= 0) {
1109 MOZ_ASSERT(inputIndex
< (int64_t)primitiveFilters
.Length(), "out-of-bounds input index!");
1110 inputFilter
= primitiveFilters
[inputIndex
];
1111 MOZ_ASSERT(inputFilter
, "Referred to input filter that comes after the current one?");
1113 int32_t sourceIndex
= -inputIndex
- 1;
1114 MOZ_ASSERT(sourceIndex
>= 0, "invalid source index");
1115 MOZ_ASSERT(sourceIndex
< 4, "invalid source index");
1116 inputFilter
= sourceFilters
[sourceIndex
];
1118 RefPtr
<FilterNode
> sourceFilterNode
;
1120 nsTArray
<SourceSurface
*> primitiveSurfaces
;
1121 nsTArray
<IntRect
> primitiveSurfaceRects
;
1122 RefPtr
<SourceSurface
> surf
=
1123 ElementForIndex(inputIndex
, primitiveSurfaces
,
1124 aSourceGraphic
, aFillPaint
, aStrokePaint
);
1125 IntRect surfaceRect
=
1126 ElementForIndex(inputIndex
, primitiveSurfaceRects
,
1127 aSourceGraphicRect
, aFillPaintRect
, aStrokePaintRect
);
1129 IntPoint offset
= surfaceRect
.TopLeft();
1130 sourceFilterNode
= FilterWrappers::ForSurface(aDT
, surf
, offset
);
1132 // Clip the original SourceGraphic to the first filter region if the
1133 // surface isn't already sized appropriately.
1134 if ((inputIndex
== FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic
||
1135 inputIndex
== FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha
) &&
1136 !descr
.FilterSpaceBounds().Contains(aSourceGraphicRect
)) {
1138 FilterWrappers::Crop(aDT
, sourceFilterNode
, descr
.FilterSpaceBounds());
1141 if (inputIndex
== FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha
) {
1142 sourceFilterNode
= FilterWrappers::ToAlpha(aDT
, sourceFilterNode
);
1146 inputFilter
= new FilterCachedColorModels(aDT
, sourceFilterNode
,
1147 ColorModel::PremulSRGB());
1148 sourceFilters
[sourceIndex
] = inputFilter
;
1151 MOZ_ASSERT(inputFilter
);
1153 AlphaModel inputAlphaModel
=
1154 InputAlphaModelForPrimitive(descr
, j
, inputFilter
->OriginalAlphaModel());
1155 inputAlphaModels
.AppendElement(inputAlphaModel
);
1156 ColorModel
inputColorModel(descr
.InputColorSpace(j
), inputAlphaModel
);
1157 inputFilterNodes
.AppendElement(inputFilter
->ForColorModel(inputColorModel
));
1160 RefPtr
<FilterNode
> primitiveFilterNode
=
1161 FilterNodeFromPrimitiveDescription(descr
, aDT
, inputFilterNodes
,
1162 inputSourceRects
, aAdditionalImages
);
1164 if (primitiveFilterNode
) {
1165 primitiveFilterNode
=
1166 FilterWrappers::Crop(aDT
, primitiveFilterNode
, descr
.PrimitiveSubregion());
1169 ColorModel
outputColorModel(descr
.OutputColorSpace(),
1170 OutputAlphaModelForPrimitive(descr
, inputAlphaModels
));
1171 RefPtr
<FilterCachedColorModels
> primitiveFilter
=
1172 new FilterCachedColorModels(aDT
, primitiveFilterNode
, outputColorModel
);
1174 primitiveFilters
.AppendElement(primitiveFilter
);
1177 return primitiveFilters
.LastElement()->ForColorModel(ColorModel::PremulSRGB());
1183 FilterSupport::RenderFilterDescription(DrawTarget
* aDT
,
1184 const FilterDescription
& aFilter
,
1185 const Rect
& aRenderRect
,
1186 SourceSurface
* aSourceGraphic
,
1187 const IntRect
& aSourceGraphicRect
,
1188 SourceSurface
* aFillPaint
,
1189 const IntRect
& aFillPaintRect
,
1190 SourceSurface
* aStrokePaint
,
1191 const IntRect
& aStrokePaintRect
,
1192 nsTArray
<RefPtr
<SourceSurface
>>& aAdditionalImages
)
1194 RefPtr
<FilterNode
> resultFilter
=
1195 FilterNodeGraphFromDescription(aDT
, aFilter
, aRenderRect
,
1196 aSourceGraphic
, aSourceGraphicRect
, aFillPaint
, aFillPaintRect
,
1197 aStrokePaint
, aStrokePaintRect
, aAdditionalImages
);
1199 aDT
->DrawFilter(resultFilter
, aRenderRect
, Point(0, 0));
1203 UnionOfRegions(const nsTArray
<nsIntRegion
>& aRegions
)
1206 for (size_t i
= 0; i
< aRegions
.Length(); i
++) {
1207 result
.Or(result
, aRegions
[i
]);
1213 InflateSizeForBlurStdDev(float aStdDev
)
1215 double size
= std::min(aStdDev
, kMaxStdDeviation
) * (3 * sqrt(2 * M_PI
) / 4) * 1.5;
1216 return uint32_t(floor(size
+ 0.5));
1220 ResultChangeRegionForPrimitive(const FilterPrimitiveDescription
& aDescription
,
1221 const nsTArray
<nsIntRegion
>& aInputChangeRegions
)
1223 const AttributeMap
& atts
= aDescription
.Attributes();
1224 switch (aDescription
.Type()) {
1226 case PrimitiveType::Empty
:
1227 case PrimitiveType::Flood
:
1228 case PrimitiveType::Turbulence
:
1229 case PrimitiveType::Image
:
1230 return nsIntRegion();
1232 case PrimitiveType::Blend
:
1233 case PrimitiveType::Composite
:
1234 case PrimitiveType::Merge
:
1235 return UnionOfRegions(aInputChangeRegions
);
1237 case PrimitiveType::ColorMatrix
:
1238 case PrimitiveType::ComponentTransfer
:
1239 case PrimitiveType::ToAlpha
:
1240 return aInputChangeRegions
[0];
1242 case PrimitiveType::Morphology
:
1244 Size radii
= atts
.GetSize(eMorphologyRadii
);
1245 int32_t rx
= clamped(int32_t(ceil(radii
.width
)), 0, kMorphologyMaxRadius
);
1246 int32_t ry
= clamped(int32_t(ceil(radii
.height
)), 0, kMorphologyMaxRadius
);
1247 return aInputChangeRegions
[0].Inflated(nsIntMargin(ry
, rx
, ry
, rx
));
1250 case PrimitiveType::Tile
:
1251 return ThebesIntRect(aDescription
.PrimitiveSubregion());
1253 case PrimitiveType::ConvolveMatrix
:
1255 Size kernelUnitLength
= atts
.GetSize(eConvolveMatrixKernelUnitLength
);
1256 IntSize kernelSize
= atts
.GetIntSize(eConvolveMatrixKernelSize
);
1257 IntPoint target
= atts
.GetIntPoint(eConvolveMatrixTarget
);
1258 nsIntMargin
m(ceil(kernelUnitLength
.width
* (target
.x
)),
1259 ceil(kernelUnitLength
.height
* (target
.y
)),
1260 ceil(kernelUnitLength
.width
* (kernelSize
.width
- target
.x
- 1)),
1261 ceil(kernelUnitLength
.height
* (kernelSize
.height
- target
.y
- 1)));
1262 return aInputChangeRegions
[0].Inflated(m
);
1265 case PrimitiveType::Offset
:
1267 IntPoint offset
= atts
.GetIntPoint(eOffsetOffset
);
1268 return aInputChangeRegions
[0].MovedBy(offset
.x
, offset
.y
);
1271 case PrimitiveType::DisplacementMap
:
1273 int32_t scale
= ceil(abs(atts
.GetFloat(eDisplacementMapScale
)));
1274 return aInputChangeRegions
[0].Inflated(nsIntMargin(scale
, scale
, scale
, scale
));
1277 case PrimitiveType::GaussianBlur
:
1279 Size stdDeviation
= atts
.GetSize(eGaussianBlurStdDeviation
);
1280 int32_t dx
= InflateSizeForBlurStdDev(stdDeviation
.width
);
1281 int32_t dy
= InflateSizeForBlurStdDev(stdDeviation
.height
);
1282 return aInputChangeRegions
[0].Inflated(nsIntMargin(dy
, dx
, dy
, dx
));
1285 case PrimitiveType::DropShadow
:
1287 IntPoint offset
= atts
.GetIntPoint(eDropShadowOffset
);
1288 nsIntRegion offsetRegion
= aInputChangeRegions
[0].MovedBy(offset
.x
, offset
.y
);
1289 Size stdDeviation
= atts
.GetSize(eDropShadowStdDeviation
);
1290 int32_t dx
= InflateSizeForBlurStdDev(stdDeviation
.width
);
1291 int32_t dy
= InflateSizeForBlurStdDev(stdDeviation
.height
);
1292 nsIntRegion blurRegion
= offsetRegion
.Inflated(nsIntMargin(dy
, dx
, dy
, dx
));
1293 blurRegion
.Or(blurRegion
, aInputChangeRegions
[0]);
1297 case PrimitiveType::DiffuseLighting
:
1298 case PrimitiveType::SpecularLighting
:
1300 Size kernelUnitLength
= atts
.GetSize(eLightingKernelUnitLength
);
1301 int32_t dx
= ceil(kernelUnitLength
.width
);
1302 int32_t dy
= ceil(kernelUnitLength
.height
);
1303 return aInputChangeRegions
[0].Inflated(nsIntMargin(dy
, dx
, dy
, dx
));
1307 return nsIntRegion();
1311 /* static */ nsIntRegion
1312 FilterSupport::ComputeResultChangeRegion(const FilterDescription
& aFilter
,
1313 const nsIntRegion
& aSourceGraphicChange
,
1314 const nsIntRegion
& aFillPaintChange
,
1315 const nsIntRegion
& aStrokePaintChange
)
1317 const nsTArray
<FilterPrimitiveDescription
>& primitives
= aFilter
.mPrimitives
;
1318 nsTArray
<nsIntRegion
> resultChangeRegions
;
1320 for (int32_t i
= 0; i
< int32_t(primitives
.Length()); ++i
) {
1321 const FilterPrimitiveDescription
& descr
= primitives
[i
];
1323 nsTArray
<nsIntRegion
> inputChangeRegions
;
1324 for (size_t j
= 0; j
< descr
.NumberOfInputs(); j
++) {
1325 int32_t inputIndex
= descr
.InputPrimitiveIndex(j
);
1326 MOZ_ASSERT(inputIndex
< i
, "bad input index");
1327 nsIntRegion inputChangeRegion
=
1328 ElementForIndex(inputIndex
, resultChangeRegions
,
1329 aSourceGraphicChange
, aFillPaintChange
,
1330 aStrokePaintChange
);
1331 inputChangeRegions
.AppendElement(inputChangeRegion
);
1333 nsIntRegion changeRegion
=
1334 ResultChangeRegionForPrimitive(descr
, inputChangeRegions
);
1335 changeRegion
.And(changeRegion
, ThebesIntRect(descr
.PrimitiveSubregion()));
1336 resultChangeRegions
.AppendElement(changeRegion
);
1339 return resultChangeRegions
[resultChangeRegions
.Length() - 1];
1343 FilterSupport::PostFilterExtentsForPrimitive(const FilterPrimitiveDescription
& aDescription
,
1344 const nsTArray
<nsIntRegion
>& aInputExtents
)
1346 const AttributeMap
& atts
= aDescription
.Attributes();
1347 switch (aDescription
.Type()) {
1349 case PrimitiveType::Empty
:
1352 case PrimitiveType::Composite
:
1354 uint32_t op
= atts
.GetUint(eCompositeOperator
);
1355 if (op
== SVG_FECOMPOSITE_OPERATOR_ARITHMETIC
) {
1356 // The arithmetic composite primitive can draw outside the bounding
1357 // box of its source images.
1358 const nsTArray
<float>& coefficients
= atts
.GetFloats(eCompositeCoefficients
);
1359 MOZ_ASSERT(coefficients
.Length() == 4);
1361 // The calculation is:
1362 // r = c[0] * in[0] * in[1] + c[1] * in[0] + c[2] * in[1] + c[3]
1364 if (coefficients
[0] > 0.0f
) {
1365 region
= aInputExtents
[0].Intersect(aInputExtents
[1]);
1367 if (coefficients
[1] > 0.0f
) {
1368 region
.Or(region
, aInputExtents
[0]);
1370 if (coefficients
[2] > 0.0f
) {
1371 region
.Or(region
, aInputExtents
[1]);
1373 if (coefficients
[3] > 0.0f
) {
1374 region
= ThebesIntRect(aDescription
.PrimitiveSubregion());
1378 if (op
== SVG_FECOMPOSITE_OPERATOR_IN
) {
1379 return aInputExtents
[0].Intersect(aInputExtents
[1]);
1381 return ResultChangeRegionForPrimitive(aDescription
, aInputExtents
);
1384 case PrimitiveType::Flood
:
1386 if (atts
.GetColor(eFloodColor
).a
== 0.0f
) {
1389 return ThebesIntRect(aDescription
.PrimitiveSubregion());
1392 case PrimitiveType::Turbulence
:
1393 case PrimitiveType::Image
:
1395 return ThebesIntRect(aDescription
.PrimitiveSubregion());
1398 case PrimitiveType::Morphology
:
1400 uint32_t op
= atts
.GetUint(eMorphologyOperator
);
1401 if (op
== SVG_OPERATOR_ERODE
) {
1402 return aInputExtents
[0];
1404 Size radii
= atts
.GetSize(eMorphologyRadii
);
1405 int32_t rx
= clamped(int32_t(ceil(radii
.width
)), 0, kMorphologyMaxRadius
);
1406 int32_t ry
= clamped(int32_t(ceil(radii
.height
)), 0, kMorphologyMaxRadius
);
1407 return aInputExtents
[0].Inflated(nsIntMargin(ry
, rx
, ry
, rx
));
1411 return ResultChangeRegionForPrimitive(aDescription
, aInputExtents
);
1415 /* static */ nsIntRegion
1416 FilterSupport::ComputePostFilterExtents(const FilterDescription
& aFilter
,
1417 const nsIntRegion
& aSourceGraphicExtents
)
1419 const nsTArray
<FilterPrimitiveDescription
>& primitives
= aFilter
.mPrimitives
;
1420 nsTArray
<nsIntRegion
> postFilterExtents
;
1422 for (int32_t i
= 0; i
< int32_t(primitives
.Length()); ++i
) {
1423 const FilterPrimitiveDescription
& descr
= primitives
[i
];
1424 nsIntRegion filterSpace
= ThebesIntRect(descr
.FilterSpaceBounds());
1426 nsTArray
<nsIntRegion
> inputExtents
;
1427 for (size_t j
= 0; j
< descr
.NumberOfInputs(); j
++) {
1428 int32_t inputIndex
= descr
.InputPrimitiveIndex(j
);
1429 MOZ_ASSERT(inputIndex
< i
, "bad input index");
1430 nsIntRegion inputExtent
=
1431 ElementForIndex(inputIndex
, postFilterExtents
,
1432 aSourceGraphicExtents
, filterSpace
, filterSpace
);
1433 inputExtents
.AppendElement(inputExtent
);
1435 nsIntRegion extent
= PostFilterExtentsForPrimitive(descr
, inputExtents
);
1436 extent
.And(extent
, ThebesIntRect(descr
.PrimitiveSubregion()));
1437 postFilterExtents
.AppendElement(extent
);
1440 return postFilterExtents
[postFilterExtents
.Length() - 1];
1444 SourceNeededRegionForPrimitive(const FilterPrimitiveDescription
& aDescription
,
1445 const nsIntRegion
& aResultNeededRegion
,
1446 int32_t aInputIndex
)
1448 const AttributeMap
& atts
= aDescription
.Attributes();
1449 switch (aDescription
.Type()) {
1451 case PrimitiveType::Flood
:
1452 case PrimitiveType::Turbulence
:
1453 case PrimitiveType::Image
:
1454 MOZ_CRASH("this shouldn't be called for filters without inputs");
1455 return nsIntRegion();
1457 case PrimitiveType::Empty
:
1458 return nsIntRegion();
1460 case PrimitiveType::Blend
:
1461 case PrimitiveType::Composite
:
1462 case PrimitiveType::Merge
:
1463 case PrimitiveType::ColorMatrix
:
1464 case PrimitiveType::ComponentTransfer
:
1465 case PrimitiveType::ToAlpha
:
1466 return aResultNeededRegion
;
1468 case PrimitiveType::Morphology
:
1470 Size radii
= atts
.GetSize(eMorphologyRadii
);
1471 int32_t rx
= clamped(int32_t(ceil(radii
.width
)), 0, kMorphologyMaxRadius
);
1472 int32_t ry
= clamped(int32_t(ceil(radii
.height
)), 0, kMorphologyMaxRadius
);
1473 return aResultNeededRegion
.Inflated(nsIntMargin(ry
, rx
, ry
, rx
));
1476 case PrimitiveType::Tile
:
1477 return nsIntRect(INT32_MIN
/2, INT32_MIN
/2, INT32_MAX
, INT32_MAX
);
1479 case PrimitiveType::ConvolveMatrix
:
1481 Size kernelUnitLength
= atts
.GetSize(eConvolveMatrixKernelUnitLength
);
1482 IntSize kernelSize
= atts
.GetIntSize(eConvolveMatrixKernelSize
);
1483 IntPoint target
= atts
.GetIntPoint(eConvolveMatrixTarget
);
1484 nsIntMargin
m(ceil(kernelUnitLength
.width
* (kernelSize
.width
- target
.x
- 1)),
1485 ceil(kernelUnitLength
.height
* (kernelSize
.height
- target
.y
- 1)),
1486 ceil(kernelUnitLength
.width
* (target
.x
)),
1487 ceil(kernelUnitLength
.height
* (target
.y
)));
1488 return aResultNeededRegion
.Inflated(m
);
1491 case PrimitiveType::Offset
:
1493 IntPoint offset
= atts
.GetIntPoint(eOffsetOffset
);
1494 return aResultNeededRegion
.MovedBy(-nsIntPoint(offset
.x
, offset
.y
));
1497 case PrimitiveType::DisplacementMap
:
1499 if (aInputIndex
== 1) {
1500 return aResultNeededRegion
;
1502 int32_t scale
= ceil(abs(atts
.GetFloat(eDisplacementMapScale
)));
1503 return aResultNeededRegion
.Inflated(nsIntMargin(scale
, scale
, scale
, scale
));
1506 case PrimitiveType::GaussianBlur
:
1508 Size stdDeviation
= atts
.GetSize(eGaussianBlurStdDeviation
);
1509 int32_t dx
= InflateSizeForBlurStdDev(stdDeviation
.width
);
1510 int32_t dy
= InflateSizeForBlurStdDev(stdDeviation
.height
);
1511 return aResultNeededRegion
.Inflated(nsIntMargin(dy
, dx
, dy
, dx
));
1514 case PrimitiveType::DropShadow
:
1516 IntPoint offset
= atts
.GetIntPoint(eDropShadowOffset
);
1517 nsIntRegion offsetRegion
=
1518 aResultNeededRegion
.MovedBy(-nsIntPoint(offset
.x
, offset
.y
));
1519 Size stdDeviation
= atts
.GetSize(eDropShadowStdDeviation
);
1520 int32_t dx
= InflateSizeForBlurStdDev(stdDeviation
.width
);
1521 int32_t dy
= InflateSizeForBlurStdDev(stdDeviation
.height
);
1522 nsIntRegion blurRegion
= offsetRegion
.Inflated(nsIntMargin(dy
, dx
, dy
, dx
));
1523 blurRegion
.Or(blurRegion
, aResultNeededRegion
);
1527 case PrimitiveType::DiffuseLighting
:
1528 case PrimitiveType::SpecularLighting
:
1530 Size kernelUnitLength
= atts
.GetSize(eLightingKernelUnitLength
);
1531 int32_t dx
= ceil(kernelUnitLength
.width
);
1532 int32_t dy
= ceil(kernelUnitLength
.height
);
1533 return aResultNeededRegion
.Inflated(nsIntMargin(dy
, dx
, dy
, dx
));
1537 return nsIntRegion();
1543 FilterSupport::ComputeSourceNeededRegions(const FilterDescription
& aFilter
,
1544 const nsIntRegion
& aResultNeededRegion
,
1545 nsIntRegion
& aSourceGraphicNeededRegion
,
1546 nsIntRegion
& aFillPaintNeededRegion
,
1547 nsIntRegion
& aStrokePaintNeededRegion
)
1549 const nsTArray
<FilterPrimitiveDescription
>& primitives
= aFilter
.mPrimitives
;
1550 nsTArray
<nsIntRegion
> primitiveNeededRegions
;
1551 primitiveNeededRegions
.AppendElements(primitives
.Length());
1553 primitiveNeededRegions
[primitives
.Length() - 1] = aResultNeededRegion
;
1555 for (int32_t i
= primitives
.Length() - 1; i
>= 0; --i
) {
1556 const FilterPrimitiveDescription
& descr
= primitives
[i
];
1557 nsIntRegion neededRegion
= primitiveNeededRegions
[i
];
1558 neededRegion
.And(neededRegion
, ThebesIntRect(descr
.PrimitiveSubregion()));
1560 for (size_t j
= 0; j
< descr
.NumberOfInputs(); j
++) {
1561 int32_t inputIndex
= descr
.InputPrimitiveIndex(j
);
1562 MOZ_ASSERT(inputIndex
< i
, "bad input index");
1563 nsIntRegion
* inputNeededRegion
= const_cast<nsIntRegion
*>(
1564 &ElementForIndex(inputIndex
, primitiveNeededRegions
,
1565 aSourceGraphicNeededRegion
,
1566 aFillPaintNeededRegion
, aStrokePaintNeededRegion
));
1567 inputNeededRegion
->Or(*inputNeededRegion
,
1568 SourceNeededRegionForPrimitive(descr
, neededRegion
, j
));
1572 // Clip original SourceGraphic to first filter region.
1573 if (primitives
.Length() > 0) {
1574 const FilterPrimitiveDescription
& firstDescr
= primitives
[0];
1575 aSourceGraphicNeededRegion
.And(aSourceGraphicNeededRegion
,
1576 ThebesIntRect(firstDescr
.FilterSpaceBounds()));
1580 // FilterPrimitiveDescription
1582 FilterPrimitiveDescription::FilterPrimitiveDescription()
1583 : mType(PrimitiveType::Empty
)
1584 , mOutputColorSpace(ColorSpace::SRGB
)
1589 FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType
)
1591 , mOutputColorSpace(ColorSpace::SRGB
)
1596 FilterPrimitiveDescription::FilterPrimitiveDescription(const FilterPrimitiveDescription
& aOther
)
1597 : mType(aOther
.mType
)
1598 , mAttributes(aOther
.mAttributes
)
1599 , mInputPrimitives(aOther
.mInputPrimitives
)
1600 , mFilterPrimitiveSubregion(aOther
.mFilterPrimitiveSubregion
)
1601 , mFilterSpaceBounds(aOther
.mFilterSpaceBounds
)
1602 , mInputColorSpaces(aOther
.mInputColorSpaces
)
1603 , mOutputColorSpace(aOther
.mOutputColorSpace
)
1604 , mIsTainted(aOther
.mIsTainted
)
1608 FilterPrimitiveDescription
&
1609 FilterPrimitiveDescription::operator=(const FilterPrimitiveDescription
& aOther
)
1611 if (this != &aOther
) {
1612 mType
= aOther
.mType
;
1613 mAttributes
= aOther
.mAttributes
;
1614 mInputPrimitives
= aOther
.mInputPrimitives
;
1615 mFilterPrimitiveSubregion
= aOther
.mFilterPrimitiveSubregion
;
1616 mFilterSpaceBounds
= aOther
.mFilterSpaceBounds
;
1617 mInputColorSpaces
= aOther
.mInputColorSpaces
;
1618 mOutputColorSpace
= aOther
.mOutputColorSpace
;
1619 mIsTainted
= aOther
.mIsTainted
;
1625 FilterPrimitiveDescription::operator==(const FilterPrimitiveDescription
& aOther
) const
1627 return mType
== aOther
.mType
&&
1628 mFilterPrimitiveSubregion
.IsEqualInterior(aOther
.mFilterPrimitiveSubregion
) &&
1629 mFilterSpaceBounds
.IsEqualInterior(aOther
.mFilterSpaceBounds
) &&
1630 mOutputColorSpace
== aOther
.mOutputColorSpace
&&
1631 mIsTainted
== aOther
.mIsTainted
&&
1632 mInputPrimitives
== aOther
.mInputPrimitives
&&
1633 mInputColorSpaces
== aOther
.mInputColorSpaces
&&
1634 mAttributes
== aOther
.mAttributes
;
1637 // FilterDescription
1640 FilterDescription::operator==(const FilterDescription
& aOther
) const
1642 return mPrimitives
== aOther
.mPrimitives
;
1647 // A class that wraps different types for easy storage in a hashtable. Only
1648 // used by AttributeMap.
1649 struct FilterAttribute
{
1650 FilterAttribute(const FilterAttribute
& aOther
);
1653 bool operator==(const FilterAttribute
& aOther
) const;
1654 bool operator!=(const FilterAttribute
& aOther
) const
1656 return !(*this == aOther
);
1659 AttributeType
Type() const { return mType
; }
1661 #define MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(type, typeLabel) \
1662 explicit FilterAttribute(type aValue) \
1663 : mType(AttributeType::e##typeLabel), m##typeLabel(aValue) \
1665 type As##typeLabel() { \
1666 MOZ_ASSERT(mType == AttributeType::e##typeLabel); \
1667 return m##typeLabel; \
1670 #define MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(className) \
1671 explicit FilterAttribute(const className& aValue) \
1672 : mType(AttributeType::e##className), m##className(new className(aValue)) \
1674 className As##className() { \
1675 MOZ_ASSERT(mType == AttributeType::e##className); \
1676 return *m##className; \
1679 MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(bool, Bool
)
1680 MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(uint32_t, Uint
)
1681 MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(float, Float
)
1682 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Size
)
1683 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntSize
)
1684 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntPoint
)
1685 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix
)
1686 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix5x4
)
1687 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Point3D
)
1688 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Color
)
1689 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(AttributeMap
)
1691 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC
1692 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS
1694 FilterAttribute(const float* aValue
, uint32_t aLength
)
1695 : mType(AttributeType::eFloats
)
1697 mFloats
= new nsTArray
<float>();
1698 mFloats
->AppendElements(aValue
, aLength
);
1701 const nsTArray
<float>& AsFloats() const {
1702 MOZ_ASSERT(mType
== AttributeType::eFloats
);
1707 const AttributeType mType
;
1715 IntPoint
* mIntPoint
;
1717 Matrix5x4
* mMatrix5x4
;
1720 AttributeMap
* mAttributeMap
;
1721 nsTArray
<float>* mFloats
;
1725 FilterAttribute::FilterAttribute(const FilterAttribute
& aOther
)
1726 : mType(aOther
.mType
)
1729 case AttributeType::eBool
:
1730 mBool
= aOther
.mBool
;
1732 case AttributeType::eUint
:
1733 mUint
= aOther
.mUint
;
1735 case AttributeType::eFloat
:
1736 mFloat
= aOther
.mFloat
;
1739 #define HANDLE_CLASS(className) \
1740 case AttributeType::e##className: \
1741 m##className = new className(*aOther.m##className); \
1745 HANDLE_CLASS(IntSize
)
1746 HANDLE_CLASS(IntPoint
)
1747 HANDLE_CLASS(Matrix
)
1748 HANDLE_CLASS(Matrix5x4
)
1749 HANDLE_CLASS(Point3D
)
1751 HANDLE_CLASS(AttributeMap
)
1755 case AttributeType::eFloats
:
1756 mFloats
= new nsTArray
<float>(*aOther
.mFloats
);
1758 case AttributeType::Max
:
1763 FilterAttribute::~FilterAttribute() {
1765 case AttributeType::Max
:
1766 case AttributeType::eBool
:
1767 case AttributeType::eUint
:
1768 case AttributeType::eFloat
:
1771 #define HANDLE_CLASS(className) \
1772 case AttributeType::e##className: \
1773 delete m##className; \
1777 HANDLE_CLASS(IntSize
)
1778 HANDLE_CLASS(IntPoint
)
1779 HANDLE_CLASS(Matrix
)
1780 HANDLE_CLASS(Matrix5x4
)
1781 HANDLE_CLASS(Point3D
)
1783 HANDLE_CLASS(AttributeMap
)
1787 case AttributeType::eFloats
:
1794 FilterAttribute::operator==(const FilterAttribute
& aOther
) const
1796 if (mType
!= aOther
.mType
) {
1802 #define HANDLE_TYPE(typeName) \
1803 case AttributeType::e##typeName: \
1804 return m##typeName == aOther.m##typeName;
1810 HANDLE_TYPE(IntSize
)
1811 HANDLE_TYPE(IntPoint
)
1813 HANDLE_TYPE(Matrix5x4
)
1814 HANDLE_TYPE(Point3D
)
1816 HANDLE_TYPE(AttributeMap
)
1826 typedef FilterAttribute Attribute
;
1828 AttributeMap::AttributeMap()
1832 AttributeMap::~AttributeMap()
1836 static PLDHashOperator
1837 CopyAttribute(const uint32_t& aAttributeName
,
1838 Attribute
* aAttribute
,
1841 typedef nsClassHashtable
<nsUint32HashKey
, Attribute
> Map
;
1842 Map
* map
= static_cast<Map
*>(aAttributes
);
1843 map
->Put(aAttributeName
, new Attribute(*aAttribute
));
1844 return PL_DHASH_NEXT
;
1847 AttributeMap::AttributeMap(const AttributeMap
& aOther
)
1849 aOther
.mMap
.EnumerateRead(CopyAttribute
, &mMap
);
1853 AttributeMap::operator=(const AttributeMap
& aOther
)
1855 if (this != &aOther
) {
1857 aOther
.mMap
.EnumerateRead(CopyAttribute
, &mMap
);
1863 struct MatchingMap
{
1864 typedef nsClassHashtable
<nsUint32HashKey
, Attribute
> Map
;
1870 static PLDHashOperator
1871 CheckAttributeEquality(const uint32_t& aAttributeName
,
1872 Attribute
* aAttribute
,
1875 MatchingMap
& matchingMap
= *static_cast<MatchingMap
*>(aMatchingMap
);
1876 Attribute
* matchingAttribute
= matchingMap
.map
.Get(aAttributeName
);
1877 if (!matchingAttribute
||
1878 *matchingAttribute
!= *aAttribute
) {
1879 matchingMap
.matches
= false;
1880 return PL_DHASH_STOP
;
1882 return PL_DHASH_NEXT
;
1886 AttributeMap::operator==(const AttributeMap
& aOther
) const
1888 if (mMap
.Count() != aOther
.mMap
.Count()) {
1892 MatchingMap matchingMap
= { mMap
, true };
1893 aOther
.mMap
.EnumerateRead(CheckAttributeEquality
, &matchingMap
);
1894 return matchingMap
.matches
;
1898 struct HandlerWithUserData
1900 AttributeMap::AttributeHandleCallback handler
;
1905 static PLDHashOperator
1906 PassAttributeToHandleCallback(const uint32_t& aAttributeName
,
1907 Attribute
* aAttribute
,
1908 void* aHandlerWithUserData
)
1910 HandlerWithUserData
* handlerWithUserData
=
1911 static_cast<HandlerWithUserData
*>(aHandlerWithUserData
);
1912 return handlerWithUserData
->handler(AttributeName(aAttributeName
),
1914 handlerWithUserData
->userData
) ?
1915 PL_DHASH_NEXT
: PL_DHASH_STOP
;
1919 AttributeMap::EnumerateRead(AttributeMap::AttributeHandleCallback aCallback
, void* aUserData
) const
1921 HandlerWithUserData handlerWithUserData
= { aCallback
, aUserData
};
1922 mMap
.EnumerateRead(PassAttributeToHandleCallback
, &handlerWithUserData
);
1926 AttributeMap::Count() const
1928 return mMap
.Count();
1931 #define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \
1933 AttributeMap::Get##typeLabel(AttributeName aName) const { \
1934 Attribute* value = mMap.Get(aName); \
1935 return value ? value->As##typeLabel() : defaultValue; \
1938 AttributeMap::Set(AttributeName aName, type aValue) { \
1939 mMap.Remove(aName); \
1940 mMap.Put(aName, new Attribute(aValue)); \
1943 #define MAKE_ATTRIBUTE_HANDLERS_CLASS(className) \
1945 AttributeMap::Get##className(AttributeName aName) const { \
1946 Attribute* value = mMap.Get(aName); \
1947 return value ? value->As##className() : className(); \
1950 AttributeMap::Set(AttributeName aName, const className& aValue) { \
1951 mMap.Remove(aName); \
1952 mMap.Put(aName, new Attribute(aValue)); \
1955 MAKE_ATTRIBUTE_HANDLERS_BASIC(bool, Bool
, false)
1956 MAKE_ATTRIBUTE_HANDLERS_BASIC(uint32_t, Uint
, 0)
1957 MAKE_ATTRIBUTE_HANDLERS_BASIC(float, Float
, 0)
1958 MAKE_ATTRIBUTE_HANDLERS_CLASS(Size
)
1959 MAKE_ATTRIBUTE_HANDLERS_CLASS(IntSize
)
1960 MAKE_ATTRIBUTE_HANDLERS_CLASS(IntPoint
)
1961 MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix
)
1962 MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix5x4
)
1963 MAKE_ATTRIBUTE_HANDLERS_CLASS(Point3D
)
1964 MAKE_ATTRIBUTE_HANDLERS_CLASS(Color
)
1965 MAKE_ATTRIBUTE_HANDLERS_CLASS(AttributeMap
)
1967 #undef MAKE_ATTRIBUTE_HANDLERS_BASIC
1968 #undef MAKE_ATTRIBUTE_HANDLERS_CLASS
1970 const nsTArray
<float>&
1971 AttributeMap::GetFloats(AttributeName aName
) const
1973 Attribute
* value
= mMap
.Get(aName
);
1975 value
= new Attribute(nullptr, 0);
1976 mMap
.Put(aName
, value
);
1978 return value
->AsFloats();
1982 AttributeMap::Set(AttributeName aName
, const float* aValues
, int32_t aLength
)
1985 mMap
.Put(aName
, new Attribute(aValues
, aLength
));