Line data Source code
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/. */
5 :
6 : #include "FilterSupport.h"
7 :
8 : #include "mozilla/gfx/2D.h"
9 : #include "mozilla/gfx/Filters.h"
10 : #include "mozilla/gfx/Logging.h"
11 : #include "mozilla/PodOperations.h"
12 :
13 : #include "gfxContext.h"
14 : #include "gfxPattern.h"
15 : #include "gfxPlatform.h"
16 : #include "gfx2DGlue.h"
17 :
18 : #include "nsMargin.h"
19 :
20 : // c = n / 255
21 : // c <= 0.0031308f ? c * 12.92f : 1.055f * powf(c, 1 / 2.4f) - 0.055f
22 : static const float glinearRGBTosRGBMap[256] = {
23 : 0.000f, 0.050f, 0.085f, 0.111f, 0.132f, 0.150f, 0.166f, 0.181f,
24 : 0.194f, 0.207f, 0.219f, 0.230f, 0.240f, 0.250f, 0.260f, 0.269f,
25 : 0.278f, 0.286f, 0.295f, 0.303f, 0.310f, 0.318f, 0.325f, 0.332f,
26 : 0.339f, 0.346f, 0.352f, 0.359f, 0.365f, 0.371f, 0.378f, 0.383f,
27 : 0.389f, 0.395f, 0.401f, 0.406f, 0.412f, 0.417f, 0.422f, 0.427f,
28 : 0.433f, 0.438f, 0.443f, 0.448f, 0.452f, 0.457f, 0.462f, 0.466f,
29 : 0.471f, 0.476f, 0.480f, 0.485f, 0.489f, 0.493f, 0.498f, 0.502f,
30 : 0.506f, 0.510f, 0.514f, 0.518f, 0.522f, 0.526f, 0.530f, 0.534f,
31 : 0.538f, 0.542f, 0.546f, 0.549f, 0.553f, 0.557f, 0.561f, 0.564f,
32 : 0.568f, 0.571f, 0.575f, 0.579f, 0.582f, 0.586f, 0.589f, 0.592f,
33 : 0.596f, 0.599f, 0.603f, 0.606f, 0.609f, 0.613f, 0.616f, 0.619f,
34 : 0.622f, 0.625f, 0.629f, 0.632f, 0.635f, 0.638f, 0.641f, 0.644f,
35 : 0.647f, 0.650f, 0.653f, 0.656f, 0.659f, 0.662f, 0.665f, 0.668f,
36 : 0.671f, 0.674f, 0.677f, 0.680f, 0.683f, 0.685f, 0.688f, 0.691f,
37 : 0.694f, 0.697f, 0.699f, 0.702f, 0.705f, 0.708f, 0.710f, 0.713f,
38 : 0.716f, 0.718f, 0.721f, 0.724f, 0.726f, 0.729f, 0.731f, 0.734f,
39 : 0.737f, 0.739f, 0.742f, 0.744f, 0.747f, 0.749f, 0.752f, 0.754f,
40 : 0.757f, 0.759f, 0.762f, 0.764f, 0.767f, 0.769f, 0.772f, 0.774f,
41 : 0.776f, 0.779f, 0.781f, 0.784f, 0.786f, 0.788f, 0.791f, 0.793f,
42 : 0.795f, 0.798f, 0.800f, 0.802f, 0.805f, 0.807f, 0.809f, 0.812f,
43 : 0.814f, 0.816f, 0.818f, 0.821f, 0.823f, 0.825f, 0.827f, 0.829f,
44 : 0.832f, 0.834f, 0.836f, 0.838f, 0.840f, 0.843f, 0.845f, 0.847f,
45 : 0.849f, 0.851f, 0.853f, 0.855f, 0.857f, 0.860f, 0.862f, 0.864f,
46 : 0.866f, 0.868f, 0.870f, 0.872f, 0.874f, 0.876f, 0.878f, 0.880f,
47 : 0.882f, 0.884f, 0.886f, 0.888f, 0.890f, 0.892f, 0.894f, 0.896f,
48 : 0.898f, 0.900f, 0.902f, 0.904f, 0.906f, 0.908f, 0.910f, 0.912f,
49 : 0.914f, 0.916f, 0.918f, 0.920f, 0.922f, 0.924f, 0.926f, 0.928f,
50 : 0.930f, 0.931f, 0.933f, 0.935f, 0.937f, 0.939f, 0.941f, 0.943f,
51 : 0.945f, 0.946f, 0.948f, 0.950f, 0.952f, 0.954f, 0.956f, 0.957f,
52 : 0.959f, 0.961f, 0.963f, 0.965f, 0.967f, 0.968f, 0.970f, 0.972f,
53 : 0.974f, 0.975f, 0.977f, 0.979f, 0.981f, 0.983f, 0.984f, 0.986f,
54 : 0.988f, 0.990f, 0.991f, 0.993f, 0.995f, 0.997f, 0.998f, 1.000f
55 : };
56 :
57 : // c = n / 255
58 : // c <= 0.04045f ? c / 12.92f : powf((c + 0.055f) / 1.055f, 2.4f)
59 : static const float gsRGBToLinearRGBMap[256] = {
60 : 0.000f, 0.000f, 0.001f, 0.001f, 0.001f, 0.002f, 0.002f, 0.002f,
61 : 0.002f, 0.003f, 0.003f, 0.003f, 0.004f, 0.004f, 0.004f, 0.005f,
62 : 0.005f, 0.006f, 0.006f, 0.007f, 0.007f, 0.007f, 0.008f, 0.009f,
63 : 0.009f, 0.010f, 0.010f, 0.011f, 0.012f, 0.012f, 0.013f, 0.014f,
64 : 0.014f, 0.015f, 0.016f, 0.017f, 0.018f, 0.019f, 0.019f, 0.020f,
65 : 0.021f, 0.022f, 0.023f, 0.024f, 0.025f, 0.026f, 0.027f, 0.028f,
66 : 0.030f, 0.031f, 0.032f, 0.033f, 0.034f, 0.036f, 0.037f, 0.038f,
67 : 0.040f, 0.041f, 0.042f, 0.044f, 0.045f, 0.047f, 0.048f, 0.050f,
68 : 0.051f, 0.053f, 0.054f, 0.056f, 0.058f, 0.060f, 0.061f, 0.063f,
69 : 0.065f, 0.067f, 0.068f, 0.070f, 0.072f, 0.074f, 0.076f, 0.078f,
70 : 0.080f, 0.082f, 0.084f, 0.087f, 0.089f, 0.091f, 0.093f, 0.095f,
71 : 0.098f, 0.100f, 0.102f, 0.105f, 0.107f, 0.109f, 0.112f, 0.114f,
72 : 0.117f, 0.120f, 0.122f, 0.125f, 0.127f, 0.130f, 0.133f, 0.136f,
73 : 0.138f, 0.141f, 0.144f, 0.147f, 0.150f, 0.153f, 0.156f, 0.159f,
74 : 0.162f, 0.165f, 0.168f, 0.171f, 0.175f, 0.178f, 0.181f, 0.184f,
75 : 0.188f, 0.191f, 0.195f, 0.198f, 0.202f, 0.205f, 0.209f, 0.212f,
76 : 0.216f, 0.220f, 0.223f, 0.227f, 0.231f, 0.235f, 0.238f, 0.242f,
77 : 0.246f, 0.250f, 0.254f, 0.258f, 0.262f, 0.266f, 0.270f, 0.275f,
78 : 0.279f, 0.283f, 0.287f, 0.292f, 0.296f, 0.301f, 0.305f, 0.309f,
79 : 0.314f, 0.319f, 0.323f, 0.328f, 0.332f, 0.337f, 0.342f, 0.347f,
80 : 0.352f, 0.356f, 0.361f, 0.366f, 0.371f, 0.376f, 0.381f, 0.386f,
81 : 0.392f, 0.397f, 0.402f, 0.407f, 0.413f, 0.418f, 0.423f, 0.429f,
82 : 0.434f, 0.440f, 0.445f, 0.451f, 0.456f, 0.462f, 0.468f, 0.474f,
83 : 0.479f, 0.485f, 0.491f, 0.497f, 0.503f, 0.509f, 0.515f, 0.521f,
84 : 0.527f, 0.533f, 0.539f, 0.546f, 0.552f, 0.558f, 0.565f, 0.571f,
85 : 0.578f, 0.584f, 0.591f, 0.597f, 0.604f, 0.610f, 0.617f, 0.624f,
86 : 0.631f, 0.638f, 0.644f, 0.651f, 0.658f, 0.665f, 0.672f, 0.680f,
87 : 0.687f, 0.694f, 0.701f, 0.708f, 0.716f, 0.723f, 0.730f, 0.738f,
88 : 0.745f, 0.753f, 0.761f, 0.768f, 0.776f, 0.784f, 0.791f, 0.799f,
89 : 0.807f, 0.815f, 0.823f, 0.831f, 0.839f, 0.847f, 0.855f, 0.863f,
90 : 0.871f, 0.880f, 0.888f, 0.896f, 0.905f, 0.913f, 0.922f, 0.930f,
91 : 0.939f, 0.947f, 0.956f, 0.965f, 0.973f, 0.982f, 0.991f, 1.000f
92 : };
93 :
94 : namespace mozilla {
95 : namespace gfx {
96 :
97 : // Some convenience FilterNode creation functions.
98 :
99 : namespace FilterWrappers {
100 :
101 : static already_AddRefed<FilterNode>
102 0 : Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
103 : {
104 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
105 0 : if (filter) {
106 0 : filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
107 0 : return filter.forget();
108 : }
109 0 : return nullptr;
110 : }
111 :
112 : static already_AddRefed<FilterNode>
113 0 : Premultiply(DrawTarget* aDT, FilterNode* aInput)
114 : {
115 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::PREMULTIPLY);
116 0 : if (filter) {
117 0 : filter->SetInput(IN_PREMULTIPLY_IN, aInput);
118 0 : return filter.forget();
119 : }
120 0 : return nullptr;
121 : }
122 :
123 : static already_AddRefed<FilterNode>
124 0 : LinearRGBToSRGB(DrawTarget* aDT, FilterNode* aInput)
125 : {
126 0 : RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
127 0 : if (transfer) {
128 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
129 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
130 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
131 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
132 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
133 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
134 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
135 0 : transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
136 0 : return transfer.forget();
137 : }
138 0 : return nullptr;
139 : }
140 :
141 : static already_AddRefed<FilterNode>
142 0 : SRGBToLinearRGB(DrawTarget* aDT, FilterNode* aInput)
143 : {
144 0 : RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
145 0 : if (transfer) {
146 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
147 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
148 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
149 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
150 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
151 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
152 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
153 0 : transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
154 0 : return transfer.forget();
155 : }
156 0 : return nullptr;
157 : }
158 :
159 : static already_AddRefed<FilterNode>
160 0 : Crop(DrawTarget* aDT, FilterNode* aInputFilter, const IntRect& aRect)
161 : {
162 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CROP);
163 0 : if (filter) {
164 0 : filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
165 0 : filter->SetInput(IN_CROP_IN, aInputFilter);
166 0 : return filter.forget();
167 : }
168 0 : return nullptr;
169 : }
170 :
171 : static already_AddRefed<FilterNode>
172 0 : Offset(DrawTarget* aDT, FilterNode* aInputFilter, const IntPoint& aOffset)
173 : {
174 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
175 0 : if (filter) {
176 0 : filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
177 0 : filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
178 0 : return filter.forget();
179 : }
180 0 : return nullptr;
181 : }
182 :
183 : static already_AddRefed<FilterNode>
184 0 : GaussianBlur(DrawTarget* aDT, FilterNode* aInputFilter, const Size& aStdDeviation)
185 : {
186 0 : float stdX = float(std::min(aStdDeviation.width, kMaxStdDeviation));
187 0 : float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
188 0 : if (stdX == stdY) {
189 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
190 0 : if (filter) {
191 0 : filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
192 0 : filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
193 0 : return filter.forget();
194 : }
195 0 : return nullptr;
196 : }
197 0 : RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
198 0 : RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
199 0 : if (filterH && filterV) {
200 0 : filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
201 0 : filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
202 0 : filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
203 0 : filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
204 0 : filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
205 0 : filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
206 0 : return filterV.forget();
207 : }
208 0 : return nullptr;
209 : }
210 :
211 : static already_AddRefed<FilterNode>
212 0 : Clear(DrawTarget* aDT)
213 : {
214 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
215 0 : if (filter) {
216 0 : filter->SetAttribute(ATT_FLOOD_COLOR, Color(0, 0, 0, 0));
217 0 : return filter.forget();
218 : }
219 0 : return nullptr;
220 : }
221 :
222 : static already_AddRefed<FilterNode>
223 0 : ForSurface(DrawTarget* aDT, SourceSurface* aSurface,
224 : const IntPoint& aSurfacePosition)
225 : {
226 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
227 0 : if (filter) {
228 0 : filter->SetAttribute(ATT_TRANSFORM_MATRIX,
229 0 : Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
230 0 : filter->SetInput(IN_TRANSFORM_IN, aSurface);
231 0 : return filter.forget();
232 : }
233 0 : return nullptr;
234 : }
235 :
236 : static already_AddRefed<FilterNode>
237 0 : ToAlpha(DrawTarget* aDT, FilterNode* aInput)
238 : {
239 0 : float zero = 0.0f;
240 0 : RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
241 0 : if (transfer) {
242 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
243 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
244 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
245 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
246 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
247 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
248 0 : transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
249 0 : transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
250 0 : return transfer.forget();
251 : }
252 0 : return nullptr;
253 : }
254 :
255 : } // namespace FilterWrappers
256 :
257 : // A class that wraps a FilterNode and handles conversion between different
258 : // color models. Create FilterCachedColorModels with your original filter and
259 : // the color model that this filter outputs in natively, and then call
260 : // ->ForColorModel(colorModel) in order to get a FilterNode which outputs to
261 : // the specified colorModel.
262 : // Internally, this is achieved by wrapping the original FilterNode with
263 : // conversion FilterNodes. These filter nodes are cached in such a way that no
264 : // repeated or back-and-forth conversions happen.
265 : class FilterCachedColorModels
266 : {
267 : public:
268 0 : NS_INLINE_DECL_REFCOUNTING(FilterCachedColorModels)
269 : // aFilter can be null. In that case, ForColorModel will return a non-null
270 : // completely transparent filter for all color models.
271 : FilterCachedColorModels(DrawTarget* aDT,
272 : FilterNode* aFilter,
273 : ColorModel aOriginalColorModel);
274 :
275 : // Get a FilterNode for the specified color model, guaranteed to be non-null.
276 : already_AddRefed<FilterNode> ForColorModel(ColorModel aColorModel);
277 :
278 0 : AlphaModel OriginalAlphaModel() const { return mOriginalColorModel.mAlphaModel; }
279 :
280 : private:
281 : // Create the required FilterNode that will be cached by ForColorModel.
282 : already_AddRefed<FilterNode> WrapForColorModel(ColorModel aColorModel);
283 :
284 : RefPtr<DrawTarget> mDT;
285 : ColorModel mOriginalColorModel;
286 :
287 : // This array is indexed by ColorModel::ToIndex.
288 : RefPtr<FilterNode> mFilterForColorModel[4];
289 :
290 0 : ~FilterCachedColorModels() {}
291 : };
292 :
293 0 : FilterCachedColorModels::FilterCachedColorModels(DrawTarget* aDT,
294 : FilterNode* aFilter,
295 0 : ColorModel aOriginalColorModel)
296 : : mDT(aDT)
297 0 : , mOriginalColorModel(aOriginalColorModel)
298 : {
299 0 : if (aFilter) {
300 0 : mFilterForColorModel[aOriginalColorModel.ToIndex()] = aFilter;
301 : } else {
302 0 : RefPtr<FilterNode> clear = FilterWrappers::Clear(aDT);
303 0 : mFilterForColorModel[0] = clear;
304 0 : mFilterForColorModel[1] = clear;
305 0 : mFilterForColorModel[2] = clear;
306 0 : mFilterForColorModel[3] = clear;
307 : }
308 0 : }
309 :
310 : already_AddRefed<FilterNode>
311 0 : FilterCachedColorModels::ForColorModel(ColorModel aColorModel)
312 : {
313 0 : if (aColorModel == mOriginalColorModel) {
314 : // Make sure to not call WrapForColorModel if our original filter node was
315 : // null, because then we'd get an infinite recursion.
316 0 : RefPtr<FilterNode> filter = mFilterForColorModel[mOriginalColorModel.ToIndex()];
317 0 : return filter.forget();
318 : }
319 :
320 0 : if (!mFilterForColorModel[aColorModel.ToIndex()]) {
321 0 : mFilterForColorModel[aColorModel.ToIndex()] = WrapForColorModel(aColorModel);
322 : }
323 0 : RefPtr<FilterNode> filter(mFilterForColorModel[aColorModel.ToIndex()]);
324 0 : return filter.forget();
325 : }
326 :
327 : already_AddRefed<FilterNode>
328 0 : FilterCachedColorModels::WrapForColorModel(ColorModel aColorModel)
329 : {
330 : // Convert one aspect at a time and recurse.
331 : // Conversions between premultiplied / unpremultiplied color channels for the
332 : // same color space can happen directly.
333 : // Conversions between different color spaces can only happen on
334 : // unpremultiplied color channels.
335 :
336 0 : if (aColorModel.mAlphaModel == AlphaModel::Premultiplied) {
337 : RefPtr<FilterNode> unpre =
338 0 : ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Unpremultiplied));
339 0 : return FilterWrappers::Premultiply(mDT, unpre);
340 : }
341 :
342 0 : MOZ_ASSERT(aColorModel.mAlphaModel == AlphaModel::Unpremultiplied);
343 0 : if (aColorModel.mColorSpace == mOriginalColorModel.mColorSpace) {
344 : RefPtr<FilterNode> premultiplied =
345 0 : ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Premultiplied));
346 0 : return FilterWrappers::Unpremultiply(mDT, premultiplied);
347 : }
348 :
349 : RefPtr<FilterNode> unpremultipliedOriginal =
350 0 : ForColorModel(ColorModel(mOriginalColorModel.mColorSpace, AlphaModel::Unpremultiplied));
351 0 : if (aColorModel.mColorSpace == ColorSpace::LinearRGB) {
352 0 : return FilterWrappers::SRGBToLinearRGB(mDT, unpremultipliedOriginal);
353 : }
354 0 : return FilterWrappers::LinearRGBToSRGB(mDT, unpremultipliedOriginal);
355 : }
356 :
357 : static const float identityMatrix[] =
358 : { 1, 0, 0, 0, 0,
359 : 0, 1, 0, 0, 0,
360 : 0, 0, 1, 0, 0,
361 : 0, 0, 0, 1, 0 };
362 :
363 : // When aAmount == 0, the identity matrix is returned.
364 : // When aAmount == 1, aToMatrix is returned.
365 : // When aAmount > 1, an exaggerated version of aToMatrix is returned. This can
366 : // be useful in certain cases, such as producing a color matrix to oversaturate
367 : // an image.
368 : //
369 : // This function is a shortcut of a full matrix addition and a scalar multiply,
370 : // and it assumes that the following elements in aToMatrix are 0 and 1:
371 : // x x x 0 0
372 : // x x x 0 0
373 : // x x x 0 0
374 : // 0 0 0 1 0
375 : static void
376 0 : InterpolateFromIdentityMatrix(const float aToMatrix[20], float aAmount,
377 : float aOutMatrix[20])
378 : {
379 0 : PodCopy(aOutMatrix, identityMatrix, 20);
380 :
381 0 : float oneMinusAmount = 1 - aAmount;
382 :
383 0 : aOutMatrix[0] = aAmount * aToMatrix[0] + oneMinusAmount;
384 0 : aOutMatrix[1] = aAmount * aToMatrix[1];
385 0 : aOutMatrix[2] = aAmount * aToMatrix[2];
386 :
387 0 : aOutMatrix[5] = aAmount * aToMatrix[5];
388 0 : aOutMatrix[6] = aAmount * aToMatrix[6] + oneMinusAmount;
389 0 : aOutMatrix[7] = aAmount * aToMatrix[7];
390 :
391 0 : aOutMatrix[10] = aAmount * aToMatrix[10];
392 0 : aOutMatrix[11] = aAmount * aToMatrix[11];
393 0 : aOutMatrix[12] = aAmount * aToMatrix[12] + oneMinusAmount;
394 0 : }
395 :
396 : // Create a 4x5 color matrix for the different ways to specify color matrices
397 : // in SVG.
398 : static nsresult
399 0 : ComputeColorMatrix(uint32_t aColorMatrixType, const nsTArray<float>& aValues,
400 : float aOutMatrix[20])
401 : {
402 : // Luminance coefficients.
403 : static const float lumR = 0.2126f;
404 : static const float lumG = 0.7152f;
405 : static const float lumB = 0.0722f;
406 :
407 : static const float oneMinusLumR = 1 - lumR;
408 : static const float oneMinusLumG = 1 - lumG;
409 : static const float oneMinusLumB = 1 - lumB;
410 :
411 : static const float luminanceToAlphaMatrix[] =
412 : { 0, 0, 0, 0, 0,
413 : 0, 0, 0, 0, 0,
414 : 0, 0, 0, 0, 0,
415 : lumR, lumG, lumB, 0, 0 };
416 :
417 : static const float saturateMatrix[] =
418 : { lumR, lumG, lumB, 0, 0,
419 : lumR, lumG, lumB, 0, 0,
420 : lumR, lumG, lumB, 0, 0,
421 : 0, 0, 0, 1, 0 };
422 :
423 : static const float sepiaMatrix[] =
424 : { 0.393f, 0.769f, 0.189f, 0, 0,
425 : 0.349f, 0.686f, 0.168f, 0, 0,
426 : 0.272f, 0.534f, 0.131f, 0, 0,
427 : 0, 0, 0, 1, 0 };
428 :
429 : // Hue rotate specific coefficients.
430 : static const float hueRotateR = 0.143f;
431 : static const float hueRotateG = 0.140f;
432 : static const float hueRotateB = 0.283f;
433 :
434 0 : switch (aColorMatrixType) {
435 :
436 : case SVG_FECOLORMATRIX_TYPE_MATRIX:
437 : {
438 0 : if (aValues.Length() != 20) {
439 0 : return NS_ERROR_FAILURE;
440 : }
441 :
442 0 : PodCopy(aOutMatrix, aValues.Elements(), 20);
443 0 : break;
444 : }
445 :
446 : case SVG_FECOLORMATRIX_TYPE_SATURATE:
447 : {
448 0 : if (aValues.Length() != 1)
449 0 : return NS_ERROR_FAILURE;
450 :
451 0 : float s = aValues[0];
452 :
453 0 : if (s < 0)
454 0 : return NS_ERROR_FAILURE;
455 :
456 0 : InterpolateFromIdentityMatrix(saturateMatrix, 1 - s, aOutMatrix);
457 0 : break;
458 : }
459 :
460 : case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE:
461 : {
462 0 : if (aValues.Length() != 1)
463 0 : return NS_ERROR_FAILURE;
464 :
465 0 : PodCopy(aOutMatrix, identityMatrix, 20);
466 :
467 0 : float hueRotateValue = aValues[0];
468 :
469 0 : float c = static_cast<float>(cos(hueRotateValue * M_PI / 180));
470 0 : float s = static_cast<float>(sin(hueRotateValue * M_PI / 180));
471 :
472 0 : aOutMatrix[0] = lumR + oneMinusLumR * c - lumR * s;
473 0 : aOutMatrix[1] = lumG - lumG * c - lumG * s;
474 0 : aOutMatrix[2] = lumB - lumB * c + oneMinusLumB * s;
475 :
476 0 : aOutMatrix[5] = lumR - lumR * c + hueRotateR * s;
477 0 : aOutMatrix[6] = lumG + oneMinusLumG * c + hueRotateG * s;
478 0 : aOutMatrix[7] = lumB - lumB * c - hueRotateB * s;
479 :
480 0 : aOutMatrix[10] = lumR - lumR * c - oneMinusLumR * s;
481 0 : aOutMatrix[11] = lumG - lumG * c + lumG * s;
482 0 : aOutMatrix[12] = lumB + oneMinusLumB * c + lumB * s;
483 :
484 0 : break;
485 : }
486 :
487 : case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA:
488 : {
489 0 : PodCopy(aOutMatrix, luminanceToAlphaMatrix, 20);
490 0 : break;
491 : }
492 :
493 : case SVG_FECOLORMATRIX_TYPE_SEPIA:
494 : {
495 0 : if (aValues.Length() != 1)
496 0 : return NS_ERROR_FAILURE;
497 :
498 0 : float amount = aValues[0];
499 :
500 0 : if (amount < 0 || amount > 1)
501 0 : return NS_ERROR_FAILURE;
502 :
503 0 : InterpolateFromIdentityMatrix(sepiaMatrix, amount, aOutMatrix);
504 0 : break;
505 : }
506 :
507 : default:
508 0 : return NS_ERROR_FAILURE;
509 :
510 : }
511 :
512 0 : return NS_OK;
513 : }
514 :
515 : static void
516 0 : DisableAllTransfers(FilterNode* aTransferFilterNode)
517 : {
518 0 : aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_R, true);
519 0 : aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_G, true);
520 0 : aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_B, true);
521 0 : aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_A, true);
522 0 : }
523 :
524 : // Called for one channel at a time.
525 : // This function creates the required FilterNodes on demand and tries to
526 : // merge conversions of different channels into the same FilterNode if
527 : // possible.
528 : // There's a mismatch between the way SVG and the Moz2D API handle transfer
529 : // functions: In SVG, it's possible to specify a different transfer function
530 : // type for each color channel, but in Moz2D, a given transfer function type
531 : // applies to all color channels.
532 : //
533 : // @param aFunctionAttributes The attributes of the transfer function for this
534 : // channel.
535 : // @param aChannel The color channel that this function applies to, where
536 : // 0 = red, 1 = green, 2 = blue, 3 = alpha
537 : // @param aDT The DrawTarget that the FilterNodes should be created for.
538 : // @param aTableTransfer Existing FilterNode holders (which may still be
539 : // null) that the resulting FilterNodes from this
540 : // function will be stored in.
541 : //
542 : static void
543 0 : ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes,
544 : int32_t aChannel,
545 : DrawTarget* aDT,
546 : RefPtr<FilterNode>& aTableTransfer,
547 : RefPtr<FilterNode>& aDiscreteTransfer,
548 : RefPtr<FilterNode>& aLinearTransfer,
549 : RefPtr<FilterNode>& aGammaTransfer)
550 : {
551 : static const TransferAtts disableAtt[4] = {
552 : ATT_TRANSFER_DISABLE_R,
553 : ATT_TRANSFER_DISABLE_G,
554 : ATT_TRANSFER_DISABLE_B,
555 : ATT_TRANSFER_DISABLE_A
556 : };
557 :
558 0 : RefPtr<FilterNode> filter;
559 :
560 0 : uint32_t type = aFunctionAttributes.GetUint(eComponentTransferFunctionType);
561 :
562 0 : switch (type) {
563 : case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
564 : {
565 : const nsTArray<float>& tableValues =
566 0 : aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
567 0 : if (tableValues.Length() < 2)
568 0 : return;
569 :
570 0 : if (!aTableTransfer) {
571 0 : aTableTransfer = aDT->CreateFilter(FilterType::TABLE_TRANSFER);
572 0 : if (!aTableTransfer) {
573 0 : return;
574 : }
575 0 : DisableAllTransfers(aTableTransfer);
576 : }
577 0 : filter = aTableTransfer;
578 : static const TableTransferAtts tableAtt[4] = {
579 : ATT_TABLE_TRANSFER_TABLE_R,
580 : ATT_TABLE_TRANSFER_TABLE_G,
581 : ATT_TABLE_TRANSFER_TABLE_B,
582 : ATT_TABLE_TRANSFER_TABLE_A
583 : };
584 0 : filter->SetAttribute(disableAtt[aChannel], false);
585 0 : filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
586 0 : break;
587 : }
588 :
589 : case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
590 : {
591 : const nsTArray<float>& tableValues =
592 0 : aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
593 0 : if (tableValues.Length() < 1)
594 0 : return;
595 :
596 0 : if (!aDiscreteTransfer) {
597 0 : aDiscreteTransfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
598 0 : if (!aDiscreteTransfer) {
599 0 : return;
600 : }
601 0 : DisableAllTransfers(aDiscreteTransfer);
602 : }
603 0 : filter = aDiscreteTransfer;
604 : static const DiscreteTransferAtts tableAtt[4] = {
605 : ATT_DISCRETE_TRANSFER_TABLE_R,
606 : ATT_DISCRETE_TRANSFER_TABLE_G,
607 : ATT_DISCRETE_TRANSFER_TABLE_B,
608 : ATT_DISCRETE_TRANSFER_TABLE_A
609 : };
610 0 : filter->SetAttribute(disableAtt[aChannel], false);
611 0 : filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
612 :
613 0 : break;
614 : }
615 :
616 : case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
617 : {
618 : static const LinearTransferAtts slopeAtt[4] = {
619 : ATT_LINEAR_TRANSFER_SLOPE_R,
620 : ATT_LINEAR_TRANSFER_SLOPE_G,
621 : ATT_LINEAR_TRANSFER_SLOPE_B,
622 : ATT_LINEAR_TRANSFER_SLOPE_A
623 : };
624 : static const LinearTransferAtts interceptAtt[4] = {
625 : ATT_LINEAR_TRANSFER_INTERCEPT_R,
626 : ATT_LINEAR_TRANSFER_INTERCEPT_G,
627 : ATT_LINEAR_TRANSFER_INTERCEPT_B,
628 : ATT_LINEAR_TRANSFER_INTERCEPT_A
629 : };
630 0 : if (!aLinearTransfer) {
631 0 : aLinearTransfer = aDT->CreateFilter(FilterType::LINEAR_TRANSFER);
632 0 : if (!aLinearTransfer) {
633 0 : return;
634 : }
635 0 : DisableAllTransfers(aLinearTransfer);
636 : }
637 0 : filter = aLinearTransfer;
638 0 : filter->SetAttribute(disableAtt[aChannel], false);
639 0 : float slope = aFunctionAttributes.GetFloat(eComponentTransferFunctionSlope);
640 0 : float intercept = aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
641 0 : filter->SetAttribute(slopeAtt[aChannel], slope);
642 0 : filter->SetAttribute(interceptAtt[aChannel], intercept);
643 0 : break;
644 : }
645 :
646 : case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
647 : {
648 : static const GammaTransferAtts amplitudeAtt[4] = {
649 : ATT_GAMMA_TRANSFER_AMPLITUDE_R,
650 : ATT_GAMMA_TRANSFER_AMPLITUDE_G,
651 : ATT_GAMMA_TRANSFER_AMPLITUDE_B,
652 : ATT_GAMMA_TRANSFER_AMPLITUDE_A
653 : };
654 : static const GammaTransferAtts exponentAtt[4] = {
655 : ATT_GAMMA_TRANSFER_EXPONENT_R,
656 : ATT_GAMMA_TRANSFER_EXPONENT_G,
657 : ATT_GAMMA_TRANSFER_EXPONENT_B,
658 : ATT_GAMMA_TRANSFER_EXPONENT_A
659 : };
660 : static const GammaTransferAtts offsetAtt[4] = {
661 : ATT_GAMMA_TRANSFER_OFFSET_R,
662 : ATT_GAMMA_TRANSFER_OFFSET_G,
663 : ATT_GAMMA_TRANSFER_OFFSET_B,
664 : ATT_GAMMA_TRANSFER_OFFSET_A
665 : };
666 0 : if (!aGammaTransfer) {
667 0 : aGammaTransfer = aDT->CreateFilter(FilterType::GAMMA_TRANSFER);
668 0 : if (!aGammaTransfer) {
669 0 : return;
670 : }
671 0 : DisableAllTransfers(aGammaTransfer);
672 : }
673 0 : filter = aGammaTransfer;
674 0 : filter->SetAttribute(disableAtt[aChannel], false);
675 0 : float amplitude = aFunctionAttributes.GetFloat(eComponentTransferFunctionAmplitude);
676 0 : float exponent = aFunctionAttributes.GetFloat(eComponentTransferFunctionExponent);
677 0 : float offset = aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
678 0 : filter->SetAttribute(amplitudeAtt[aChannel], amplitude);
679 0 : filter->SetAttribute(exponentAtt[aChannel], exponent);
680 0 : filter->SetAttribute(offsetAtt[aChannel], offset);
681 0 : break;
682 : }
683 :
684 : case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
685 : default:
686 0 : break;
687 : }
688 : }
689 :
690 : const int32_t kMorphologyMaxRadius = 100000;
691 :
692 : // Handle the different primitive description types and create the necessary
693 : // FilterNode(s) for each.
694 : // Returns nullptr for invalid filter primitives. This should be interpreted as
695 : // transparent black by the caller.
696 : // aSourceRegions contains the filter primitive subregions of the source
697 : // primitives; only needed for eTile primitives.
698 : // aInputImages carries additional surfaces that are used by eImage primitives.
699 : static already_AddRefed<FilterNode>
700 0 : FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescription,
701 : DrawTarget* aDT,
702 : nsTArray<RefPtr<FilterNode> >& aSources,
703 : nsTArray<IntRect>& aSourceRegions,
704 : nsTArray<RefPtr<SourceSurface>>& aInputImages)
705 : {
706 0 : const AttributeMap& atts = aDescription.Attributes();
707 0 : switch (aDescription.Type()) {
708 :
709 : case PrimitiveType::Empty:
710 0 : return nullptr;
711 :
712 : case PrimitiveType::Blend:
713 : {
714 0 : uint32_t mode = atts.GetUint(eBlendBlendmode);
715 0 : RefPtr<FilterNode> filter;
716 0 : if (mode == SVG_FEBLEND_MODE_UNKNOWN) {
717 0 : return nullptr;
718 : }
719 0 : if (mode == SVG_FEBLEND_MODE_NORMAL) {
720 0 : filter = aDT->CreateFilter(FilterType::COMPOSITE);
721 0 : if (!filter) {
722 0 : return nullptr;
723 : }
724 0 : filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
725 0 : filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
726 : } else {
727 0 : filter = aDT->CreateFilter(FilterType::BLEND);
728 0 : if (!filter) {
729 0 : return nullptr;
730 : }
731 : static const uint8_t blendModes[SVG_FEBLEND_MODE_LUMINOSITY + 1] = {
732 : 0,
733 : 0,
734 : BLEND_MODE_MULTIPLY,
735 : BLEND_MODE_SCREEN,
736 : BLEND_MODE_DARKEN,
737 : BLEND_MODE_LIGHTEN,
738 : BLEND_MODE_OVERLAY,
739 : BLEND_MODE_COLOR_DODGE,
740 : BLEND_MODE_COLOR_BURN,
741 : BLEND_MODE_HARD_LIGHT,
742 : BLEND_MODE_SOFT_LIGHT,
743 : BLEND_MODE_DIFFERENCE,
744 : BLEND_MODE_EXCLUSION,
745 : BLEND_MODE_HUE,
746 : BLEND_MODE_SATURATION,
747 : BLEND_MODE_COLOR,
748 : BLEND_MODE_LUMINOSITY
749 : };
750 0 : filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)blendModes[mode]);
751 : // The correct input order for both software and D2D filters is flipped
752 : // from our source order, so flip here.
753 0 : filter->SetInput(IN_BLEND_IN, aSources[1]);
754 0 : filter->SetInput(IN_BLEND_IN2, aSources[0]);
755 : }
756 0 : return filter.forget();
757 : }
758 :
759 : case PrimitiveType::ColorMatrix:
760 : {
761 : float colorMatrix[20];
762 0 : uint32_t type = atts.GetUint(eColorMatrixType);
763 0 : const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
764 0 : if (NS_FAILED(ComputeColorMatrix(type, values, colorMatrix)) ||
765 0 : PodEqual(colorMatrix, identityMatrix)) {
766 0 : RefPtr<FilterNode> filter(aSources[0]);
767 0 : return filter.forget();
768 : }
769 : Matrix5x4 matrix(colorMatrix[0], colorMatrix[5], colorMatrix[10], colorMatrix[15],
770 : colorMatrix[1], colorMatrix[6], colorMatrix[11], colorMatrix[16],
771 : colorMatrix[2], colorMatrix[7], colorMatrix[12], colorMatrix[17],
772 : colorMatrix[3], colorMatrix[8], colorMatrix[13], colorMatrix[18],
773 0 : colorMatrix[4], colorMatrix[9], colorMatrix[14], colorMatrix[19]);
774 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COLOR_MATRIX);
775 0 : if (!filter) {
776 0 : return nullptr;
777 : }
778 0 : filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
779 0 : filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
780 0 : filter->SetInput(IN_COLOR_MATRIX_IN, aSources[0]);
781 0 : return filter.forget();
782 : }
783 :
784 : case PrimitiveType::Morphology:
785 : {
786 0 : Size radii = atts.GetSize(eMorphologyRadii);
787 0 : int32_t rx = radii.width;
788 0 : int32_t ry = radii.height;
789 0 : if (rx < 0 || ry < 0) {
790 : // XXX SVGContentUtils::ReportToConsole()
791 0 : return nullptr;
792 : }
793 0 : if (rx == 0 && ry == 0) {
794 0 : return nullptr;
795 : }
796 :
797 : // Clamp radii to prevent completely insane values:
798 0 : rx = std::min(rx, kMorphologyMaxRadius);
799 0 : ry = std::min(ry, kMorphologyMaxRadius);
800 :
801 0 : MorphologyOperator op = atts.GetUint(eMorphologyOperator) == SVG_OPERATOR_ERODE ?
802 0 : MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE;
803 :
804 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::MORPHOLOGY);
805 0 : if (!filter) {
806 0 : return nullptr;
807 : }
808 0 : filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
809 0 : filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
810 0 : filter->SetInput(IN_MORPHOLOGY_IN, aSources[0]);
811 0 : return filter.forget();
812 : }
813 :
814 : case PrimitiveType::Flood:
815 : {
816 0 : Color color = atts.GetColor(eFloodColor);
817 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
818 0 : if (!filter) {
819 0 : return nullptr;
820 : }
821 0 : filter->SetAttribute(ATT_FLOOD_COLOR, color);
822 0 : return filter.forget();
823 : }
824 :
825 : case PrimitiveType::Tile:
826 : {
827 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TILE);
828 0 : if (!filter) {
829 0 : return nullptr;
830 : }
831 0 : filter->SetAttribute(ATT_TILE_SOURCE_RECT, aSourceRegions[0]);
832 0 : filter->SetInput(IN_TILE_IN, aSources[0]);
833 0 : return filter.forget();
834 : }
835 :
836 : case PrimitiveType::ComponentTransfer:
837 : {
838 0 : RefPtr<FilterNode> filters[4]; // one for each FILTER_*_TRANSFER type
839 : static const AttributeName componentFunctionNames[4] = {
840 : eComponentTransferFunctionR,
841 : eComponentTransferFunctionG,
842 : eComponentTransferFunctionB,
843 : eComponentTransferFunctionA
844 : };
845 0 : for (int32_t i = 0; i < 4; i++) {
846 : AttributeMap functionAttributes =
847 0 : atts.GetAttributeMap(componentFunctionNames[i]);
848 : ConvertComponentTransferFunctionToFilter(functionAttributes, i, aDT,
849 0 : filters[0], filters[1], filters[2], filters[3]);
850 : }
851 :
852 : // Connect all used filters nodes.
853 0 : RefPtr<FilterNode> lastFilter = aSources[0];
854 0 : for (int32_t i = 0; i < 4; i++) {
855 0 : if (filters[i]) {
856 0 : filters[i]->SetInput(0, lastFilter);
857 0 : lastFilter = filters[i];
858 : }
859 : }
860 :
861 0 : return lastFilter.forget();
862 : }
863 :
864 : case PrimitiveType::ConvolveMatrix:
865 : {
866 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
867 0 : if (!filter) {
868 0 : return nullptr;
869 : }
870 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, atts.GetIntSize(eConvolveMatrixKernelSize));
871 0 : const nsTArray<float>& matrix = atts.GetFloats(eConvolveMatrixKernelMatrix);
872 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,
873 0 : matrix.Elements(), matrix.Length());
874 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR,
875 0 : atts.GetFloat(eConvolveMatrixDivisor));
876 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS,
877 0 : atts.GetFloat(eConvolveMatrixBias));
878 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET,
879 0 : atts.GetIntPoint(eConvolveMatrixTarget));
880 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT,
881 0 : aSourceRegions[0]);
882 0 : uint32_t edgeMode = atts.GetUint(eConvolveMatrixEdgeMode);
883 : static const uint8_t edgeModes[SVG_EDGEMODE_NONE+1] = {
884 : EDGE_MODE_NONE, // SVG_EDGEMODE_UNKNOWN
885 : EDGE_MODE_DUPLICATE, // SVG_EDGEMODE_DUPLICATE
886 : EDGE_MODE_WRAP, // SVG_EDGEMODE_WRAP
887 : EDGE_MODE_NONE // SVG_EDGEMODE_NONE
888 : };
889 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)edgeModes[edgeMode]);
890 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH,
891 0 : atts.GetSize(eConvolveMatrixKernelUnitLength));
892 0 : filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA,
893 0 : atts.GetBool(eConvolveMatrixPreserveAlpha));
894 0 : filter->SetInput(IN_CONVOLVE_MATRIX_IN, aSources[0]);
895 0 : return filter.forget();
896 : }
897 :
898 : case PrimitiveType::Offset:
899 : {
900 0 : return FilterWrappers::Offset(aDT, aSources[0],
901 0 : atts.GetIntPoint(eOffsetOffset));
902 : }
903 :
904 : case PrimitiveType::DisplacementMap:
905 : {
906 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
907 0 : if (!filter) {
908 0 : return nullptr;
909 : }
910 0 : filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE,
911 0 : atts.GetFloat(eDisplacementMapScale));
912 : static const uint8_t channel[SVG_CHANNEL_A+1] = {
913 : COLOR_CHANNEL_R, // SVG_CHANNEL_UNKNOWN
914 : COLOR_CHANNEL_R, // SVG_CHANNEL_R
915 : COLOR_CHANNEL_G, // SVG_CHANNEL_G
916 : COLOR_CHANNEL_B, // SVG_CHANNEL_B
917 : COLOR_CHANNEL_A // SVG_CHANNEL_A
918 : };
919 0 : filter->SetAttribute(ATT_DISPLACEMENT_MAP_X_CHANNEL,
920 0 : (uint32_t)channel[atts.GetUint(eDisplacementMapXChannel)]);
921 0 : filter->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL,
922 0 : (uint32_t)channel[atts.GetUint(eDisplacementMapYChannel)]);
923 0 : filter->SetInput(IN_DISPLACEMENT_MAP_IN, aSources[0]);
924 0 : filter->SetInput(IN_DISPLACEMENT_MAP_IN2, aSources[1]);
925 0 : return filter.forget();
926 : }
927 :
928 : case PrimitiveType::Turbulence:
929 : {
930 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TURBULENCE);
931 0 : if (!filter) {
932 0 : return nullptr;
933 : }
934 0 : filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
935 0 : atts.GetSize(eTurbulenceBaseFrequency));
936 0 : filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES,
937 0 : atts.GetUint(eTurbulenceNumOctaves));
938 0 : filter->SetAttribute(ATT_TURBULENCE_STITCHABLE,
939 0 : atts.GetBool(eTurbulenceStitchable));
940 0 : filter->SetAttribute(ATT_TURBULENCE_SEED,
941 0 : (uint32_t)atts.GetFloat(eTurbulenceSeed));
942 : static const uint8_t type[SVG_TURBULENCE_TYPE_TURBULENCE+1] = {
943 : TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_UNKNOWN
944 : TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_FRACTALNOISE
945 : TURBULENCE_TYPE_TURBULENCE // SVG_TURBULENCE_TYPE_TURBULENCE
946 : };
947 0 : filter->SetAttribute(ATT_TURBULENCE_TYPE,
948 0 : (uint32_t)type[atts.GetUint(eTurbulenceType)]);
949 0 : filter->SetAttribute(ATT_TURBULENCE_RECT,
950 0 : aDescription.PrimitiveSubregion() - atts.GetIntPoint(eTurbulenceOffset));
951 0 : return FilterWrappers::Offset(aDT, filter, atts.GetIntPoint(eTurbulenceOffset));
952 : }
953 :
954 : case PrimitiveType::Composite:
955 : {
956 0 : RefPtr<FilterNode> filter;
957 0 : uint32_t op = atts.GetUint(eCompositeOperator);
958 0 : if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
959 0 : const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
960 : static const float allZero[4] = { 0, 0, 0, 0 };
961 0 : filter = aDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
962 : // All-zero coefficients sometimes occur in junk filters.
963 0 : if (!filter ||
964 0 : (coefficients.Length() == ArrayLength(allZero) &&
965 0 : PodEqual(coefficients.Elements(), allZero, ArrayLength(allZero)))) {
966 0 : return nullptr;
967 : }
968 0 : filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS,
969 0 : coefficients.Elements(), coefficients.Length());
970 0 : filter->SetInput(IN_ARITHMETIC_COMBINE_IN, aSources[0]);
971 0 : filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, aSources[1]);
972 : } else {
973 0 : filter = aDT->CreateFilter(FilterType::COMPOSITE);
974 0 : if (!filter) {
975 0 : return nullptr;
976 : }
977 : static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
978 : COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
979 : COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
980 : COMPOSITE_OPERATOR_IN, // SVG_FECOMPOSITE_OPERATOR_IN
981 : COMPOSITE_OPERATOR_OUT, // SVG_FECOMPOSITE_OPERATOR_OUT
982 : COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
983 : COMPOSITE_OPERATOR_XOR // SVG_FECOMPOSITE_OPERATOR_XOR
984 : };
985 0 : filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)operators[op]);
986 0 : filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
987 0 : filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
988 : }
989 0 : return filter.forget();
990 : }
991 :
992 : case PrimitiveType::Merge:
993 : {
994 0 : if (aSources.Length() == 0) {
995 0 : return nullptr;
996 : }
997 0 : if (aSources.Length() == 1) {
998 0 : RefPtr<FilterNode> filter(aSources[0]);
999 0 : return filter.forget();
1000 : }
1001 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
1002 0 : if (!filter) {
1003 0 : return nullptr;
1004 : }
1005 0 : filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
1006 0 : for (size_t i = 0; i < aSources.Length(); i++) {
1007 0 : filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
1008 : }
1009 0 : return filter.forget();
1010 : }
1011 :
1012 : case PrimitiveType::GaussianBlur:
1013 : {
1014 0 : return FilterWrappers::GaussianBlur(aDT, aSources[0],
1015 0 : atts.GetSize(eGaussianBlurStdDeviation));
1016 : }
1017 :
1018 : case PrimitiveType::DropShadow:
1019 : {
1020 0 : RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(aDT, aSources[0]);
1021 0 : RefPtr<FilterNode> blur = FilterWrappers::GaussianBlur(aDT, alpha,
1022 0 : atts.GetSize(eDropShadowStdDeviation));
1023 0 : RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
1024 0 : atts.GetIntPoint(eDropShadowOffset));
1025 0 : RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
1026 0 : if (!flood) {
1027 0 : return nullptr;
1028 : }
1029 0 : Color color = atts.GetColor(eDropShadowColor);
1030 0 : if (aDescription.InputColorSpace(0) == ColorSpace::LinearRGB) {
1031 0 : color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
1032 0 : gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
1033 0 : gsRGBToLinearRGBMap[uint8_t(color.b * 255)],
1034 : color.a);
1035 : }
1036 0 : flood->SetAttribute(ATT_FLOOD_COLOR, color);
1037 :
1038 0 : RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
1039 0 : if (!composite) {
1040 0 : return nullptr;
1041 : }
1042 0 : composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
1043 0 : composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
1044 0 : composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
1045 :
1046 0 : RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
1047 0 : if (!filter) {
1048 0 : return nullptr;
1049 : }
1050 0 : filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
1051 0 : filter->SetInput(IN_COMPOSITE_IN_START, composite);
1052 0 : filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
1053 0 : return filter.forget();
1054 : }
1055 :
1056 : case PrimitiveType::DiffuseLighting:
1057 : case PrimitiveType::SpecularLighting:
1058 : {
1059 : bool isSpecular =
1060 0 : aDescription.Type() == PrimitiveType::SpecularLighting;
1061 :
1062 0 : AttributeMap lightAttributes = atts.GetAttributeMap(eLightingLight);
1063 :
1064 0 : if (lightAttributes.GetUint(eLightType) == eLightTypeNone) {
1065 0 : return nullptr;
1066 : }
1067 :
1068 0 : enum { POINT = 0, SPOT, DISTANT } lightType = POINT;
1069 :
1070 0 : switch (lightAttributes.GetUint(eLightType)) {
1071 0 : case eLightTypePoint: lightType = POINT; break;
1072 0 : case eLightTypeSpot: lightType = SPOT; break;
1073 0 : case eLightTypeDistant: lightType = DISTANT; break;
1074 : }
1075 :
1076 : static const FilterType filterType[2][DISTANT+1] = {
1077 : { FilterType::POINT_DIFFUSE, FilterType::SPOT_DIFFUSE, FilterType::DISTANT_DIFFUSE },
1078 : { FilterType::POINT_SPECULAR, FilterType::SPOT_SPECULAR, FilterType::DISTANT_SPECULAR }
1079 : };
1080 : RefPtr<FilterNode> filter =
1081 0 : aDT->CreateFilter(filterType[isSpecular][lightType]);
1082 0 : if (!filter) {
1083 0 : return nullptr;
1084 : }
1085 :
1086 0 : filter->SetAttribute(ATT_LIGHTING_COLOR,
1087 0 : atts.GetColor(eLightingColor));
1088 0 : filter->SetAttribute(ATT_LIGHTING_SURFACE_SCALE,
1089 0 : atts.GetFloat(eLightingSurfaceScale));
1090 0 : filter->SetAttribute(ATT_LIGHTING_KERNEL_UNIT_LENGTH,
1091 0 : atts.GetSize(eLightingKernelUnitLength));
1092 :
1093 0 : if (isSpecular) {
1094 0 : filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
1095 0 : atts.GetFloat(eSpecularLightingSpecularConstant));
1096 0 : filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT,
1097 0 : atts.GetFloat(eSpecularLightingSpecularExponent));
1098 : } else {
1099 0 : filter->SetAttribute(ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT,
1100 0 : atts.GetFloat(eDiffuseLightingDiffuseConstant));
1101 : }
1102 :
1103 0 : switch (lightType) {
1104 : case POINT:
1105 0 : filter->SetAttribute(ATT_POINT_LIGHT_POSITION,
1106 0 : lightAttributes.GetPoint3D(ePointLightPosition));
1107 0 : break;
1108 : case SPOT:
1109 0 : filter->SetAttribute(ATT_SPOT_LIGHT_POSITION,
1110 0 : lightAttributes.GetPoint3D(eSpotLightPosition));
1111 0 : filter->SetAttribute(ATT_SPOT_LIGHT_POINTS_AT,
1112 0 : lightAttributes.GetPoint3D(eSpotLightPointsAt));
1113 0 : filter->SetAttribute(ATT_SPOT_LIGHT_FOCUS,
1114 0 : lightAttributes.GetFloat(eSpotLightFocus));
1115 0 : filter->SetAttribute(ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,
1116 0 : lightAttributes.GetFloat(eSpotLightLimitingConeAngle));
1117 0 : break;
1118 : case DISTANT:
1119 0 : filter->SetAttribute(ATT_DISTANT_LIGHT_AZIMUTH,
1120 0 : lightAttributes.GetFloat(eDistantLightAzimuth));
1121 0 : filter->SetAttribute(ATT_DISTANT_LIGHT_ELEVATION,
1122 0 : lightAttributes.GetFloat(eDistantLightElevation));
1123 0 : break;
1124 : }
1125 :
1126 0 : filter->SetInput(IN_LIGHTING_IN, aSources[0]);
1127 :
1128 0 : return filter.forget();
1129 : }
1130 :
1131 : case PrimitiveType::Image:
1132 : {
1133 0 : Matrix TM = atts.GetMatrix(eImageTransform);
1134 0 : if (!TM.Determinant()) {
1135 0 : return nullptr;
1136 : }
1137 :
1138 : // Pull the image from the additional image list using the index that's
1139 : // stored in the primitive description.
1140 : RefPtr<SourceSurface> inputImage =
1141 0 : aInputImages[atts.GetUint(eImageInputIndex)];
1142 :
1143 0 : RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
1144 0 : if (!transform) {
1145 0 : return nullptr;
1146 : }
1147 0 : transform->SetInput(IN_TRANSFORM_IN, inputImage);
1148 0 : transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
1149 0 : transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
1150 0 : return transform.forget();
1151 : }
1152 :
1153 : case PrimitiveType::ToAlpha:
1154 : {
1155 0 : return FilterWrappers::ToAlpha(aDT, aSources[0]);
1156 : }
1157 :
1158 : default:
1159 0 : return nullptr;
1160 : }
1161 : }
1162 :
1163 : template<typename T>
1164 : static const T&
1165 0 : ElementForIndex(int32_t aIndex,
1166 : const nsTArray<T>& aPrimitiveElements,
1167 : const T& aSourceGraphicElement,
1168 : const T& aFillPaintElement,
1169 : const T& aStrokePaintElement)
1170 : {
1171 0 : switch (aIndex) {
1172 : case FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic:
1173 : case FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha:
1174 0 : return aSourceGraphicElement;
1175 : case FilterPrimitiveDescription::kPrimitiveIndexFillPaint:
1176 0 : return aFillPaintElement;
1177 : case FilterPrimitiveDescription::kPrimitiveIndexStrokePaint:
1178 0 : return aStrokePaintElement;
1179 : default:
1180 0 : MOZ_ASSERT(aIndex >= 0, "bad index");
1181 0 : return aPrimitiveElements[aIndex];
1182 : }
1183 : }
1184 :
1185 : static AlphaModel
1186 0 : InputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
1187 : int32_t aInputIndex,
1188 : AlphaModel aOriginalAlphaModel)
1189 : {
1190 0 : switch (aDescr.Type()) {
1191 : case PrimitiveType::Tile:
1192 : case PrimitiveType::Offset:
1193 : case PrimitiveType::ToAlpha:
1194 0 : return aOriginalAlphaModel;
1195 :
1196 : case PrimitiveType::ColorMatrix:
1197 : case PrimitiveType::ComponentTransfer:
1198 0 : return AlphaModel::Unpremultiplied;
1199 :
1200 : case PrimitiveType::DisplacementMap:
1201 0 : return aInputIndex == 0 ?
1202 0 : AlphaModel::Premultiplied : AlphaModel::Unpremultiplied;
1203 :
1204 : case PrimitiveType::ConvolveMatrix:
1205 0 : return aDescr.Attributes().GetBool(eConvolveMatrixPreserveAlpha) ?
1206 0 : AlphaModel::Unpremultiplied : AlphaModel::Premultiplied;
1207 :
1208 : default:
1209 0 : return AlphaModel::Premultiplied;
1210 : }
1211 : }
1212 :
1213 : static AlphaModel
1214 0 : OutputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
1215 : const nsTArray<AlphaModel>& aInputAlphaModels)
1216 : {
1217 0 : if (aInputAlphaModels.Length()) {
1218 : // For filters with inputs, the output is premultiplied if and only if the
1219 : // first input is premultiplied.
1220 0 : return InputAlphaModelForPrimitive(aDescr, 0, aInputAlphaModels[0]);
1221 : }
1222 :
1223 : // All filters without inputs produce premultiplied alpha.
1224 0 : return AlphaModel::Premultiplied;
1225 : }
1226 :
1227 : // Returns the output FilterNode, in premultiplied sRGB space.
1228 : static already_AddRefed<FilterNode>
1229 0 : FilterNodeGraphFromDescription(DrawTarget* aDT,
1230 : const FilterDescription& aFilter,
1231 : const Rect& aResultNeededRect,
1232 : SourceSurface* aSourceGraphic,
1233 : const IntRect& aSourceGraphicRect,
1234 : SourceSurface* aFillPaint,
1235 : const IntRect& aFillPaintRect,
1236 : SourceSurface* aStrokePaint,
1237 : const IntRect& aStrokePaintRect,
1238 : nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
1239 : {
1240 0 : const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1241 0 : MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
1242 :
1243 0 : RefPtr<FilterCachedColorModels> sourceFilters[4];
1244 0 : nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters;
1245 :
1246 0 : for (size_t i = 0; i < primitives.Length(); ++i) {
1247 0 : const FilterPrimitiveDescription& descr = primitives[i];
1248 :
1249 0 : nsTArray<RefPtr<FilterNode> > inputFilterNodes;
1250 0 : nsTArray<IntRect> inputSourceRects;
1251 0 : nsTArray<AlphaModel> inputAlphaModels;
1252 :
1253 0 : for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1254 :
1255 0 : int32_t inputIndex = descr.InputPrimitiveIndex(j);
1256 0 : if (inputIndex < 0) {
1257 0 : inputSourceRects.AppendElement(descr.FilterSpaceBounds());
1258 : } else {
1259 0 : inputSourceRects.AppendElement(primitives[inputIndex].PrimitiveSubregion());
1260 : }
1261 :
1262 0 : RefPtr<FilterCachedColorModels> inputFilter;
1263 0 : if (inputIndex >= 0) {
1264 0 : MOZ_ASSERT(inputIndex < (int64_t)primitiveFilters.Length(), "out-of-bounds input index!");
1265 0 : inputFilter = primitiveFilters[inputIndex];
1266 0 : MOZ_ASSERT(inputFilter, "Referred to input filter that comes after the current one?");
1267 : } else {
1268 0 : int32_t sourceIndex = -inputIndex - 1;
1269 0 : MOZ_ASSERT(sourceIndex >= 0, "invalid source index");
1270 0 : MOZ_ASSERT(sourceIndex < 4, "invalid source index");
1271 0 : inputFilter = sourceFilters[sourceIndex];
1272 0 : if (!inputFilter) {
1273 0 : RefPtr<FilterNode> sourceFilterNode;
1274 :
1275 0 : nsTArray<SourceSurface*> primitiveSurfaces;
1276 0 : nsTArray<IntRect> primitiveSurfaceRects;
1277 : RefPtr<SourceSurface> surf =
1278 : ElementForIndex(inputIndex, primitiveSurfaces,
1279 0 : aSourceGraphic, aFillPaint, aStrokePaint);
1280 : IntRect surfaceRect =
1281 : ElementForIndex(inputIndex, primitiveSurfaceRects,
1282 0 : aSourceGraphicRect, aFillPaintRect, aStrokePaintRect);
1283 0 : if (surf) {
1284 0 : IntPoint offset = surfaceRect.TopLeft();
1285 0 : sourceFilterNode = FilterWrappers::ForSurface(aDT, surf, offset);
1286 :
1287 : // Clip the original SourceGraphic to the first filter region if the
1288 : // surface isn't already sized appropriately.
1289 0 : if ((inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic ||
1290 0 : inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) &&
1291 0 : !descr.FilterSpaceBounds().Contains(aSourceGraphicRect)) {
1292 : sourceFilterNode =
1293 0 : FilterWrappers::Crop(aDT, sourceFilterNode, descr.FilterSpaceBounds());
1294 : }
1295 :
1296 0 : if (inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) {
1297 0 : sourceFilterNode = FilterWrappers::ToAlpha(aDT, sourceFilterNode);
1298 : }
1299 : }
1300 :
1301 : inputFilter = new FilterCachedColorModels(aDT, sourceFilterNode,
1302 0 : ColorModel::PremulSRGB());
1303 0 : sourceFilters[sourceIndex] = inputFilter;
1304 : }
1305 : }
1306 0 : MOZ_ASSERT(inputFilter);
1307 :
1308 : AlphaModel inputAlphaModel =
1309 0 : InputAlphaModelForPrimitive(descr, j, inputFilter->OriginalAlphaModel());
1310 0 : inputAlphaModels.AppendElement(inputAlphaModel);
1311 0 : ColorModel inputColorModel(descr.InputColorSpace(j), inputAlphaModel);
1312 0 : inputFilterNodes.AppendElement(inputFilter->ForColorModel(inputColorModel));
1313 : }
1314 :
1315 : RefPtr<FilterNode> primitiveFilterNode =
1316 0 : FilterNodeFromPrimitiveDescription(descr, aDT, inputFilterNodes,
1317 0 : inputSourceRects, aAdditionalImages);
1318 :
1319 0 : if (primitiveFilterNode) {
1320 : primitiveFilterNode =
1321 0 : FilterWrappers::Crop(aDT, primitiveFilterNode, descr.PrimitiveSubregion());
1322 : }
1323 :
1324 : ColorModel outputColorModel(descr.OutputColorSpace(),
1325 0 : OutputAlphaModelForPrimitive(descr, inputAlphaModels));
1326 : RefPtr<FilterCachedColorModels> primitiveFilter =
1327 0 : new FilterCachedColorModels(aDT, primitiveFilterNode, outputColorModel);
1328 :
1329 0 : primitiveFilters.AppendElement(primitiveFilter);
1330 : }
1331 :
1332 0 : MOZ_RELEASE_ASSERT(!primitiveFilters.IsEmpty());
1333 0 : return primitiveFilters.LastElement()->ForColorModel(ColorModel::PremulSRGB());
1334 : }
1335 :
1336 : // FilterSupport
1337 :
1338 : void
1339 0 : FilterSupport::RenderFilterDescription(DrawTarget* aDT,
1340 : const FilterDescription& aFilter,
1341 : const Rect& aRenderRect,
1342 : SourceSurface* aSourceGraphic,
1343 : const IntRect& aSourceGraphicRect,
1344 : SourceSurface* aFillPaint,
1345 : const IntRect& aFillPaintRect,
1346 : SourceSurface* aStrokePaint,
1347 : const IntRect& aStrokePaintRect,
1348 : nsTArray<RefPtr<SourceSurface>>& aAdditionalImages,
1349 : const Point& aDestPoint,
1350 : const DrawOptions& aOptions)
1351 : {
1352 : RefPtr<FilterNode> resultFilter =
1353 0 : FilterNodeGraphFromDescription(aDT, aFilter, aRenderRect,
1354 : aSourceGraphic, aSourceGraphicRect, aFillPaint, aFillPaintRect,
1355 0 : aStrokePaint, aStrokePaintRect, aAdditionalImages);
1356 0 : if (!resultFilter) {
1357 0 : gfxWarning() << "Filter is NULL.";
1358 0 : return;
1359 : }
1360 0 : aDT->DrawFilter(resultFilter, aRenderRect, aDestPoint, aOptions);
1361 : }
1362 :
1363 : static nsIntRegion
1364 0 : UnionOfRegions(const nsTArray<nsIntRegion>& aRegions)
1365 : {
1366 0 : nsIntRegion result;
1367 0 : for (size_t i = 0; i < aRegions.Length(); i++) {
1368 0 : result.Or(result, aRegions[i]);
1369 : }
1370 0 : return result;
1371 : }
1372 :
1373 : static int32_t
1374 0 : InflateSizeForBlurStdDev(float aStdDev)
1375 : {
1376 0 : double size = std::min(aStdDev, kMaxStdDeviation) * (3 * sqrt(2 * M_PI) / 4) * 1.5;
1377 0 : return uint32_t(floor(size + 0.5));
1378 : }
1379 :
1380 : static nsIntRegion
1381 0 : ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
1382 : const nsTArray<nsIntRegion>& aInputChangeRegions)
1383 : {
1384 0 : const AttributeMap& atts = aDescription.Attributes();
1385 0 : switch (aDescription.Type()) {
1386 :
1387 : case PrimitiveType::Empty:
1388 : case PrimitiveType::Flood:
1389 : case PrimitiveType::Turbulence:
1390 : case PrimitiveType::Image:
1391 0 : return nsIntRegion();
1392 :
1393 : case PrimitiveType::Blend:
1394 : case PrimitiveType::Composite:
1395 : case PrimitiveType::Merge:
1396 0 : return UnionOfRegions(aInputChangeRegions);
1397 :
1398 : case PrimitiveType::ColorMatrix:
1399 : case PrimitiveType::ComponentTransfer:
1400 : case PrimitiveType::ToAlpha:
1401 0 : return aInputChangeRegions[0];
1402 :
1403 : case PrimitiveType::Morphology:
1404 : {
1405 0 : Size radii = atts.GetSize(eMorphologyRadii);
1406 0 : int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
1407 0 : int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
1408 0 : return aInputChangeRegions[0].Inflated(nsIntMargin(ry, rx, ry, rx));
1409 : }
1410 :
1411 : case PrimitiveType::Tile:
1412 0 : return aDescription.PrimitiveSubregion();
1413 :
1414 : case PrimitiveType::ConvolveMatrix:
1415 : {
1416 0 : if (atts.GetUint(eConvolveMatrixEdgeMode) != EDGE_MODE_NONE) {
1417 0 : return aDescription.PrimitiveSubregion();
1418 : }
1419 0 : Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
1420 0 : IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
1421 0 : IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
1422 0 : nsIntMargin m(ceil(kernelUnitLength.width * (target.x)),
1423 0 : ceil(kernelUnitLength.height * (target.y)),
1424 0 : ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
1425 0 : ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)));
1426 0 : return aInputChangeRegions[0].Inflated(m);
1427 : }
1428 :
1429 : case PrimitiveType::Offset:
1430 : {
1431 0 : IntPoint offset = atts.GetIntPoint(eOffsetOffset);
1432 0 : return aInputChangeRegions[0].MovedBy(offset.x, offset.y);
1433 : }
1434 :
1435 : case PrimitiveType::DisplacementMap:
1436 : {
1437 0 : int32_t scale = ceil(std::abs(atts.GetFloat(eDisplacementMapScale)));
1438 0 : return aInputChangeRegions[0].Inflated(nsIntMargin(scale, scale, scale, scale));
1439 : }
1440 :
1441 : case PrimitiveType::GaussianBlur:
1442 : {
1443 0 : Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
1444 0 : int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1445 0 : int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1446 0 : return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
1447 : }
1448 :
1449 : case PrimitiveType::DropShadow:
1450 : {
1451 0 : IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
1452 0 : nsIntRegion offsetRegion = aInputChangeRegions[0].MovedBy(offset.x, offset.y);
1453 0 : Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
1454 0 : int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1455 0 : int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1456 0 : nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1457 0 : blurRegion.Or(blurRegion, aInputChangeRegions[0]);
1458 0 : return blurRegion;
1459 : }
1460 :
1461 : case PrimitiveType::DiffuseLighting:
1462 : case PrimitiveType::SpecularLighting:
1463 : {
1464 0 : Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
1465 0 : int32_t dx = ceil(kernelUnitLength.width);
1466 0 : int32_t dy = ceil(kernelUnitLength.height);
1467 0 : return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
1468 : }
1469 :
1470 : default:
1471 0 : return nsIntRegion();
1472 : }
1473 : }
1474 :
1475 : /* static */ nsIntRegion
1476 0 : FilterSupport::ComputeResultChangeRegion(const FilterDescription& aFilter,
1477 : const nsIntRegion& aSourceGraphicChange,
1478 : const nsIntRegion& aFillPaintChange,
1479 : const nsIntRegion& aStrokePaintChange)
1480 : {
1481 0 : const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1482 0 : MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
1483 :
1484 0 : nsTArray<nsIntRegion> resultChangeRegions;
1485 :
1486 0 : for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
1487 0 : const FilterPrimitiveDescription& descr = primitives[i];
1488 :
1489 0 : nsTArray<nsIntRegion> inputChangeRegions;
1490 0 : for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1491 0 : int32_t inputIndex = descr.InputPrimitiveIndex(j);
1492 0 : MOZ_ASSERT(inputIndex < i, "bad input index");
1493 : nsIntRegion inputChangeRegion =
1494 : ElementForIndex(inputIndex, resultChangeRegions,
1495 : aSourceGraphicChange, aFillPaintChange,
1496 0 : aStrokePaintChange);
1497 0 : inputChangeRegions.AppendElement(inputChangeRegion);
1498 : }
1499 : nsIntRegion changeRegion =
1500 0 : ResultChangeRegionForPrimitive(descr, inputChangeRegions);
1501 0 : changeRegion.And(changeRegion, descr.PrimitiveSubregion());
1502 0 : resultChangeRegions.AppendElement(changeRegion);
1503 : }
1504 :
1505 0 : MOZ_RELEASE_ASSERT(!resultChangeRegions.IsEmpty());
1506 0 : return resultChangeRegions[resultChangeRegions.Length() - 1];
1507 : }
1508 :
1509 : static float
1510 0 : ResultOfZeroUnderTransferFunction(const AttributeMap& aFunctionAttributes)
1511 : {
1512 0 : switch (aFunctionAttributes.GetUint(eComponentTransferFunctionType)) {
1513 : case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
1514 : {
1515 : const nsTArray<float>& tableValues =
1516 0 : aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
1517 0 : if (tableValues.Length() < 2) {
1518 0 : return 0.0f;
1519 : }
1520 0 : return tableValues[0];
1521 : }
1522 :
1523 : case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
1524 : {
1525 : const nsTArray<float>& tableValues =
1526 0 : aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
1527 0 : if (tableValues.Length() < 1) {
1528 0 : return 0.0f;
1529 : }
1530 0 : return tableValues[0];
1531 : }
1532 :
1533 : case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
1534 0 : return aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
1535 :
1536 : case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
1537 0 : return aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
1538 :
1539 : case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
1540 : default:
1541 0 : return 0.0f;
1542 : }
1543 : }
1544 :
1545 : nsIntRegion
1546 0 : FilterSupport::PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
1547 : const nsTArray<nsIntRegion>& aInputExtents)
1548 : {
1549 0 : const AttributeMap& atts = aDescription.Attributes();
1550 0 : switch (aDescription.Type()) {
1551 :
1552 : case PrimitiveType::Empty:
1553 0 : return IntRect();
1554 :
1555 : case PrimitiveType::Composite:
1556 : {
1557 0 : uint32_t op = atts.GetUint(eCompositeOperator);
1558 0 : if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
1559 : // The arithmetic composite primitive can draw outside the bounding
1560 : // box of its source images.
1561 0 : const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
1562 0 : MOZ_ASSERT(coefficients.Length() == 4);
1563 :
1564 : // The calculation is:
1565 : // r = c[0] * in[0] * in[1] + c[1] * in[0] + c[2] * in[1] + c[3]
1566 0 : nsIntRegion region;
1567 0 : if (coefficients[0] > 0.0f) {
1568 0 : region = aInputExtents[0].Intersect(aInputExtents[1]);
1569 : }
1570 0 : if (coefficients[1] > 0.0f) {
1571 0 : region.Or(region, aInputExtents[0]);
1572 : }
1573 0 : if (coefficients[2] > 0.0f) {
1574 0 : region.Or(region, aInputExtents[1]);
1575 : }
1576 0 : if (coefficients[3] > 0.0f) {
1577 0 : region = aDescription.PrimitiveSubregion();
1578 : }
1579 0 : return region;
1580 : }
1581 0 : if (op == SVG_FECOMPOSITE_OPERATOR_IN) {
1582 0 : return aInputExtents[0].Intersect(aInputExtents[1]);
1583 : }
1584 0 : return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
1585 : }
1586 :
1587 : case PrimitiveType::Flood:
1588 : {
1589 0 : if (atts.GetColor(eFloodColor).a == 0.0f) {
1590 0 : return IntRect();
1591 : }
1592 0 : return aDescription.PrimitiveSubregion();
1593 : }
1594 :
1595 : case PrimitiveType::ColorMatrix:
1596 : {
1597 0 : if (atts.GetUint(eColorMatrixType) == (uint32_t)SVG_FECOLORMATRIX_TYPE_MATRIX) {
1598 0 : const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
1599 0 : if (values.Length() == 20 && values[19] > 0.0f) {
1600 0 : return aDescription.PrimitiveSubregion();
1601 : }
1602 : }
1603 0 : return aInputExtents[0];
1604 : }
1605 :
1606 : case PrimitiveType::ComponentTransfer:
1607 : {
1608 : AttributeMap functionAttributes =
1609 0 : atts.GetAttributeMap(eComponentTransferFunctionA);
1610 0 : if (ResultOfZeroUnderTransferFunction(functionAttributes) > 0.0f) {
1611 0 : return aDescription.PrimitiveSubregion();
1612 : }
1613 0 : return aInputExtents[0];
1614 : }
1615 :
1616 : case PrimitiveType::Turbulence:
1617 : case PrimitiveType::Image:
1618 : case PrimitiveType::DiffuseLighting:
1619 : case PrimitiveType::SpecularLighting:
1620 : {
1621 0 : return aDescription.PrimitiveSubregion();
1622 : }
1623 :
1624 : case PrimitiveType::Morphology:
1625 : {
1626 0 : uint32_t op = atts.GetUint(eMorphologyOperator);
1627 0 : if (op == SVG_OPERATOR_ERODE) {
1628 0 : return aInputExtents[0];
1629 : }
1630 0 : Size radii = atts.GetSize(eMorphologyRadii);
1631 0 : int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
1632 0 : int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
1633 0 : return aInputExtents[0].Inflated(nsIntMargin(ry, rx, ry, rx));
1634 : }
1635 :
1636 : default:
1637 0 : return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
1638 : }
1639 : }
1640 :
1641 : /* static */ nsIntRegion
1642 0 : FilterSupport::ComputePostFilterExtents(const FilterDescription& aFilter,
1643 : const nsIntRegion& aSourceGraphicExtents)
1644 : {
1645 0 : const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1646 0 : MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
1647 0 : nsTArray<nsIntRegion> postFilterExtents;
1648 :
1649 0 : for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
1650 0 : const FilterPrimitiveDescription& descr = primitives[i];
1651 0 : nsIntRegion filterSpace = descr.FilterSpaceBounds();
1652 :
1653 0 : nsTArray<nsIntRegion> inputExtents;
1654 0 : for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1655 0 : int32_t inputIndex = descr.InputPrimitiveIndex(j);
1656 0 : MOZ_ASSERT(inputIndex < i, "bad input index");
1657 : nsIntRegion inputExtent =
1658 : ElementForIndex(inputIndex, postFilterExtents,
1659 0 : aSourceGraphicExtents, filterSpace, filterSpace);
1660 0 : inputExtents.AppendElement(inputExtent);
1661 : }
1662 0 : nsIntRegion extent = PostFilterExtentsForPrimitive(descr, inputExtents);
1663 0 : extent.And(extent, descr.PrimitiveSubregion());
1664 0 : postFilterExtents.AppendElement(extent);
1665 : }
1666 :
1667 0 : MOZ_RELEASE_ASSERT(!postFilterExtents.IsEmpty());
1668 0 : return postFilterExtents[postFilterExtents.Length() - 1];
1669 : }
1670 :
1671 : static nsIntRegion
1672 0 : SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
1673 : const nsIntRegion& aResultNeededRegion,
1674 : int32_t aInputIndex)
1675 : {
1676 0 : const AttributeMap& atts = aDescription.Attributes();
1677 0 : switch (aDescription.Type()) {
1678 :
1679 : case PrimitiveType::Flood:
1680 : case PrimitiveType::Turbulence:
1681 : case PrimitiveType::Image:
1682 0 : MOZ_CRASH("GFX: this shouldn't be called for filters without inputs");
1683 : return nsIntRegion();
1684 :
1685 : case PrimitiveType::Empty:
1686 0 : return nsIntRegion();
1687 :
1688 : case PrimitiveType::Blend:
1689 : case PrimitiveType::Composite:
1690 : case PrimitiveType::Merge:
1691 : case PrimitiveType::ColorMatrix:
1692 : case PrimitiveType::ComponentTransfer:
1693 : case PrimitiveType::ToAlpha:
1694 0 : return aResultNeededRegion;
1695 :
1696 : case PrimitiveType::Morphology:
1697 : {
1698 0 : Size radii = atts.GetSize(eMorphologyRadii);
1699 0 : int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
1700 0 : int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
1701 0 : return aResultNeededRegion.Inflated(nsIntMargin(ry, rx, ry, rx));
1702 : }
1703 :
1704 : case PrimitiveType::Tile:
1705 0 : return IntRect(INT32_MIN/2, INT32_MIN/2, INT32_MAX, INT32_MAX);
1706 :
1707 : case PrimitiveType::ConvolveMatrix:
1708 : {
1709 0 : Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
1710 0 : IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
1711 0 : IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
1712 0 : nsIntMargin m(ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
1713 0 : ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)),
1714 0 : ceil(kernelUnitLength.width * (target.x)),
1715 0 : ceil(kernelUnitLength.height * (target.y)));
1716 0 : return aResultNeededRegion.Inflated(m);
1717 : }
1718 :
1719 : case PrimitiveType::Offset:
1720 : {
1721 0 : IntPoint offset = atts.GetIntPoint(eOffsetOffset);
1722 0 : return aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
1723 : }
1724 :
1725 : case PrimitiveType::DisplacementMap:
1726 : {
1727 0 : if (aInputIndex == 1) {
1728 0 : return aResultNeededRegion;
1729 : }
1730 0 : int32_t scale = ceil(std::abs(atts.GetFloat(eDisplacementMapScale)));
1731 0 : return aResultNeededRegion.Inflated(nsIntMargin(scale, scale, scale, scale));
1732 : }
1733 :
1734 : case PrimitiveType::GaussianBlur:
1735 : {
1736 0 : Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
1737 0 : int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1738 0 : int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1739 0 : return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1740 : }
1741 :
1742 : case PrimitiveType::DropShadow:
1743 : {
1744 0 : IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
1745 : nsIntRegion offsetRegion =
1746 0 : aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
1747 0 : Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
1748 0 : int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
1749 0 : int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
1750 0 : nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1751 0 : blurRegion.Or(blurRegion, aResultNeededRegion);
1752 0 : return blurRegion;
1753 : }
1754 :
1755 : case PrimitiveType::DiffuseLighting:
1756 : case PrimitiveType::SpecularLighting:
1757 : {
1758 0 : Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
1759 0 : int32_t dx = ceil(kernelUnitLength.width);
1760 0 : int32_t dy = ceil(kernelUnitLength.height);
1761 0 : return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
1762 : }
1763 :
1764 : default:
1765 0 : return nsIntRegion();
1766 : }
1767 :
1768 : }
1769 :
1770 : /* static */ void
1771 0 : FilterSupport::ComputeSourceNeededRegions(const FilterDescription& aFilter,
1772 : const nsIntRegion& aResultNeededRegion,
1773 : nsIntRegion& aSourceGraphicNeededRegion,
1774 : nsIntRegion& aFillPaintNeededRegion,
1775 : nsIntRegion& aStrokePaintNeededRegion)
1776 : {
1777 0 : const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
1778 0 : MOZ_ASSERT(!primitives.IsEmpty());
1779 0 : if (primitives.IsEmpty()) {
1780 0 : return;
1781 : }
1782 :
1783 0 : nsTArray<nsIntRegion> primitiveNeededRegions;
1784 0 : primitiveNeededRegions.AppendElements(primitives.Length());
1785 :
1786 0 : primitiveNeededRegions[primitives.Length() - 1] = aResultNeededRegion;
1787 :
1788 0 : for (int32_t i = primitives.Length() - 1; i >= 0; --i) {
1789 0 : const FilterPrimitiveDescription& descr = primitives[i];
1790 0 : nsIntRegion neededRegion = primitiveNeededRegions[i];
1791 0 : neededRegion.And(neededRegion, descr.PrimitiveSubregion());
1792 :
1793 0 : for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
1794 0 : int32_t inputIndex = descr.InputPrimitiveIndex(j);
1795 0 : MOZ_ASSERT(inputIndex < i, "bad input index");
1796 : nsIntRegion* inputNeededRegion = const_cast<nsIntRegion*>(
1797 : &ElementForIndex(inputIndex, primitiveNeededRegions,
1798 : aSourceGraphicNeededRegion,
1799 0 : aFillPaintNeededRegion, aStrokePaintNeededRegion));
1800 : inputNeededRegion->Or(*inputNeededRegion,
1801 0 : SourceNeededRegionForPrimitive(descr, neededRegion, j));
1802 : }
1803 : }
1804 :
1805 : // Clip original SourceGraphic to first filter region.
1806 0 : const FilterPrimitiveDescription& firstDescr = primitives[0];
1807 : aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
1808 0 : firstDescr.FilterSpaceBounds());
1809 : }
1810 :
1811 : // FilterPrimitiveDescription
1812 :
1813 0 : FilterPrimitiveDescription::FilterPrimitiveDescription()
1814 : : mType(PrimitiveType::Empty)
1815 : , mOutputColorSpace(ColorSpace::SRGB)
1816 0 : , mIsTainted(false)
1817 : {
1818 0 : }
1819 :
1820 0 : FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType)
1821 : : mType(aType)
1822 : , mOutputColorSpace(ColorSpace::SRGB)
1823 0 : , mIsTainted(false)
1824 : {
1825 0 : }
1826 :
1827 0 : FilterPrimitiveDescription::FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther)
1828 0 : : mType(aOther.mType)
1829 : , mAttributes(aOther.mAttributes)
1830 : , mInputPrimitives(aOther.mInputPrimitives)
1831 : , mFilterPrimitiveSubregion(aOther.mFilterPrimitiveSubregion)
1832 : , mFilterSpaceBounds(aOther.mFilterSpaceBounds)
1833 : , mInputColorSpaces(aOther.mInputColorSpaces)
1834 0 : , mOutputColorSpace(aOther.mOutputColorSpace)
1835 0 : , mIsTainted(aOther.mIsTainted)
1836 : {
1837 0 : }
1838 :
1839 : FilterPrimitiveDescription&
1840 0 : FilterPrimitiveDescription::operator=(const FilterPrimitiveDescription& aOther)
1841 : {
1842 0 : if (this != &aOther) {
1843 0 : mType = aOther.mType;
1844 0 : mAttributes = aOther.mAttributes;
1845 0 : mInputPrimitives = aOther.mInputPrimitives;
1846 0 : mFilterPrimitiveSubregion = aOther.mFilterPrimitiveSubregion;
1847 0 : mFilterSpaceBounds = aOther.mFilterSpaceBounds;
1848 0 : mInputColorSpaces = aOther.mInputColorSpaces;
1849 0 : mOutputColorSpace = aOther.mOutputColorSpace;
1850 0 : mIsTainted = aOther.mIsTainted;
1851 : }
1852 0 : return *this;
1853 : }
1854 :
1855 : bool
1856 0 : FilterPrimitiveDescription::operator==(const FilterPrimitiveDescription& aOther) const
1857 : {
1858 0 : return mType == aOther.mType &&
1859 0 : mFilterPrimitiveSubregion.IsEqualInterior(aOther.mFilterPrimitiveSubregion) &&
1860 0 : mFilterSpaceBounds.IsEqualInterior(aOther.mFilterSpaceBounds) &&
1861 0 : mOutputColorSpace == aOther.mOutputColorSpace &&
1862 0 : mIsTainted == aOther.mIsTainted &&
1863 0 : mInputPrimitives == aOther.mInputPrimitives &&
1864 0 : mInputColorSpaces == aOther.mInputColorSpaces &&
1865 0 : mAttributes == aOther.mAttributes;
1866 : }
1867 :
1868 : // FilterDescription
1869 :
1870 : bool
1871 0 : FilterDescription::operator==(const FilterDescription& aOther) const
1872 : {
1873 0 : return mPrimitives == aOther.mPrimitives;
1874 : }
1875 :
1876 : // AttributeMap
1877 :
1878 : // A class that wraps different types for easy storage in a hashtable. Only
1879 : // used by AttributeMap.
1880 : struct FilterAttribute {
1881 : FilterAttribute(const FilterAttribute& aOther);
1882 : ~FilterAttribute();
1883 :
1884 : bool operator==(const FilterAttribute& aOther) const;
1885 0 : bool operator!=(const FilterAttribute& aOther) const
1886 : {
1887 0 : return !(*this == aOther);
1888 : }
1889 :
1890 0 : AttributeType Type() const { return mType; }
1891 :
1892 : #define MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(type, typeLabel) \
1893 : explicit FilterAttribute(type aValue) \
1894 : : mType(AttributeType::e##typeLabel), m##typeLabel(aValue) \
1895 : {} \
1896 : type As##typeLabel() { \
1897 : MOZ_ASSERT(mType == AttributeType::e##typeLabel); \
1898 : return m##typeLabel; \
1899 : }
1900 :
1901 : #define MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(className) \
1902 : explicit FilterAttribute(const className& aValue) \
1903 : : mType(AttributeType::e##className), m##className(new className(aValue)) \
1904 : {} \
1905 : className As##className() { \
1906 : MOZ_ASSERT(mType == AttributeType::e##className); \
1907 : return *m##className; \
1908 : }
1909 :
1910 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(bool, Bool)
1911 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(uint32_t, Uint)
1912 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(float, Float)
1913 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Size)
1914 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntSize)
1915 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntPoint)
1916 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix)
1917 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix5x4)
1918 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Point3D)
1919 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Color)
1920 0 : MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(AttributeMap)
1921 :
1922 : #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC
1923 : #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS
1924 :
1925 0 : FilterAttribute(const float* aValue, uint32_t aLength)
1926 0 : : mType(AttributeType::eFloats)
1927 : {
1928 0 : mFloats = new nsTArray<float>();
1929 0 : mFloats->AppendElements(aValue, aLength);
1930 0 : }
1931 :
1932 0 : const nsTArray<float>& AsFloats() const {
1933 0 : MOZ_ASSERT(mType == AttributeType::eFloats);
1934 0 : return *mFloats;
1935 : }
1936 :
1937 : private:
1938 : const AttributeType mType;
1939 :
1940 : union {
1941 : bool mBool;
1942 : uint32_t mUint;
1943 : float mFloat;
1944 : Size* mSize;
1945 : IntSize* mIntSize;
1946 : IntPoint* mIntPoint;
1947 : Matrix* mMatrix;
1948 : Matrix5x4* mMatrix5x4;
1949 : Point3D* mPoint3D;
1950 : Color* mColor;
1951 : AttributeMap* mAttributeMap;
1952 : nsTArray<float>* mFloats;
1953 : };
1954 : };
1955 :
1956 0 : FilterAttribute::FilterAttribute(const FilterAttribute& aOther)
1957 0 : : mType(aOther.mType)
1958 : {
1959 0 : switch (mType) {
1960 : case AttributeType::eBool:
1961 0 : mBool = aOther.mBool;
1962 0 : break;
1963 : case AttributeType::eUint:
1964 0 : mUint = aOther.mUint;
1965 0 : break;
1966 : case AttributeType::eFloat:
1967 0 : mFloat = aOther.mFloat;
1968 0 : break;
1969 :
1970 : #define HANDLE_CLASS(className) \
1971 : case AttributeType::e##className: \
1972 : m##className = new className(*aOther.m##className); \
1973 : break;
1974 :
1975 0 : HANDLE_CLASS(Size)
1976 0 : HANDLE_CLASS(IntSize)
1977 0 : HANDLE_CLASS(IntPoint)
1978 0 : HANDLE_CLASS(Matrix)
1979 0 : HANDLE_CLASS(Matrix5x4)
1980 0 : HANDLE_CLASS(Point3D)
1981 0 : HANDLE_CLASS(Color)
1982 0 : HANDLE_CLASS(AttributeMap)
1983 :
1984 : #undef HANDLE_CLASS
1985 :
1986 : case AttributeType::eFloats:
1987 0 : mFloats = new nsTArray<float>(*aOther.mFloats);
1988 0 : break;
1989 : case AttributeType::Max:
1990 0 : break;
1991 : }
1992 0 : }
1993 :
1994 0 : FilterAttribute::~FilterAttribute() {
1995 0 : switch (mType) {
1996 : case AttributeType::Max:
1997 : case AttributeType::eBool:
1998 : case AttributeType::eUint:
1999 : case AttributeType::eFloat:
2000 0 : break;
2001 :
2002 : #define HANDLE_CLASS(className) \
2003 : case AttributeType::e##className: \
2004 : delete m##className; \
2005 : break;
2006 :
2007 0 : HANDLE_CLASS(Size)
2008 0 : HANDLE_CLASS(IntSize)
2009 0 : HANDLE_CLASS(IntPoint)
2010 0 : HANDLE_CLASS(Matrix)
2011 0 : HANDLE_CLASS(Matrix5x4)
2012 0 : HANDLE_CLASS(Point3D)
2013 0 : HANDLE_CLASS(Color)
2014 0 : HANDLE_CLASS(AttributeMap)
2015 :
2016 : #undef HANDLE_CLASS
2017 :
2018 : case AttributeType::eFloats:
2019 0 : delete mFloats;
2020 0 : break;
2021 : }
2022 0 : }
2023 :
2024 : bool
2025 0 : FilterAttribute::operator==(const FilterAttribute& aOther) const
2026 : {
2027 0 : if (mType != aOther.mType) {
2028 0 : return false;
2029 : }
2030 :
2031 0 : switch (mType) {
2032 :
2033 : #define HANDLE_TYPE(typeName) \
2034 : case AttributeType::e##typeName: \
2035 : return m##typeName == aOther.m##typeName;
2036 :
2037 0 : HANDLE_TYPE(Bool)
2038 0 : HANDLE_TYPE(Uint)
2039 0 : HANDLE_TYPE(Float)
2040 0 : HANDLE_TYPE(Size)
2041 0 : HANDLE_TYPE(IntSize)
2042 0 : HANDLE_TYPE(IntPoint)
2043 0 : HANDLE_TYPE(Matrix)
2044 0 : HANDLE_TYPE(Matrix5x4)
2045 0 : HANDLE_TYPE(Point3D)
2046 0 : HANDLE_TYPE(Color)
2047 0 : HANDLE_TYPE(AttributeMap)
2048 0 : HANDLE_TYPE(Floats)
2049 :
2050 : #undef HANDLE_TYPE
2051 :
2052 : default:
2053 0 : return false;
2054 : }
2055 : }
2056 :
2057 : typedef FilterAttribute Attribute;
2058 :
2059 0 : AttributeMap::AttributeMap()
2060 : {
2061 0 : }
2062 :
2063 0 : AttributeMap::~AttributeMap()
2064 : {
2065 0 : }
2066 :
2067 0 : AttributeMap::AttributeMap(const AttributeMap& aOther)
2068 : {
2069 0 : for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
2070 0 : const uint32_t& attributeName = iter.Key();
2071 0 : Attribute* attribute = iter.UserData();
2072 0 : mMap.Put(attributeName, new Attribute(*attribute));
2073 : }
2074 0 : }
2075 :
2076 : AttributeMap&
2077 0 : AttributeMap::operator=(const AttributeMap& aOther)
2078 : {
2079 0 : if (this != &aOther) {
2080 0 : mMap.Clear();
2081 0 : for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
2082 0 : const uint32_t& attributeName = iter.Key();
2083 0 : Attribute* attribute = iter.UserData();
2084 0 : mMap.Put(attributeName, new Attribute(*attribute));
2085 : }
2086 : }
2087 0 : return *this;
2088 : }
2089 :
2090 : bool
2091 0 : AttributeMap::operator==(const AttributeMap& aOther) const
2092 : {
2093 0 : if (mMap.Count() != aOther.mMap.Count()) {
2094 0 : return false;
2095 : }
2096 :
2097 0 : for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
2098 0 : const uint32_t& attributeName = iter.Key();
2099 0 : Attribute* attribute = iter.UserData();
2100 0 : Attribute* matchingAttribute = mMap.Get(attributeName);
2101 0 : if (!matchingAttribute || *matchingAttribute != *attribute) {
2102 0 : return false;
2103 : }
2104 : }
2105 :
2106 0 : return true;
2107 : }
2108 :
2109 : uint32_t
2110 0 : AttributeMap::Count() const
2111 : {
2112 0 : return mMap.Count();
2113 : }
2114 :
2115 : nsClassHashtable<nsUint32HashKey, FilterAttribute>::Iterator
2116 0 : AttributeMap::ConstIter() const
2117 : {
2118 0 : return mMap.ConstIter();
2119 : }
2120 :
2121 : /* static */ AttributeType
2122 0 : AttributeMap::GetType(FilterAttribute* aAttribute)
2123 : {
2124 0 : return aAttribute->Type();
2125 : }
2126 :
2127 : #define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \
2128 : type \
2129 : AttributeMap::Get##typeLabel(AttributeName aName) const { \
2130 : Attribute* value = mMap.Get(aName); \
2131 : return value ? value->As##typeLabel() : defaultValue; \
2132 : } \
2133 : void \
2134 : AttributeMap::Set(AttributeName aName, type aValue) { \
2135 : mMap.Put(aName, new Attribute(aValue)); \
2136 : }
2137 :
2138 : #define MAKE_ATTRIBUTE_HANDLERS_CLASS(className) \
2139 : className \
2140 : AttributeMap::Get##className(AttributeName aName) const { \
2141 : Attribute* value = mMap.Get(aName); \
2142 : return value ? value->As##className() : className(); \
2143 : } \
2144 : void \
2145 : AttributeMap::Set(AttributeName aName, const className& aValue) { \
2146 : mMap.Put(aName, new Attribute(aValue)); \
2147 : }
2148 :
2149 0 : MAKE_ATTRIBUTE_HANDLERS_BASIC(bool, Bool, false)
2150 0 : MAKE_ATTRIBUTE_HANDLERS_BASIC(uint32_t, Uint, 0)
2151 0 : MAKE_ATTRIBUTE_HANDLERS_BASIC(float, Float, 0)
2152 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Size)
2153 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(IntSize)
2154 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(IntPoint)
2155 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix)
2156 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix5x4)
2157 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Point3D)
2158 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Color)
2159 0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(AttributeMap)
2160 :
2161 : #undef MAKE_ATTRIBUTE_HANDLERS_BASIC
2162 : #undef MAKE_ATTRIBUTE_HANDLERS_CLASS
2163 :
2164 : const nsTArray<float>&
2165 0 : AttributeMap::GetFloats(AttributeName aName) const
2166 : {
2167 0 : Attribute* value = mMap.LookupForAdd(aName).OrInsert(
2168 0 : [] () { return new Attribute(nullptr, 0); });
2169 0 : return value->AsFloats();
2170 : }
2171 :
2172 : void
2173 0 : AttributeMap::Set(AttributeName aName, const float* aValues, int32_t aLength)
2174 : {
2175 0 : mMap.Put(aName, new Attribute(aValues, aLength));
2176 0 : }
2177 :
2178 : } // namespace gfx
2179 : } // namespace mozilla
|