Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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"
17 #include "nsMargin.h"
19 // c = n / 255
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
54 };
56 // c = n / 255
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
91 };
93 namespace mozilla {
94 namespace gfx {
96 // Some convenience FilterNode creation functions.
98 static const float kMaxStdDeviation = 500;
100 namespace FilterWrappers {
102 static TemporaryRef<FilterNode>
103 Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
104 {
105 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
106 filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
107 return filter;
108 }
110 static TemporaryRef<FilterNode>
111 Premultiply(DrawTarget* aDT, FilterNode* aInput)
112 {
113 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::PREMULTIPLY);
114 filter->SetInput(IN_PREMULTIPLY_IN, aInput);
115 return filter;
116 }
118 static TemporaryRef<FilterNode>
119 LinearRGBToSRGB(DrawTarget* aDT, FilterNode* aInput)
120 {
121 RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
122 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
123 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
124 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
125 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
126 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
127 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
128 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
129 transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
130 return transfer;
131 }
133 static TemporaryRef<FilterNode>
134 SRGBToLinearRGB(DrawTarget* aDT, FilterNode* aInput)
135 {
136 RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
137 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
138 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
139 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
140 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
141 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
142 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
143 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
144 transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
145 return transfer;
146 }
148 static TemporaryRef<FilterNode>
149 Crop(DrawTarget* aDT, FilterNode* aInputFilter, const IntRect& aRect)
150 {
151 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CROP);
152 filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
153 filter->SetInput(IN_CROP_IN, aInputFilter);
154 return filter;
155 }
157 static TemporaryRef<FilterNode>
158 Offset(DrawTarget* aDT, FilterNode* aInputFilter, const IntPoint& aOffset)
159 {
160 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
161 filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
162 filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
163 return filter;
164 }
166 static TemporaryRef<FilterNode>
167 GaussianBlur(DrawTarget* aDT, FilterNode* aInputFilter, const Size& aStdDeviation)
168 {
169 float stdX = float(std::min(aStdDeviation.width, kMaxStdDeviation));
170 float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
171 if (stdX == stdY) {
172 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
173 filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
174 filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
175 return filter;
176 }
177 RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
178 RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
179 filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
180 filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
181 filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
182 filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
183 filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
184 filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
185 return filterV;
186 }
188 static TemporaryRef<FilterNode>
189 Clear(DrawTarget* aDT)
190 {
191 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
192 filter->SetAttribute(ATT_FLOOD_COLOR, Color(0,0,0,0));
193 return filter;
194 }
196 static TemporaryRef<FilterNode>
197 ForSurface(DrawTarget* aDT, SourceSurface* aSurface,
198 const IntPoint& aSurfacePosition)
199 {
200 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
201 filter->SetAttribute(ATT_TRANSFORM_MATRIX,
202 Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
203 filter->SetInput(IN_TRANSFORM_IN, aSurface);
204 return filter;
205 }
207 static TemporaryRef<FilterNode>
208 ToAlpha(DrawTarget* aDT, FilterNode* aInput)
209 {
210 float zero = 0.0f;
211 RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
212 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
213 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
214 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
215 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
216 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
217 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
218 transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
219 transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
220 return transfer;
221 }
223 }
225 // A class that wraps a FilterNode and handles conversion between different
226 // color models. Create FilterCachedColorModels with your original filter and
227 // the color model that this filter outputs in natively, and then call
228 // ->ForColorModel(colorModel) in order to get a FilterNode which outputs to
229 // the specified colorModel.
230 // Internally, this is achieved by wrapping the original FilterNode with
231 // conversion FilterNodes. These filter nodes are cached in such a way that no
232 // repeated or back-and-forth conversions happen.
233 class FilterCachedColorModels
234 {
235 public:
236 NS_INLINE_DECL_REFCOUNTING(FilterCachedColorModels)
237 // aFilter can be null. In that case, ForColorModel will return a non-null
238 // completely transparent filter for all color models.
239 FilterCachedColorModels(DrawTarget* aDT,
240 FilterNode* aFilter,
241 ColorModel aOriginalColorModel);
243 // Get a FilterNode for the specified color model, guaranteed to be non-null.
244 TemporaryRef<FilterNode> ForColorModel(ColorModel aColorModel);
246 AlphaModel OriginalAlphaModel() const { return mOriginalColorModel.mAlphaModel; }
248 private:
249 // Create the required FilterNode that will be cached by ForColorModel.
250 TemporaryRef<FilterNode> WrapForColorModel(ColorModel aColorModel);
252 RefPtr<DrawTarget> mDT;
253 ColorModel mOriginalColorModel;
255 // This array is indexed by ColorModel::ToIndex.
256 RefPtr<FilterNode> mFilterForColorModel[4];
257 };
259 FilterCachedColorModels::FilterCachedColorModels(DrawTarget* aDT,
260 FilterNode* aFilter,
261 ColorModel aOriginalColorModel)
262 : mDT(aDT)
263 , mOriginalColorModel(aOriginalColorModel)
264 {
265 if (aFilter) {
266 mFilterForColorModel[aOriginalColorModel.ToIndex()] = aFilter;
267 } else {
268 RefPtr<FilterNode> clear = FilterWrappers::Clear(aDT);
269 mFilterForColorModel[0] = clear;
270 mFilterForColorModel[1] = clear;
271 mFilterForColorModel[2] = clear;
272 mFilterForColorModel[3] = clear;
273 }
274 }
276 TemporaryRef<FilterNode>
277 FilterCachedColorModels::ForColorModel(ColorModel aColorModel)
278 {
279 if (!mFilterForColorModel[aColorModel.ToIndex()]) {
280 mFilterForColorModel[aColorModel.ToIndex()] = WrapForColorModel(aColorModel);
281 }
282 return mFilterForColorModel[aColorModel.ToIndex()];
283 }
285 TemporaryRef<FilterNode>
286 FilterCachedColorModels::WrapForColorModel(ColorModel aColorModel)
287 {
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);
298 }
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);
305 }
307 RefPtr<FilterNode> unpremultipliedOriginal =
308 ForColorModel(ColorModel(mOriginalColorModel.mColorSpace, AlphaModel::Unpremultiplied));
309 if (aColorModel.mColorSpace == ColorSpace::LinearRGB) {
310 return FilterWrappers::SRGBToLinearRGB(mDT, unpremultipliedOriginal);
311 }
312 return FilterWrappers::LinearRGBToSRGB(mDT, unpremultipliedOriginal);
313 }
315 // Create a 4x5 color matrix for the different ways to specify color matrices
316 // in SVG.
317 static nsresult
318 ComputeColorMatrix(uint32_t aColorMatrixType, const nsTArray<float>& aValues,
319 float aOutMatrix[20])
320 {
321 static const float identityMatrix[] =
322 { 1, 0, 0, 0, 0,
323 0, 1, 0, 0, 0,
324 0, 0, 1, 0, 0,
325 0, 0, 0, 1, 0 };
327 static const float luminanceToAlphaMatrix[] =
328 { 0, 0, 0, 0, 0,
329 0, 0, 0, 0, 0,
330 0, 0, 0, 0, 0,
331 0.2125f, 0.7154f, 0.0721f, 0, 0 };
333 switch (aColorMatrixType) {
335 case SVG_FECOLORMATRIX_TYPE_MATRIX:
336 {
337 if (aValues.Length() != 20)
338 return NS_ERROR_FAILURE;
340 PodCopy(aOutMatrix, aValues.Elements(), 20);
341 break;
342 }
344 case SVG_FECOLORMATRIX_TYPE_SATURATE:
345 {
346 if (aValues.Length() != 1)
347 return NS_ERROR_FAILURE;
349 float s = aValues[0];
351 if (s < 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;
368 break;
369 }
371 case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE:
372 {
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;
395 break;
396 }
398 case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA:
399 {
400 PodCopy(aOutMatrix, luminanceToAlphaMatrix, 20);
401 break;
402 }
404 default:
405 return NS_ERROR_FAILURE;
407 }
409 return NS_OK;
410 }
412 static void
413 DisableAllTransfers(FilterNode* aTransferFilterNode)
414 {
415 aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_R, true);
416 aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_G, true);
417 aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_B, true);
418 aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_A, true);
419 }
421 // Called for one channel at a time.
422 // This function creates the required FilterNodes on demand and tries to
423 // merge conversions of different channels into the same FilterNode if
424 // possible.
425 // There's a mismatch between the way SVG and the Moz2D API handle transfer
426 // functions: In SVG, it's possible to specify a different transfer function
427 // type for each color channel, but in Moz2D, a given transfer function type
428 // applies to all color channels.
429 //
430 // @param aFunctionAttributes The attributes of the transfer function for this
431 // channel.
432 // @param aChannel The color channel that this function applies to, where
433 // 0 = red, 1 = green, 2 = blue, 3 = alpha
434 // @param aDT The DrawTarget that the FilterNodes should be created for.
435 // @param aTableTransfer Existing FilterNode holders (which may still be
436 // null) that the resulting FilterNodes from this
437 // function will be stored in.
438 //
439 static void
440 ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes,
441 int32_t aChannel,
442 DrawTarget* aDT,
443 RefPtr<FilterNode>& aTableTransfer,
444 RefPtr<FilterNode>& aDiscreteTransfer,
445 RefPtr<FilterNode>& aLinearTransfer,
446 RefPtr<FilterNode>& aGammaTransfer)
447 {
448 static const TransferAtts disableAtt[4] = {
449 ATT_TRANSFER_DISABLE_R,
450 ATT_TRANSFER_DISABLE_G,
451 ATT_TRANSFER_DISABLE_B,
452 ATT_TRANSFER_DISABLE_A
453 };
455 RefPtr<FilterNode> filter;
457 uint32_t type = aFunctionAttributes.GetUint(eComponentTransferFunctionType);
459 switch (type) {
460 case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
461 {
462 const nsTArray<float>& tableValues =
463 aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
464 if (tableValues.Length() < 2)
465 return;
467 if (!aTableTransfer) {
468 aTableTransfer = aDT->CreateFilter(FilterType::TABLE_TRANSFER);
469 DisableAllTransfers(aTableTransfer);
470 }
471 filter = aTableTransfer;
472 static const TableTransferAtts tableAtt[4] = {
473 ATT_TABLE_TRANSFER_TABLE_R,
474 ATT_TABLE_TRANSFER_TABLE_G,
475 ATT_TABLE_TRANSFER_TABLE_B,
476 ATT_TABLE_TRANSFER_TABLE_A
477 };
478 filter->SetAttribute(disableAtt[aChannel], false);
479 filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
480 break;
481 }
483 case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
484 {
485 const nsTArray<float>& tableValues =
486 aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
487 if (tableValues.Length() < 1)
488 return;
490 if (!aDiscreteTransfer) {
491 aDiscreteTransfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
492 DisableAllTransfers(aDiscreteTransfer);
493 }
494 filter = aDiscreteTransfer;
495 static const DiscreteTransferAtts tableAtt[4] = {
496 ATT_DISCRETE_TRANSFER_TABLE_R,
497 ATT_DISCRETE_TRANSFER_TABLE_G,
498 ATT_DISCRETE_TRANSFER_TABLE_B,
499 ATT_DISCRETE_TRANSFER_TABLE_A
500 };
501 filter->SetAttribute(disableAtt[aChannel], false);
502 filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
504 break;
505 }
507 case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
508 {
509 static const LinearTransferAtts slopeAtt[4] = {
510 ATT_LINEAR_TRANSFER_SLOPE_R,
511 ATT_LINEAR_TRANSFER_SLOPE_G,
512 ATT_LINEAR_TRANSFER_SLOPE_B,
513 ATT_LINEAR_TRANSFER_SLOPE_A
514 };
515 static const LinearTransferAtts interceptAtt[4] = {
516 ATT_LINEAR_TRANSFER_INTERCEPT_R,
517 ATT_LINEAR_TRANSFER_INTERCEPT_G,
518 ATT_LINEAR_TRANSFER_INTERCEPT_B,
519 ATT_LINEAR_TRANSFER_INTERCEPT_A
520 };
521 if (!aLinearTransfer) {
522 aLinearTransfer = aDT->CreateFilter(FilterType::LINEAR_TRANSFER);
523 DisableAllTransfers(aLinearTransfer);
524 }
525 filter = aLinearTransfer;
526 filter->SetAttribute(disableAtt[aChannel], false);
527 float slope = aFunctionAttributes.GetFloat(eComponentTransferFunctionSlope);
528 float intercept = aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
529 filter->SetAttribute(slopeAtt[aChannel], slope);
530 filter->SetAttribute(interceptAtt[aChannel], intercept);
531 break;
532 }
534 case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
535 {
536 static const GammaTransferAtts amplitudeAtt[4] = {
537 ATT_GAMMA_TRANSFER_AMPLITUDE_R,
538 ATT_GAMMA_TRANSFER_AMPLITUDE_G,
539 ATT_GAMMA_TRANSFER_AMPLITUDE_B,
540 ATT_GAMMA_TRANSFER_AMPLITUDE_A
541 };
542 static const GammaTransferAtts exponentAtt[4] = {
543 ATT_GAMMA_TRANSFER_EXPONENT_R,
544 ATT_GAMMA_TRANSFER_EXPONENT_G,
545 ATT_GAMMA_TRANSFER_EXPONENT_B,
546 ATT_GAMMA_TRANSFER_EXPONENT_A
547 };
548 static const GammaTransferAtts offsetAtt[4] = {
549 ATT_GAMMA_TRANSFER_OFFSET_R,
550 ATT_GAMMA_TRANSFER_OFFSET_G,
551 ATT_GAMMA_TRANSFER_OFFSET_B,
552 ATT_GAMMA_TRANSFER_OFFSET_A
553 };
554 if (!aGammaTransfer) {
555 aGammaTransfer = aDT->CreateFilter(FilterType::GAMMA_TRANSFER);
556 DisableAllTransfers(aGammaTransfer);
557 }
558 filter = aGammaTransfer;
559 filter->SetAttribute(disableAtt[aChannel], false);
560 float amplitude = aFunctionAttributes.GetFloat(eComponentTransferFunctionAmplitude);
561 float exponent = aFunctionAttributes.GetFloat(eComponentTransferFunctionExponent);
562 float offset = aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
563 filter->SetAttribute(amplitudeAtt[aChannel], amplitude);
564 filter->SetAttribute(exponentAtt[aChannel], exponent);
565 filter->SetAttribute(offsetAtt[aChannel], offset);
566 break;
567 }
569 case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
570 default:
571 break;
572 }
573 }
575 const int32_t kMorphologyMaxRadius = 100000;
577 // Handle the different primitive description types and create the necessary
578 // FilterNode(s) for each.
579 // Returns nullptr for invalid filter primitives. This should be interpreted as
580 // transparent black by the caller.
581 // aSourceRegions contains the filter primitive subregions of the source
582 // primitives; only needed for eTile primitives.
583 // aInputImages carries additional surfaces that are used by eImage primitives.
584 static TemporaryRef<FilterNode>
585 FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescription,
586 DrawTarget* aDT,
587 nsTArray<RefPtr<FilterNode> >& aSources,
588 nsTArray<IntRect>& aSourceRegions,
589 nsTArray<RefPtr<SourceSurface>>& aInputImages)
590 {
591 const AttributeMap& atts = aDescription.Attributes();
592 switch (aDescription.Type()) {
594 case PrimitiveType::Empty:
595 return nullptr;
597 case PrimitiveType::Blend:
598 {
599 uint32_t mode = atts.GetUint(eBlendBlendmode);
600 RefPtr<FilterNode> filter;
601 if (mode == SVG_FEBLEND_MODE_UNKNOWN) {
602 return nullptr;
603 }
604 if (mode == SVG_FEBLEND_MODE_NORMAL) {
605 filter = aDT->CreateFilter(FilterType::COMPOSITE);
606 filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
607 filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
608 } else {
609 filter = aDT->CreateFilter(FilterType::BLEND);
610 static const uint8_t blendModes[SVG_FEBLEND_MODE_LIGHTEN + 1] = {
611 0,
612 0,
613 BLEND_MODE_MULTIPLY,
614 BLEND_MODE_SCREEN,
615 BLEND_MODE_DARKEN,
616 BLEND_MODE_LIGHTEN
617 };
618 filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)blendModes[mode]);
619 filter->SetInput(IN_BLEND_IN, aSources[0]);
620 filter->SetInput(IN_BLEND_IN2, aSources[1]);
621 }
622 return filter;
623 }
625 case PrimitiveType::ColorMatrix:
626 {
627 float colorMatrix[20];
628 uint32_t type = atts.GetUint(eColorMatrixType);
629 const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
630 if (NS_FAILED(ComputeColorMatrix(type, values, colorMatrix))) {
631 return aSources[0];
632 }
633 Matrix5x4 matrix(colorMatrix[0], colorMatrix[5], colorMatrix[10], colorMatrix[15],
634 colorMatrix[1], colorMatrix[6], colorMatrix[11], colorMatrix[16],
635 colorMatrix[2], colorMatrix[7], colorMatrix[12], colorMatrix[17],
636 colorMatrix[3], colorMatrix[8], colorMatrix[13], colorMatrix[18],
637 colorMatrix[4], colorMatrix[9], colorMatrix[14], colorMatrix[19]);
638 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COLOR_MATRIX);
639 filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
640 filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
641 filter->SetInput(IN_COLOR_MATRIX_IN, aSources[0]);
642 return filter;
643 }
645 case PrimitiveType::Morphology:
646 {
647 Size radii = atts.GetSize(eMorphologyRadii);
648 int32_t rx = radii.width;
649 int32_t ry = radii.height;
650 if (rx < 0 || ry < 0) {
651 // XXX SVGContentUtils::ReportToConsole()
652 return nullptr;
653 }
654 if (rx == 0 && ry == 0) {
655 return nullptr;
656 }
658 // Clamp radii to prevent completely insane values:
659 rx = std::min(rx, kMorphologyMaxRadius);
660 ry = std::min(ry, kMorphologyMaxRadius);
662 MorphologyOperator op = atts.GetUint(eMorphologyOperator) == SVG_OPERATOR_ERODE ?
663 MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE;
665 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::MORPHOLOGY);
666 filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
667 filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
668 filter->SetInput(IN_MORPHOLOGY_IN, aSources[0]);
669 return filter;
670 }
672 case PrimitiveType::Flood:
673 {
674 Color color = atts.GetColor(eFloodColor);
675 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
676 filter->SetAttribute(ATT_FLOOD_COLOR, color);
677 return filter;
678 }
680 case PrimitiveType::Tile:
681 {
682 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TILE);
683 filter->SetAttribute(ATT_TILE_SOURCE_RECT, aSourceRegions[0]);
684 filter->SetInput(IN_TILE_IN, aSources[0]);
685 return filter;
686 }
688 case PrimitiveType::ComponentTransfer:
689 {
690 RefPtr<FilterNode> filters[4]; // one for each FILTER_*_TRANSFER type
691 static const AttributeName componentFunctionNames[4] = {
692 eComponentTransferFunctionR,
693 eComponentTransferFunctionG,
694 eComponentTransferFunctionB,
695 eComponentTransferFunctionA
696 };
697 for (int32_t i = 0; i < 4; i++) {
698 AttributeMap functionAttributes =
699 atts.GetAttributeMap(componentFunctionNames[i]);
700 ConvertComponentTransferFunctionToFilter(functionAttributes, i, aDT,
701 filters[0], filters[1], filters[2], filters[3]);
702 }
704 // Connect all used filters nodes.
705 RefPtr<FilterNode> lastFilter = aSources[0];
706 for (int32_t i = 0; i < 4; i++) {
707 if (filters[i]) {
708 filters[i]->SetInput(0, lastFilter);
709 lastFilter = filters[i];
710 }
711 }
713 return lastFilter;
714 }
716 case PrimitiveType::ConvolveMatrix:
717 {
718 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
719 filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, atts.GetIntSize(eConvolveMatrixKernelSize));
720 const nsTArray<float>& matrix = atts.GetFloats(eConvolveMatrixKernelMatrix);
721 filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,
722 matrix.Elements(), matrix.Length());
723 filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR,
724 atts.GetFloat(eConvolveMatrixDivisor));
725 filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS,
726 atts.GetFloat(eConvolveMatrixBias));
727 filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET,
728 atts.GetIntPoint(eConvolveMatrixTarget));
729 filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT,
730 aSourceRegions[0]);
731 uint32_t edgeMode = atts.GetUint(eConvolveMatrixEdgeMode);
732 static const uint8_t edgeModes[SVG_EDGEMODE_NONE+1] = {
733 EDGE_MODE_NONE, // SVG_EDGEMODE_UNKNOWN
734 EDGE_MODE_DUPLICATE, // SVG_EDGEMODE_DUPLICATE
735 EDGE_MODE_WRAP, // SVG_EDGEMODE_WRAP
736 EDGE_MODE_NONE // SVG_EDGEMODE_NONE
737 };
738 filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)edgeModes[edgeMode]);
739 filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH,
740 atts.GetSize(eConvolveMatrixKernelUnitLength));
741 filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA,
742 atts.GetBool(eConvolveMatrixPreserveAlpha));
743 filter->SetInput(IN_CONVOLVE_MATRIX_IN, aSources[0]);
744 return filter;
745 }
747 case PrimitiveType::Offset:
748 {
749 return FilterWrappers::Offset(aDT, aSources[0],
750 atts.GetIntPoint(eOffsetOffset));
751 }
753 case PrimitiveType::DisplacementMap:
754 {
755 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
756 filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE,
757 atts.GetFloat(eDisplacementMapScale));
758 static const uint8_t channel[SVG_CHANNEL_A+1] = {
759 COLOR_CHANNEL_R, // SVG_CHANNEL_UNKNOWN
760 COLOR_CHANNEL_R, // SVG_CHANNEL_R
761 COLOR_CHANNEL_G, // SVG_CHANNEL_G
762 COLOR_CHANNEL_B, // SVG_CHANNEL_B
763 COLOR_CHANNEL_A // SVG_CHANNEL_A
764 };
765 filter->SetAttribute(ATT_DISPLACEMENT_MAP_X_CHANNEL,
766 (uint32_t)channel[atts.GetUint(eDisplacementMapXChannel)]);
767 filter->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL,
768 (uint32_t)channel[atts.GetUint(eDisplacementMapYChannel)]);
769 filter->SetInput(IN_DISPLACEMENT_MAP_IN, aSources[0]);
770 filter->SetInput(IN_DISPLACEMENT_MAP_IN2, aSources[1]);
771 return filter;
772 }
774 case PrimitiveType::Turbulence:
775 {
776 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TURBULENCE);
777 filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
778 atts.GetSize(eTurbulenceBaseFrequency));
779 filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES,
780 atts.GetUint(eTurbulenceNumOctaves));
781 filter->SetAttribute(ATT_TURBULENCE_STITCHABLE,
782 atts.GetBool(eTurbulenceStitchable));
783 filter->SetAttribute(ATT_TURBULENCE_SEED,
784 (uint32_t)atts.GetFloat(eTurbulenceSeed));
785 static const uint8_t type[SVG_TURBULENCE_TYPE_TURBULENCE+1] = {
786 TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_UNKNOWN
787 TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_FRACTALNOISE
788 TURBULENCE_TYPE_TURBULENCE // SVG_TURBULENCE_TYPE_TURBULENCE
789 };
790 filter->SetAttribute(ATT_TURBULENCE_TYPE,
791 (uint32_t)type[atts.GetUint(eTurbulenceType)]);
792 filter->SetAttribute(ATT_TURBULENCE_RECT,
793 aDescription.PrimitiveSubregion() - atts.GetIntPoint(eTurbulenceOffset));
794 return FilterWrappers::Offset(aDT, filter, atts.GetIntPoint(eTurbulenceOffset));
795 }
797 case PrimitiveType::Composite:
798 {
799 RefPtr<FilterNode> filter;
800 uint32_t op = atts.GetUint(eCompositeOperator);
801 if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
802 filter = aDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
803 const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
804 filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS,
805 coefficients.Elements(), coefficients.Length());
806 filter->SetInput(IN_ARITHMETIC_COMBINE_IN, aSources[0]);
807 filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, aSources[1]);
808 } else {
809 filter = aDT->CreateFilter(FilterType::COMPOSITE);
810 static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
811 COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
812 COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
813 COMPOSITE_OPERATOR_IN, // SVG_FECOMPOSITE_OPERATOR_IN
814 COMPOSITE_OPERATOR_OUT, // SVG_FECOMPOSITE_OPERATOR_OUT
815 COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
816 COMPOSITE_OPERATOR_XOR // SVG_FECOMPOSITE_OPERATOR_XOR
817 };
818 filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)operators[op]);
819 filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
820 filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
821 }
822 return filter;
823 }
825 case PrimitiveType::Merge:
826 {
827 if (aSources.Length() == 0) {
828 return nullptr;
829 }
830 if (aSources.Length() == 1) {
831 return aSources[0];
832 }
833 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
834 filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
835 for (size_t i = 0; i < aSources.Length(); i++) {
836 filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
837 }
838 return filter;
839 }
841 case PrimitiveType::GaussianBlur:
842 {
843 return FilterWrappers::GaussianBlur(aDT, aSources[0],
844 atts.GetSize(eGaussianBlurStdDeviation));
845 }
847 case PrimitiveType::DropShadow:
848 {
849 RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(aDT, aSources[0]);
850 RefPtr<FilterNode> blur = FilterWrappers::GaussianBlur(aDT, alpha,
851 atts.GetSize(eDropShadowStdDeviation));
852 RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
853 atts.GetIntPoint(eDropShadowOffset));
854 RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
855 Color color = atts.GetColor(eDropShadowColor);
856 if (aDescription.InputColorSpace(0) == ColorSpace::LinearRGB) {
857 color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
858 gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
859 gsRGBToLinearRGBMap[uint8_t(color.b * 255)],
860 color.a);
861 }
862 flood->SetAttribute(ATT_FLOOD_COLOR, color);
864 RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
865 composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
866 composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
867 composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
869 RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
870 filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
871 filter->SetInput(IN_COMPOSITE_IN_START, composite);
872 filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
873 return filter;
874 }
876 case PrimitiveType::DiffuseLighting:
877 case PrimitiveType::SpecularLighting:
878 {
879 bool isSpecular =
880 aDescription.Type() == PrimitiveType::SpecularLighting;
882 AttributeMap lightAttributes = atts.GetAttributeMap(eLightingLight);
884 if (lightAttributes.GetUint(eLightType) == eLightTypeNone) {
885 return nullptr;
886 }
888 enum { POINT = 0, SPOT, DISTANT } lightType = POINT;
890 switch (lightAttributes.GetUint(eLightType)) {
891 case eLightTypePoint: lightType = POINT; break;
892 case eLightTypeSpot: lightType = SPOT; break;
893 case eLightTypeDistant: lightType = DISTANT; break;
894 }
896 static const FilterType filterType[2][DISTANT+1] = {
897 { FilterType::POINT_DIFFUSE, FilterType::SPOT_DIFFUSE, FilterType::DISTANT_DIFFUSE },
898 { FilterType::POINT_SPECULAR, FilterType::SPOT_SPECULAR, FilterType::DISTANT_SPECULAR }
899 };
900 RefPtr<FilterNode> filter =
901 aDT->CreateFilter(filterType[isSpecular][lightType]);
903 filter->SetAttribute(ATT_LIGHTING_COLOR,
904 atts.GetColor(eLightingColor));
905 filter->SetAttribute(ATT_LIGHTING_SURFACE_SCALE,
906 atts.GetFloat(eLightingSurfaceScale));
907 filter->SetAttribute(ATT_LIGHTING_KERNEL_UNIT_LENGTH,
908 atts.GetSize(eLightingKernelUnitLength));
910 if (isSpecular) {
911 filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
912 atts.GetFloat(eSpecularLightingSpecularConstant));
913 filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT,
914 atts.GetFloat(eSpecularLightingSpecularExponent));
915 } else {
916 filter->SetAttribute(ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT,
917 atts.GetFloat(eDiffuseLightingDiffuseConstant));
918 }
920 switch (lightType) {
921 case POINT:
922 filter->SetAttribute(ATT_POINT_LIGHT_POSITION,
923 lightAttributes.GetPoint3D(ePointLightPosition));
924 break;
925 case SPOT:
926 filter->SetAttribute(ATT_SPOT_LIGHT_POSITION,
927 lightAttributes.GetPoint3D(eSpotLightPosition));
928 filter->SetAttribute(ATT_SPOT_LIGHT_POINTS_AT,
929 lightAttributes.GetPoint3D(eSpotLightPointsAt));
930 filter->SetAttribute(ATT_SPOT_LIGHT_FOCUS,
931 lightAttributes.GetFloat(eSpotLightFocus));
932 filter->SetAttribute(ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,
933 lightAttributes.GetFloat(eSpotLightLimitingConeAngle));
934 break;
935 case DISTANT:
936 filter->SetAttribute(ATT_DISTANT_LIGHT_AZIMUTH,
937 lightAttributes.GetFloat(eDistantLightAzimuth));
938 filter->SetAttribute(ATT_DISTANT_LIGHT_ELEVATION,
939 lightAttributes.GetFloat(eDistantLightElevation));
940 break;
941 }
943 filter->SetInput(IN_LIGHTING_IN, aSources[0]);
945 return filter;
946 }
948 case PrimitiveType::Image:
949 {
950 Matrix TM = atts.GetMatrix(eImageTransform);
951 if (!TM.Determinant()) {
952 return nullptr;
953 }
955 // Pull the image from the additional image list using the index that's
956 // stored in the primitive description.
957 RefPtr<SourceSurface> inputImage =
958 aInputImages[atts.GetUint(eImageInputIndex)];
960 RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
961 transform->SetInput(IN_TRANSFORM_IN, inputImage);
962 transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
963 transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
964 return transform;
965 }
967 default:
968 return nullptr;
969 }
970 }
972 template<typename T>
973 static const T&
974 ElementForIndex(int32_t aIndex,
975 const nsTArray<T>& aPrimitiveElements,
976 const T& aSourceGraphicElement,
977 const T& aFillPaintElement,
978 const T& aStrokePaintElement)
979 {
980 switch (aIndex) {
981 case FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic:
982 case FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha:
983 return aSourceGraphicElement;
984 case FilterPrimitiveDescription::kPrimitiveIndexFillPaint:
985 return aFillPaintElement;
986 case FilterPrimitiveDescription::kPrimitiveIndexStrokePaint:
987 return aStrokePaintElement;
988 default:
989 MOZ_ASSERT(aIndex >= 0, "bad index");
990 return aPrimitiveElements[aIndex];
991 }
992 }
994 static AlphaModel
995 InputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
996 int32_t aInputIndex,
997 AlphaModel aOriginalAlphaModel)
998 {
999 switch (aDescr.Type()) {
1000 case PrimitiveType::Tile:
1001 case PrimitiveType::Offset:
1002 return aOriginalAlphaModel;
1004 case PrimitiveType::ColorMatrix:
1005 case PrimitiveType::ComponentTransfer:
1006 return AlphaModel::Unpremultiplied;
1008 case PrimitiveType::DisplacementMap:
1009 return aInputIndex == 0 ?
1010 AlphaModel::Premultiplied : AlphaModel::Unpremultiplied;
1012 case PrimitiveType::ConvolveMatrix:
1013 return aDescr.Attributes().GetBool(eConvolveMatrixPreserveAlpha) ?
1014 AlphaModel::Unpremultiplied : AlphaModel::Premultiplied;
1016 default:
1017 return AlphaModel::Premultiplied;
1018 }
1019 }
1021 static AlphaModel
1022 OutputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
1023 const nsTArray<AlphaModel>& aInputAlphaModels)
1024 {
1025 if (aInputAlphaModels.Length()) {
1026 // For filters with inputs, the output is premultiplied if and only if the
1027 // first input is premultiplied.
1028 return InputAlphaModelForPrimitive(aDescr, 0, aInputAlphaModels[0]);
1029 }
1031 // All filters without inputs produce premultiplied alpha.
1032 return AlphaModel::Premultiplied;
1033 }
1035 // Returns the output FilterNode, in premultiplied sRGB space.
1036 static TemporaryRef<FilterNode>
1037 FilterNodeGraphFromDescription(DrawTarget* aDT,
1038 const FilterDescription& aFilter,
1039 const Rect& aResultNeededRect,
1040 SourceSurface* aSourceGraphic,
1041 const IntRect& aSourceGraphicRect,
1042 SourceSurface* aFillPaint,
1043 const IntRect& aFillPaintRect,
1044 SourceSurface* aStrokePaint,
1045 const IntRect& aStrokePaintRect,
1046 nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
1047 {
1048 const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1049 const IntRect& filterSpaceBounds = aFilter.mFilterSpaceBounds;
1051 Rect resultNeededRect(aResultNeededRect);
1052 resultNeededRect.RoundOut();
1054 RefPtr<FilterCachedColorModels> sourceFilters[4];
1055 nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters;
1057 for (size_t i = 0; i < primitives.Length(); ++i) {
1058 const FilterPrimitiveDescription& descr = primitives[i];
1060 nsTArray<RefPtr<FilterNode> > inputFilterNodes;
1061 nsTArray<IntRect> inputSourceRects;
1062 nsTArray<AlphaModel> inputAlphaModels;
1064 for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1066 int32_t inputIndex = descr.InputPrimitiveIndex(j);
1067 if (inputIndex < 0) {
1068 inputSourceRects.AppendElement(filterSpaceBounds);
1069 } else {
1070 inputSourceRects.AppendElement(filterSpaceBounds.Intersect(
1071 primitives[inputIndex].PrimitiveSubregion()));
1072 }
1074 RefPtr<FilterCachedColorModels> inputFilter;
1075 if (inputIndex >= 0) {
1076 MOZ_ASSERT(inputIndex < (int64_t)primitiveFilters.Length(), "out-of-bounds input index!");
1077 inputFilter = primitiveFilters[inputIndex];
1078 MOZ_ASSERT(inputFilter, "Referred to input filter that comes after the current one?");
1079 } else {
1080 int32_t sourceIndex = -inputIndex - 1;
1081 MOZ_ASSERT(sourceIndex >= 0, "invalid source index");
1082 MOZ_ASSERT(sourceIndex < 4, "invalid source index");
1083 inputFilter = sourceFilters[sourceIndex];
1084 if (!inputFilter) {
1085 RefPtr<FilterNode> sourceFilterNode;
1087 nsTArray<SourceSurface*> primitiveSurfaces;
1088 nsTArray<IntRect> primitiveSurfaceRects;
1089 RefPtr<SourceSurface> surf =
1090 ElementForIndex(inputIndex, primitiveSurfaces,
1091 aSourceGraphic, aFillPaint, aStrokePaint);
1092 IntRect surfaceRect =
1093 ElementForIndex(inputIndex, primitiveSurfaceRects,
1094 aSourceGraphicRect, aFillPaintRect, aStrokePaintRect);
1095 if (surf) {
1096 IntPoint offset = surfaceRect.TopLeft();
1097 sourceFilterNode = FilterWrappers::ForSurface(aDT, surf, offset);
1099 if (inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) {
1100 sourceFilterNode = FilterWrappers::ToAlpha(aDT, sourceFilterNode);
1101 }
1102 }
1104 inputFilter = new FilterCachedColorModels(aDT, sourceFilterNode,
1105 ColorModel::PremulSRGB());
1106 sourceFilters[sourceIndex] = inputFilter;
1107 }
1108 }
1109 MOZ_ASSERT(inputFilter);
1111 AlphaModel inputAlphaModel =
1112 InputAlphaModelForPrimitive(descr, j, inputFilter->OriginalAlphaModel());
1113 inputAlphaModels.AppendElement(inputAlphaModel);
1114 ColorModel inputColorModel(descr.InputColorSpace(j), inputAlphaModel);
1115 inputFilterNodes.AppendElement(inputFilter->ForColorModel(inputColorModel));
1116 }
1118 RefPtr<FilterNode> primitiveFilterNode =
1119 FilterNodeFromPrimitiveDescription(descr, aDT, inputFilterNodes,
1120 inputSourceRects, aAdditionalImages);
1122 if (primitiveFilterNode) {
1123 IntRect cropRect = filterSpaceBounds.Intersect(descr.PrimitiveSubregion());
1124 primitiveFilterNode = FilterWrappers::Crop(aDT, primitiveFilterNode, cropRect);
1125 }
1127 ColorModel outputColorModel(descr.OutputColorSpace(),
1128 OutputAlphaModelForPrimitive(descr, inputAlphaModels));
1129 RefPtr<FilterCachedColorModels> primitiveFilter =
1130 new FilterCachedColorModels(aDT, primitiveFilterNode, outputColorModel);
1132 primitiveFilters.AppendElement(primitiveFilter);
1133 }
1135 return primitiveFilters.LastElement()->ForColorModel(ColorModel::PremulSRGB());
1136 }
1138 // FilterSupport
1140 void
1141 FilterSupport::RenderFilterDescription(DrawTarget* aDT,
1142 const FilterDescription& aFilter,
1143 const Rect& aRenderRect,
1144 SourceSurface* aSourceGraphic,
1145 const IntRect& aSourceGraphicRect,
1146 SourceSurface* aFillPaint,
1147 const IntRect& aFillPaintRect,
1148 SourceSurface* aStrokePaint,
1149 const IntRect& aStrokePaintRect,
1150 nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
1151 {
1152 RefPtr<FilterNode> resultFilter =
1153 FilterNodeGraphFromDescription(aDT, aFilter, aRenderRect,
1154 aSourceGraphic, aSourceGraphicRect, aFillPaint, aFillPaintRect,
1155 aStrokePaint, aStrokePaintRect, aAdditionalImages);
1157 aDT->DrawFilter(resultFilter, aRenderRect, Point(0, 0));
1158 }
1160 static nsIntRegion
1161 UnionOfRegions(const nsTArray<nsIntRegion>& aRegions)
1162 {
1163 nsIntRegion result;
1164 for (size_t i = 0; i < aRegions.Length(); i++) {
1165 result.Or(result, aRegions[i]);
1166 }
1167 return result;
1168 }
1170 static int32_t
1171 InflateSizeForBlurStdDev(float aStdDev)
1172 {
1173 double size = std::min(aStdDev, kMaxStdDeviation) * (3 * sqrt(2 * M_PI) / 4) * 1.5;
1174 return uint32_t(floor(size + 0.5));
1175 }
1177 static nsIntRegion
1178 ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
1179 const nsTArray<nsIntRegion>& aInputChangeRegions)
1180 {
1181 const AttributeMap& atts = aDescription.Attributes();
1182 switch (aDescription.Type()) {
1184 case PrimitiveType::Empty:
1185 case PrimitiveType::Flood:
1186 case PrimitiveType::Turbulence:
1187 case PrimitiveType::Image:
1188 return nsIntRegion();
1190 case PrimitiveType::Blend:
1191 case PrimitiveType::Composite:
1192 case PrimitiveType::Merge:
1193 return UnionOfRegions(aInputChangeRegions);
1195 case PrimitiveType::ColorMatrix:
1196 case PrimitiveType::ComponentTransfer:
1197 return aInputChangeRegions[0];
1199 case PrimitiveType::Morphology:
1200 {
1201 Size radii = atts.GetSize(eMorphologyRadii);
1202 int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
1203 int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
1204 return aInputChangeRegions[0].Inflated(nsIntMargin(ry, rx, ry, rx));
1205 }
1207 case PrimitiveType::Tile:
1208 return ThebesIntRect(aDescription.PrimitiveSubregion());
1210 case PrimitiveType::ConvolveMatrix:
1211 {
1212 Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
1213 IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
1214 IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
1215 nsIntMargin m(ceil(kernelUnitLength.width * (target.x)),
1216 ceil(kernelUnitLength.height * (target.y)),
1217 ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
1218 ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)));
1219 return aInputChangeRegions[0].Inflated(m);
1220 }
1222 case PrimitiveType::Offset:
1223 {
1224 IntPoint offset = atts.GetIntPoint(eOffsetOffset);
1225 return aInputChangeRegions[0].MovedBy(offset.x, offset.y);
1226 }
1228 case PrimitiveType::DisplacementMap:
1229 {
1230 int32_t scale = ceil(abs(atts.GetFloat(eDisplacementMapScale)));
1231 return aInputChangeRegions[0].Inflated(nsIntMargin(scale, scale, scale, scale));
1232 }
1234 case PrimitiveType::GaussianBlur:
1235 {
1236 Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
1237 int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1238 int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1239 return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
1240 }
1242 case PrimitiveType::DropShadow:
1243 {
1244 IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
1245 nsIntRegion offsetRegion = aInputChangeRegions[0].MovedBy(offset.x, offset.y);
1246 Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
1247 int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1248 int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1249 nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1250 blurRegion.Or(blurRegion, aInputChangeRegions[0]);
1251 return blurRegion;
1252 }
1254 case PrimitiveType::DiffuseLighting:
1255 case PrimitiveType::SpecularLighting:
1256 {
1257 Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
1258 int32_t dx = ceil(kernelUnitLength.width);
1259 int32_t dy = ceil(kernelUnitLength.height);
1260 return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
1261 }
1263 default:
1264 return nsIntRegion();
1265 }
1266 }
1268 /* static */ nsIntRegion
1269 FilterSupport::ComputeResultChangeRegion(const FilterDescription& aFilter,
1270 const nsIntRegion& aSourceGraphicChange,
1271 const nsIntRegion& aFillPaintChange,
1272 const nsIntRegion& aStrokePaintChange)
1273 {
1274 const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1275 nsTArray<nsIntRegion> resultChangeRegions;
1277 for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
1278 const FilterPrimitiveDescription& descr = primitives[i];
1280 nsTArray<nsIntRegion> inputChangeRegions;
1281 for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1282 int32_t inputIndex = descr.InputPrimitiveIndex(j);
1283 MOZ_ASSERT(inputIndex < i, "bad input index");
1284 nsIntRegion inputChangeRegion =
1285 ElementForIndex(inputIndex, resultChangeRegions,
1286 aSourceGraphicChange, aFillPaintChange,
1287 aStrokePaintChange);
1288 inputChangeRegions.AppendElement(inputChangeRegion);
1289 }
1290 nsIntRegion changeRegion =
1291 ResultChangeRegionForPrimitive(descr, inputChangeRegions);
1292 IntRect cropRect =
1293 descr.PrimitiveSubregion().Intersect(aFilter.mFilterSpaceBounds);
1294 changeRegion.And(changeRegion, ThebesIntRect(cropRect));
1295 resultChangeRegions.AppendElement(changeRegion);
1296 }
1298 return resultChangeRegions[resultChangeRegions.Length() - 1];
1299 }
1301 static nsIntRegion
1302 PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
1303 const nsTArray<nsIntRegion>& aInputExtents)
1304 {
1305 const AttributeMap& atts = aDescription.Attributes();
1306 switch (aDescription.Type()) {
1308 case PrimitiveType::Empty:
1309 return nsIntRect();
1311 case PrimitiveType::Composite:
1312 {
1313 uint32_t op = atts.GetUint(eCompositeOperator);
1314 if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
1315 // The arithmetic composite primitive can draw outside the bounding
1316 // box of its source images.
1317 const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
1318 MOZ_ASSERT(coefficients.Length() == 4);
1320 // The calculation is:
1321 // r = c[0] * in[0] * in[1] + c[1] * in[0] + c[2] * in[1] + c[3]
1322 nsIntRegion region;
1323 if (coefficients[0] > 0.0f) {
1324 region = aInputExtents[0].Intersect(aInputExtents[1]);
1325 }
1326 if (coefficients[1] > 0.0f) {
1327 region.Or(region, aInputExtents[0]);
1328 }
1329 if (coefficients[2] > 0.0f) {
1330 region.Or(region, aInputExtents[1]);
1331 }
1332 if (coefficients[3] > 0.0f) {
1333 region = ThebesIntRect(aDescription.PrimitiveSubregion());
1334 }
1335 return region;
1336 }
1337 if (op == SVG_FECOMPOSITE_OPERATOR_IN) {
1338 return aInputExtents[0].Intersect(aInputExtents[1]);
1339 }
1340 return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
1341 }
1343 case PrimitiveType::Flood:
1344 {
1345 if (atts.GetColor(eFloodColor).a == 0.0f) {
1346 return nsIntRect();
1347 }
1348 return ThebesIntRect(aDescription.PrimitiveSubregion());
1349 }
1351 case PrimitiveType::Turbulence:
1352 case PrimitiveType::Image:
1353 {
1354 return ThebesIntRect(aDescription.PrimitiveSubregion());
1355 }
1357 case PrimitiveType::Morphology:
1358 {
1359 uint32_t op = atts.GetUint(eMorphologyOperator);
1360 if (op == SVG_OPERATOR_ERODE) {
1361 return aInputExtents[0];
1362 }
1363 Size radii = atts.GetSize(eMorphologyRadii);
1364 int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
1365 int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
1366 return aInputExtents[0].Inflated(nsIntMargin(ry, rx, ry, rx));
1367 }
1369 default:
1370 return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
1371 }
1372 }
1374 /* static */ nsIntRegion
1375 FilterSupport::ComputePostFilterExtents(const FilterDescription& aFilter,
1376 const nsIntRegion& aSourceGraphicExtents)
1377 {
1378 const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1379 nsIntRegion filterSpace = ThebesIntRect(aFilter.mFilterSpaceBounds);
1380 nsTArray<nsIntRegion> postFilterExtents;
1382 for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
1383 const FilterPrimitiveDescription& descr = primitives[i];
1385 nsTArray<nsIntRegion> inputExtents;
1386 for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1387 int32_t inputIndex = descr.InputPrimitiveIndex(j);
1388 MOZ_ASSERT(inputIndex < i, "bad input index");
1389 nsIntRegion inputExtent =
1390 ElementForIndex(inputIndex, postFilterExtents,
1391 aSourceGraphicExtents, filterSpace, filterSpace);
1392 inputExtents.AppendElement(inputExtent);
1393 }
1394 nsIntRegion extent = PostFilterExtentsForPrimitive(descr, inputExtents);
1395 IntRect cropRect =
1396 descr.PrimitiveSubregion().Intersect(aFilter.mFilterSpaceBounds);
1397 extent.And(extent, ThebesIntRect(cropRect));
1398 postFilterExtents.AppendElement(extent);
1399 }
1401 return postFilterExtents[postFilterExtents.Length() - 1];
1402 }
1404 static nsIntRegion
1405 SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
1406 const nsIntRegion& aResultNeededRegion,
1407 int32_t aInputIndex)
1408 {
1409 const AttributeMap& atts = aDescription.Attributes();
1410 switch (aDescription.Type()) {
1412 case PrimitiveType::Flood:
1413 case PrimitiveType::Turbulence:
1414 case PrimitiveType::Image:
1415 MOZ_CRASH("this shouldn't be called for filters without inputs");
1416 return nsIntRegion();
1418 case PrimitiveType::Empty:
1419 return nsIntRegion();
1421 case PrimitiveType::Blend:
1422 case PrimitiveType::Composite:
1423 case PrimitiveType::Merge:
1424 case PrimitiveType::ColorMatrix:
1425 case PrimitiveType::ComponentTransfer:
1426 return aResultNeededRegion;
1428 case PrimitiveType::Morphology:
1429 {
1430 Size radii = atts.GetSize(eMorphologyRadii);
1431 int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
1432 int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
1433 return aResultNeededRegion.Inflated(nsIntMargin(ry, rx, ry, rx));
1434 }
1436 case PrimitiveType::Tile:
1437 return nsIntRect(INT32_MIN/2, INT32_MIN/2, INT32_MAX, INT32_MAX);
1439 case PrimitiveType::ConvolveMatrix:
1440 {
1441 Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
1442 IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
1443 IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
1444 nsIntMargin m(ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
1445 ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)),
1446 ceil(kernelUnitLength.width * (target.x)),
1447 ceil(kernelUnitLength.height * (target.y)));
1448 return aResultNeededRegion.Inflated(m);
1449 }
1451 case PrimitiveType::Offset:
1452 {
1453 IntPoint offset = atts.GetIntPoint(eOffsetOffset);
1454 return aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
1455 }
1457 case PrimitiveType::DisplacementMap:
1458 {
1459 if (aInputIndex == 1) {
1460 return aResultNeededRegion;
1461 }
1462 int32_t scale = ceil(abs(atts.GetFloat(eDisplacementMapScale)));
1463 return aResultNeededRegion.Inflated(nsIntMargin(scale, scale, scale, scale));
1464 }
1466 case PrimitiveType::GaussianBlur:
1467 {
1468 Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
1469 int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1470 int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1471 return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1472 }
1474 case PrimitiveType::DropShadow:
1475 {
1476 IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
1477 nsIntRegion offsetRegion =
1478 aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
1479 Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
1480 int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1481 int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1482 nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1483 blurRegion.Or(blurRegion, aResultNeededRegion);
1484 return blurRegion;
1485 }
1487 case PrimitiveType::DiffuseLighting:
1488 case PrimitiveType::SpecularLighting:
1489 {
1490 Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
1491 int32_t dx = ceil(kernelUnitLength.width);
1492 int32_t dy = ceil(kernelUnitLength.height);
1493 return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1494 }
1496 default:
1497 return nsIntRegion();
1498 }
1500 }
1502 /* static */ void
1503 FilterSupport::ComputeSourceNeededRegions(const FilterDescription& aFilter,
1504 const nsIntRegion& aResultNeededRegion,
1505 nsIntRegion& aSourceGraphicNeededRegion,
1506 nsIntRegion& aFillPaintNeededRegion,
1507 nsIntRegion& aStrokePaintNeededRegion)
1508 {
1509 const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1510 nsTArray<nsIntRegion> primitiveNeededRegions;
1511 primitiveNeededRegions.AppendElements(primitives.Length());
1513 primitiveNeededRegions[primitives.Length() - 1] = aResultNeededRegion;
1515 for (int32_t i = primitives.Length() - 1; i >= 0; --i) {
1516 const FilterPrimitiveDescription& descr = primitives[i];
1517 nsIntRegion neededRegion = primitiveNeededRegions[i];
1518 neededRegion.And(neededRegion, ThebesIntRect(descr.PrimitiveSubregion()));
1520 for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1521 int32_t inputIndex = descr.InputPrimitiveIndex(j);
1522 MOZ_ASSERT(inputIndex < i, "bad input index");
1523 nsIntRegion* inputNeededRegion = const_cast<nsIntRegion*>(
1524 &ElementForIndex(inputIndex, primitiveNeededRegions,
1525 aSourceGraphicNeededRegion,
1526 aFillPaintNeededRegion, aStrokePaintNeededRegion));
1527 inputNeededRegion->Or(*inputNeededRegion,
1528 SourceNeededRegionForPrimitive(descr, neededRegion, j));
1529 }
1530 }
1532 aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
1533 ThebesIntRect(aFilter.mFilterSpaceBounds));
1534 }
1536 // FilterPrimitiveDescription
1538 FilterPrimitiveDescription::FilterPrimitiveDescription()
1539 : mType(PrimitiveType::Empty)
1540 , mOutputColorSpace(ColorSpace::SRGB)
1541 , mIsTainted(false)
1542 {
1543 }
1545 FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType)
1546 : mType(aType)
1547 , mOutputColorSpace(ColorSpace::SRGB)
1548 , mIsTainted(false)
1549 {
1550 }
1552 FilterPrimitiveDescription::FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther)
1553 : mType(aOther.mType)
1554 , mAttributes(aOther.mAttributes)
1555 , mInputPrimitives(aOther.mInputPrimitives)
1556 , mFilterPrimitiveSubregion(aOther.mFilterPrimitiveSubregion)
1557 , mInputColorSpaces(aOther.mInputColorSpaces)
1558 , mOutputColorSpace(aOther.mOutputColorSpace)
1559 , mIsTainted(aOther.mIsTainted)
1560 {
1561 }
1563 FilterPrimitiveDescription&
1564 FilterPrimitiveDescription::operator=(const FilterPrimitiveDescription& aOther)
1565 {
1566 if (this != &aOther) {
1567 mType = aOther.mType;
1568 mAttributes = aOther.mAttributes;
1569 mInputPrimitives = aOther.mInputPrimitives;
1570 mFilterPrimitiveSubregion = aOther.mFilterPrimitiveSubregion;
1571 mInputColorSpaces = aOther.mInputColorSpaces;
1572 mOutputColorSpace = aOther.mOutputColorSpace;
1573 mIsTainted = aOther.mIsTainted;
1574 }
1575 return *this;
1576 }
1578 bool
1579 FilterPrimitiveDescription::operator==(const FilterPrimitiveDescription& aOther) const
1580 {
1581 return mType == aOther.mType &&
1582 mFilterPrimitiveSubregion.IsEqualInterior(aOther.mFilterPrimitiveSubregion) &&
1583 mOutputColorSpace == aOther.mOutputColorSpace &&
1584 mIsTainted == aOther.mIsTainted &&
1585 mInputPrimitives == aOther.mInputPrimitives &&
1586 mInputColorSpaces == aOther.mInputColorSpaces &&
1587 mAttributes == aOther.mAttributes;
1588 }
1590 // FilterDescription
1592 bool
1593 FilterDescription::operator==(const FilterDescription& aOther) const
1594 {
1595 return mFilterSpaceBounds.IsEqualInterior(aOther.mFilterSpaceBounds) &&
1596 mPrimitives == aOther.mPrimitives;
1597 }
1599 // AttributeMap
1601 // A class that wraps different types for easy storage in a hashtable. Only
1602 // used by AttributeMap.
1603 struct FilterAttribute {
1604 FilterAttribute(const FilterAttribute& aOther);
1605 ~FilterAttribute();
1607 bool operator==(const FilterAttribute& aOther) const;
1608 bool operator!=(const FilterAttribute& aOther) const
1609 {
1610 return !(*this == aOther);
1611 }
1613 AttributeType Type() const { return mType; }
1615 #define MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(type, typeLabel) \
1616 FilterAttribute(type aValue) \
1617 : mType(AttributeType::e##typeLabel), m##typeLabel(aValue) \
1618 {} \
1619 type As##typeLabel() { \
1620 MOZ_ASSERT(mType == AttributeType::e##typeLabel); \
1621 return m##typeLabel; \
1622 }
1624 #define MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(className) \
1625 FilterAttribute(const className& aValue) \
1626 : mType(AttributeType::e##className), m##className(new className(aValue)) \
1627 {} \
1628 className As##className() { \
1629 MOZ_ASSERT(mType == AttributeType::e##className); \
1630 return *m##className; \
1631 }
1633 MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(bool, Bool)
1634 MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(uint32_t, Uint)
1635 MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(float, Float)
1636 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Size)
1637 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntSize)
1638 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntPoint)
1639 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix)
1640 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix5x4)
1641 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Point3D)
1642 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Color)
1643 MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(AttributeMap)
1645 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC
1646 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS
1648 FilterAttribute(const float* aValue, uint32_t aLength)
1649 : mType(AttributeType::eFloats)
1650 {
1651 mFloats = new nsTArray<float>();
1652 mFloats->AppendElements(aValue, aLength);
1653 }
1655 const nsTArray<float>& AsFloats() const {
1656 MOZ_ASSERT(mType == AttributeType::eFloats);
1657 return *mFloats;
1658 }
1660 private:
1661 const AttributeType mType;
1663 union {
1664 bool mBool;
1665 uint32_t mUint;
1666 float mFloat;
1667 Size* mSize;
1668 IntSize* mIntSize;
1669 IntPoint* mIntPoint;
1670 Matrix* mMatrix;
1671 Matrix5x4* mMatrix5x4;
1672 Point3D* mPoint3D;
1673 Color* mColor;
1674 AttributeMap* mAttributeMap;
1675 nsTArray<float>* mFloats;
1676 };
1677 };
1679 FilterAttribute::FilterAttribute(const FilterAttribute& aOther)
1680 : mType(aOther.mType)
1681 {
1682 switch (mType) {
1683 case AttributeType::eBool:
1684 mBool = aOther.mBool;
1685 break;
1686 case AttributeType::eUint:
1687 mUint = aOther.mUint;
1688 break;
1689 case AttributeType::eFloat:
1690 mFloat = aOther.mFloat;
1691 break;
1693 #define HANDLE_CLASS(className) \
1694 case AttributeType::e##className: \
1695 m##className = new className(*aOther.m##className); \
1696 break;
1698 HANDLE_CLASS(Size)
1699 HANDLE_CLASS(IntSize)
1700 HANDLE_CLASS(IntPoint)
1701 HANDLE_CLASS(Matrix)
1702 HANDLE_CLASS(Matrix5x4)
1703 HANDLE_CLASS(Point3D)
1704 HANDLE_CLASS(Color)
1705 HANDLE_CLASS(AttributeMap)
1707 #undef HANDLE_CLASS
1709 case AttributeType::eFloats:
1710 mFloats = new nsTArray<float>(*aOther.mFloats);
1711 break;
1712 case AttributeType::Max:
1713 break;
1714 }
1715 }
1717 FilterAttribute::~FilterAttribute() {
1718 switch (mType) {
1719 case AttributeType::Max:
1720 case AttributeType::eBool:
1721 case AttributeType::eUint:
1722 case AttributeType::eFloat:
1723 break;
1725 #define HANDLE_CLASS(className) \
1726 case AttributeType::e##className: \
1727 delete m##className; \
1728 break;
1730 HANDLE_CLASS(Size)
1731 HANDLE_CLASS(IntSize)
1732 HANDLE_CLASS(IntPoint)
1733 HANDLE_CLASS(Matrix)
1734 HANDLE_CLASS(Matrix5x4)
1735 HANDLE_CLASS(Point3D)
1736 HANDLE_CLASS(Color)
1737 HANDLE_CLASS(AttributeMap)
1739 #undef HANDLE_CLASS
1741 case AttributeType::eFloats:
1742 delete mFloats;
1743 break;
1744 }
1745 }
1747 bool
1748 FilterAttribute::operator==(const FilterAttribute& aOther) const
1749 {
1750 if (mType != aOther.mType) {
1751 return false;
1752 }
1754 switch (mType) {
1756 #define HANDLE_TYPE(typeName) \
1757 case AttributeType::e##typeName: \
1758 return m##typeName == aOther.m##typeName;
1760 HANDLE_TYPE(Bool)
1761 HANDLE_TYPE(Uint)
1762 HANDLE_TYPE(Float)
1763 HANDLE_TYPE(Size)
1764 HANDLE_TYPE(IntSize)
1765 HANDLE_TYPE(IntPoint)
1766 HANDLE_TYPE(Matrix)
1767 HANDLE_TYPE(Matrix5x4)
1768 HANDLE_TYPE(Point3D)
1769 HANDLE_TYPE(Color)
1770 HANDLE_TYPE(AttributeMap)
1771 HANDLE_TYPE(Floats)
1773 #undef HANDLE_TYPE
1775 default:
1776 return false;
1777 }
1778 }
1780 typedef FilterAttribute Attribute;
1782 AttributeMap::AttributeMap()
1783 {
1784 }
1786 AttributeMap::~AttributeMap()
1787 {
1788 }
1790 static PLDHashOperator
1791 CopyAttribute(const uint32_t& aAttributeName,
1792 Attribute* aAttribute,
1793 void* aAttributes)
1794 {
1795 typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
1796 Map* map = static_cast<Map*>(aAttributes);
1797 map->Put(aAttributeName, new Attribute(*aAttribute));
1798 return PL_DHASH_NEXT;
1799 }
1801 AttributeMap::AttributeMap(const AttributeMap& aOther)
1802 {
1803 aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
1804 }
1806 AttributeMap&
1807 AttributeMap::operator=(const AttributeMap& aOther)
1808 {
1809 if (this != &aOther) {
1810 mMap.Clear();
1811 aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
1812 }
1813 return *this;
1814 }
1816 namespace {
1817 struct MatchingMap {
1818 typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
1819 const Map& map;
1820 bool matches;
1821 };
1822 }
1824 static PLDHashOperator
1825 CheckAttributeEquality(const uint32_t& aAttributeName,
1826 Attribute* aAttribute,
1827 void* aMatchingMap)
1828 {
1829 MatchingMap& matchingMap = *static_cast<MatchingMap*>(aMatchingMap);
1830 Attribute* matchingAttribute = matchingMap.map.Get(aAttributeName);
1831 if (!matchingAttribute ||
1832 *matchingAttribute != *aAttribute) {
1833 matchingMap.matches = false;
1834 return PL_DHASH_STOP;
1835 }
1836 return PL_DHASH_NEXT;
1837 }
1839 bool
1840 AttributeMap::operator==(const AttributeMap& aOther) const
1841 {
1842 if (mMap.Count() != aOther.mMap.Count()) {
1843 return false;
1844 }
1846 MatchingMap matchingMap = { mMap, true };
1847 aOther.mMap.EnumerateRead(CheckAttributeEquality, &matchingMap);
1848 return matchingMap.matches;
1849 }
1851 namespace {
1852 struct HandlerWithUserData
1853 {
1854 AttributeMap::AttributeHandleCallback handler;
1855 void* userData;
1856 };
1857 }
1859 static PLDHashOperator
1860 PassAttributeToHandleCallback(const uint32_t& aAttributeName,
1861 Attribute* aAttribute,
1862 void* aHandlerWithUserData)
1863 {
1864 HandlerWithUserData* handlerWithUserData =
1865 static_cast<HandlerWithUserData*>(aHandlerWithUserData);
1866 return handlerWithUserData->handler(AttributeName(aAttributeName),
1867 aAttribute->Type(),
1868 handlerWithUserData->userData) ?
1869 PL_DHASH_NEXT : PL_DHASH_STOP;
1870 }
1872 void
1873 AttributeMap::EnumerateRead(AttributeMap::AttributeHandleCallback aCallback, void* aUserData) const
1874 {
1875 HandlerWithUserData handlerWithUserData = { aCallback, aUserData };
1876 mMap.EnumerateRead(PassAttributeToHandleCallback, &handlerWithUserData);
1877 }
1879 uint32_t
1880 AttributeMap::Count() const
1881 {
1882 return mMap.Count();
1883 }
1885 #define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \
1886 type \
1887 AttributeMap::Get##typeLabel(AttributeName aName) const { \
1888 Attribute* value = mMap.Get(aName); \
1889 return value ? value->As##typeLabel() : defaultValue; \
1890 } \
1891 void \
1892 AttributeMap::Set(AttributeName aName, type aValue) { \
1893 mMap.Remove(aName); \
1894 mMap.Put(aName, new Attribute(aValue)); \
1895 }
1897 #define MAKE_ATTRIBUTE_HANDLERS_CLASS(className) \
1898 className \
1899 AttributeMap::Get##className(AttributeName aName) const { \
1900 Attribute* value = mMap.Get(aName); \
1901 return value ? value->As##className() : className(); \
1902 } \
1903 void \
1904 AttributeMap::Set(AttributeName aName, const className& aValue) { \
1905 mMap.Remove(aName); \
1906 mMap.Put(aName, new Attribute(aValue)); \
1907 }
1909 MAKE_ATTRIBUTE_HANDLERS_BASIC(bool, Bool, false)
1910 MAKE_ATTRIBUTE_HANDLERS_BASIC(uint32_t, Uint, 0)
1911 MAKE_ATTRIBUTE_HANDLERS_BASIC(float, Float, 0)
1912 MAKE_ATTRIBUTE_HANDLERS_CLASS(Size)
1913 MAKE_ATTRIBUTE_HANDLERS_CLASS(IntSize)
1914 MAKE_ATTRIBUTE_HANDLERS_CLASS(IntPoint)
1915 MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix)
1916 MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix5x4)
1917 MAKE_ATTRIBUTE_HANDLERS_CLASS(Point3D)
1918 MAKE_ATTRIBUTE_HANDLERS_CLASS(Color)
1919 MAKE_ATTRIBUTE_HANDLERS_CLASS(AttributeMap)
1921 #undef MAKE_ATTRIBUTE_HANDLERS_BASIC
1922 #undef MAKE_ATTRIBUTE_HANDLERS_CLASS
1924 const nsTArray<float>&
1925 AttributeMap::GetFloats(AttributeName aName) const
1926 {
1927 Attribute* value = mMap.Get(aName);
1928 if (!value) {
1929 value = new Attribute(nullptr, 0);
1930 mMap.Put(aName, value);
1931 }
1932 return value->AsFloats();
1933 }
1935 void
1936 AttributeMap::Set(AttributeName aName, const float* aValues, int32_t aLength)
1937 {
1938 mMap.Remove(aName);
1939 mMap.Put(aName, new Attribute(aValues, aLength));
1940 }
1942 }
1943 }