|
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/PodOperations.h" |
|
11 |
|
12 #include "gfxContext.h" |
|
13 #include "gfxPattern.h" |
|
14 #include "gfxPlatform.h" |
|
15 #include "gfx2DGlue.h" |
|
16 |
|
17 #include "nsMargin.h" |
|
18 |
|
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 }; |
|
55 |
|
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 }; |
|
92 |
|
93 namespace mozilla { |
|
94 namespace gfx { |
|
95 |
|
96 // Some convenience FilterNode creation functions. |
|
97 |
|
98 static const float kMaxStdDeviation = 500; |
|
99 |
|
100 namespace FilterWrappers { |
|
101 |
|
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 } |
|
109 |
|
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 } |
|
117 |
|
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 } |
|
132 |
|
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 } |
|
147 |
|
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 } |
|
156 |
|
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 } |
|
165 |
|
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 } |
|
187 |
|
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 } |
|
195 |
|
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 } |
|
206 |
|
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 } |
|
222 |
|
223 } |
|
224 |
|
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); |
|
242 |
|
243 // Get a FilterNode for the specified color model, guaranteed to be non-null. |
|
244 TemporaryRef<FilterNode> ForColorModel(ColorModel aColorModel); |
|
245 |
|
246 AlphaModel OriginalAlphaModel() const { return mOriginalColorModel.mAlphaModel; } |
|
247 |
|
248 private: |
|
249 // Create the required FilterNode that will be cached by ForColorModel. |
|
250 TemporaryRef<FilterNode> WrapForColorModel(ColorModel aColorModel); |
|
251 |
|
252 RefPtr<DrawTarget> mDT; |
|
253 ColorModel mOriginalColorModel; |
|
254 |
|
255 // This array is indexed by ColorModel::ToIndex. |
|
256 RefPtr<FilterNode> mFilterForColorModel[4]; |
|
257 }; |
|
258 |
|
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 } |
|
275 |
|
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 } |
|
284 |
|
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. |
|
293 |
|
294 if (aColorModel.mAlphaModel == AlphaModel::Premultiplied) { |
|
295 RefPtr<FilterNode> unpre = |
|
296 ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Unpremultiplied)); |
|
297 return FilterWrappers::Premultiply(mDT, unpre); |
|
298 } |
|
299 |
|
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 } |
|
306 |
|
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 } |
|
314 |
|
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 }; |
|
326 |
|
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 }; |
|
332 |
|
333 switch (aColorMatrixType) { |
|
334 |
|
335 case SVG_FECOLORMATRIX_TYPE_MATRIX: |
|
336 { |
|
337 if (aValues.Length() != 20) |
|
338 return NS_ERROR_FAILURE; |
|
339 |
|
340 PodCopy(aOutMatrix, aValues.Elements(), 20); |
|
341 break; |
|
342 } |
|
343 |
|
344 case SVG_FECOLORMATRIX_TYPE_SATURATE: |
|
345 { |
|
346 if (aValues.Length() != 1) |
|
347 return NS_ERROR_FAILURE; |
|
348 |
|
349 float s = aValues[0]; |
|
350 |
|
351 if (s < 0) |
|
352 return NS_ERROR_FAILURE; |
|
353 |
|
354 PodCopy(aOutMatrix, identityMatrix, 20); |
|
355 |
|
356 aOutMatrix[0] = 0.213f + 0.787f * s; |
|
357 aOutMatrix[1] = 0.715f - 0.715f * s; |
|
358 aOutMatrix[2] = 0.072f - 0.072f * s; |
|
359 |
|
360 aOutMatrix[5] = 0.213f - 0.213f * s; |
|
361 aOutMatrix[6] = 0.715f + 0.285f * s; |
|
362 aOutMatrix[7] = 0.072f - 0.072f * s; |
|
363 |
|
364 aOutMatrix[10] = 0.213f - 0.213f * s; |
|
365 aOutMatrix[11] = 0.715f - 0.715f * s; |
|
366 aOutMatrix[12] = 0.072f + 0.928f * s; |
|
367 |
|
368 break; |
|
369 } |
|
370 |
|
371 case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE: |
|
372 { |
|
373 if (aValues.Length() != 1) |
|
374 return NS_ERROR_FAILURE; |
|
375 |
|
376 PodCopy(aOutMatrix, identityMatrix, 20); |
|
377 |
|
378 float hueRotateValue = aValues[0]; |
|
379 |
|
380 float c = static_cast<float>(cos(hueRotateValue * M_PI / 180)); |
|
381 float s = static_cast<float>(sin(hueRotateValue * M_PI / 180)); |
|
382 |
|
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; |
|
386 |
|
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; |
|
390 |
|
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; |
|
394 |
|
395 break; |
|
396 } |
|
397 |
|
398 case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA: |
|
399 { |
|
400 PodCopy(aOutMatrix, luminanceToAlphaMatrix, 20); |
|
401 break; |
|
402 } |
|
403 |
|
404 default: |
|
405 return NS_ERROR_FAILURE; |
|
406 |
|
407 } |
|
408 |
|
409 return NS_OK; |
|
410 } |
|
411 |
|
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 } |
|
420 |
|
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 }; |
|
454 |
|
455 RefPtr<FilterNode> filter; |
|
456 |
|
457 uint32_t type = aFunctionAttributes.GetUint(eComponentTransferFunctionType); |
|
458 |
|
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; |
|
466 |
|
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 } |
|
482 |
|
483 case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE: |
|
484 { |
|
485 const nsTArray<float>& tableValues = |
|
486 aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues); |
|
487 if (tableValues.Length() < 1) |
|
488 return; |
|
489 |
|
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()); |
|
503 |
|
504 break; |
|
505 } |
|
506 |
|
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 } |
|
533 |
|
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 } |
|
568 |
|
569 case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY: |
|
570 default: |
|
571 break; |
|
572 } |
|
573 } |
|
574 |
|
575 const int32_t kMorphologyMaxRadius = 100000; |
|
576 |
|
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()) { |
|
593 |
|
594 case PrimitiveType::Empty: |
|
595 return nullptr; |
|
596 |
|
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 } |
|
624 |
|
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 } |
|
644 |
|
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 } |
|
657 |
|
658 // Clamp radii to prevent completely insane values: |
|
659 rx = std::min(rx, kMorphologyMaxRadius); |
|
660 ry = std::min(ry, kMorphologyMaxRadius); |
|
661 |
|
662 MorphologyOperator op = atts.GetUint(eMorphologyOperator) == SVG_OPERATOR_ERODE ? |
|
663 MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE; |
|
664 |
|
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 } |
|
671 |
|
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 } |
|
679 |
|
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 } |
|
687 |
|
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 } |
|
703 |
|
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 } |
|
712 |
|
713 return lastFilter; |
|
714 } |
|
715 |
|
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 } |
|
746 |
|
747 case PrimitiveType::Offset: |
|
748 { |
|
749 return FilterWrappers::Offset(aDT, aSources[0], |
|
750 atts.GetIntPoint(eOffsetOffset)); |
|
751 } |
|
752 |
|
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 } |
|
773 |
|
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 } |
|
796 |
|
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 } |
|
824 |
|
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 } |
|
840 |
|
841 case PrimitiveType::GaussianBlur: |
|
842 { |
|
843 return FilterWrappers::GaussianBlur(aDT, aSources[0], |
|
844 atts.GetSize(eGaussianBlurStdDeviation)); |
|
845 } |
|
846 |
|
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); |
|
863 |
|
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); |
|
868 |
|
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 } |
|
875 |
|
876 case PrimitiveType::DiffuseLighting: |
|
877 case PrimitiveType::SpecularLighting: |
|
878 { |
|
879 bool isSpecular = |
|
880 aDescription.Type() == PrimitiveType::SpecularLighting; |
|
881 |
|
882 AttributeMap lightAttributes = atts.GetAttributeMap(eLightingLight); |
|
883 |
|
884 if (lightAttributes.GetUint(eLightType) == eLightTypeNone) { |
|
885 return nullptr; |
|
886 } |
|
887 |
|
888 enum { POINT = 0, SPOT, DISTANT } lightType = POINT; |
|
889 |
|
890 switch (lightAttributes.GetUint(eLightType)) { |
|
891 case eLightTypePoint: lightType = POINT; break; |
|
892 case eLightTypeSpot: lightType = SPOT; break; |
|
893 case eLightTypeDistant: lightType = DISTANT; break; |
|
894 } |
|
895 |
|
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]); |
|
902 |
|
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)); |
|
909 |
|
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 } |
|
919 |
|
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 } |
|
942 |
|
943 filter->SetInput(IN_LIGHTING_IN, aSources[0]); |
|
944 |
|
945 return filter; |
|
946 } |
|
947 |
|
948 case PrimitiveType::Image: |
|
949 { |
|
950 Matrix TM = atts.GetMatrix(eImageTransform); |
|
951 if (!TM.Determinant()) { |
|
952 return nullptr; |
|
953 } |
|
954 |
|
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)]; |
|
959 |
|
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 } |
|
966 |
|
967 default: |
|
968 return nullptr; |
|
969 } |
|
970 } |
|
971 |
|
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 } |
|
993 |
|
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; |
|
1003 |
|
1004 case PrimitiveType::ColorMatrix: |
|
1005 case PrimitiveType::ComponentTransfer: |
|
1006 return AlphaModel::Unpremultiplied; |
|
1007 |
|
1008 case PrimitiveType::DisplacementMap: |
|
1009 return aInputIndex == 0 ? |
|
1010 AlphaModel::Premultiplied : AlphaModel::Unpremultiplied; |
|
1011 |
|
1012 case PrimitiveType::ConvolveMatrix: |
|
1013 return aDescr.Attributes().GetBool(eConvolveMatrixPreserveAlpha) ? |
|
1014 AlphaModel::Unpremultiplied : AlphaModel::Premultiplied; |
|
1015 |
|
1016 default: |
|
1017 return AlphaModel::Premultiplied; |
|
1018 } |
|
1019 } |
|
1020 |
|
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 } |
|
1030 |
|
1031 // All filters without inputs produce premultiplied alpha. |
|
1032 return AlphaModel::Premultiplied; |
|
1033 } |
|
1034 |
|
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; |
|
1050 |
|
1051 Rect resultNeededRect(aResultNeededRect); |
|
1052 resultNeededRect.RoundOut(); |
|
1053 |
|
1054 RefPtr<FilterCachedColorModels> sourceFilters[4]; |
|
1055 nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters; |
|
1056 |
|
1057 for (size_t i = 0; i < primitives.Length(); ++i) { |
|
1058 const FilterPrimitiveDescription& descr = primitives[i]; |
|
1059 |
|
1060 nsTArray<RefPtr<FilterNode> > inputFilterNodes; |
|
1061 nsTArray<IntRect> inputSourceRects; |
|
1062 nsTArray<AlphaModel> inputAlphaModels; |
|
1063 |
|
1064 for (size_t j = 0; j < descr.NumberOfInputs(); j++) { |
|
1065 |
|
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 } |
|
1073 |
|
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; |
|
1086 |
|
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); |
|
1098 |
|
1099 if (inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) { |
|
1100 sourceFilterNode = FilterWrappers::ToAlpha(aDT, sourceFilterNode); |
|
1101 } |
|
1102 } |
|
1103 |
|
1104 inputFilter = new FilterCachedColorModels(aDT, sourceFilterNode, |
|
1105 ColorModel::PremulSRGB()); |
|
1106 sourceFilters[sourceIndex] = inputFilter; |
|
1107 } |
|
1108 } |
|
1109 MOZ_ASSERT(inputFilter); |
|
1110 |
|
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 } |
|
1117 |
|
1118 RefPtr<FilterNode> primitiveFilterNode = |
|
1119 FilterNodeFromPrimitiveDescription(descr, aDT, inputFilterNodes, |
|
1120 inputSourceRects, aAdditionalImages); |
|
1121 |
|
1122 if (primitiveFilterNode) { |
|
1123 IntRect cropRect = filterSpaceBounds.Intersect(descr.PrimitiveSubregion()); |
|
1124 primitiveFilterNode = FilterWrappers::Crop(aDT, primitiveFilterNode, cropRect); |
|
1125 } |
|
1126 |
|
1127 ColorModel outputColorModel(descr.OutputColorSpace(), |
|
1128 OutputAlphaModelForPrimitive(descr, inputAlphaModels)); |
|
1129 RefPtr<FilterCachedColorModels> primitiveFilter = |
|
1130 new FilterCachedColorModels(aDT, primitiveFilterNode, outputColorModel); |
|
1131 |
|
1132 primitiveFilters.AppendElement(primitiveFilter); |
|
1133 } |
|
1134 |
|
1135 return primitiveFilters.LastElement()->ForColorModel(ColorModel::PremulSRGB()); |
|
1136 } |
|
1137 |
|
1138 // FilterSupport |
|
1139 |
|
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); |
|
1156 |
|
1157 aDT->DrawFilter(resultFilter, aRenderRect, Point(0, 0)); |
|
1158 } |
|
1159 |
|
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 } |
|
1169 |
|
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 } |
|
1176 |
|
1177 static nsIntRegion |
|
1178 ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription, |
|
1179 const nsTArray<nsIntRegion>& aInputChangeRegions) |
|
1180 { |
|
1181 const AttributeMap& atts = aDescription.Attributes(); |
|
1182 switch (aDescription.Type()) { |
|
1183 |
|
1184 case PrimitiveType::Empty: |
|
1185 case PrimitiveType::Flood: |
|
1186 case PrimitiveType::Turbulence: |
|
1187 case PrimitiveType::Image: |
|
1188 return nsIntRegion(); |
|
1189 |
|
1190 case PrimitiveType::Blend: |
|
1191 case PrimitiveType::Composite: |
|
1192 case PrimitiveType::Merge: |
|
1193 return UnionOfRegions(aInputChangeRegions); |
|
1194 |
|
1195 case PrimitiveType::ColorMatrix: |
|
1196 case PrimitiveType::ComponentTransfer: |
|
1197 return aInputChangeRegions[0]; |
|
1198 |
|
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 } |
|
1206 |
|
1207 case PrimitiveType::Tile: |
|
1208 return ThebesIntRect(aDescription.PrimitiveSubregion()); |
|
1209 |
|
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 } |
|
1221 |
|
1222 case PrimitiveType::Offset: |
|
1223 { |
|
1224 IntPoint offset = atts.GetIntPoint(eOffsetOffset); |
|
1225 return aInputChangeRegions[0].MovedBy(offset.x, offset.y); |
|
1226 } |
|
1227 |
|
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 } |
|
1233 |
|
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 } |
|
1241 |
|
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 } |
|
1253 |
|
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 } |
|
1262 |
|
1263 default: |
|
1264 return nsIntRegion(); |
|
1265 } |
|
1266 } |
|
1267 |
|
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; |
|
1276 |
|
1277 for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) { |
|
1278 const FilterPrimitiveDescription& descr = primitives[i]; |
|
1279 |
|
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 } |
|
1297 |
|
1298 return resultChangeRegions[resultChangeRegions.Length() - 1]; |
|
1299 } |
|
1300 |
|
1301 static nsIntRegion |
|
1302 PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription, |
|
1303 const nsTArray<nsIntRegion>& aInputExtents) |
|
1304 { |
|
1305 const AttributeMap& atts = aDescription.Attributes(); |
|
1306 switch (aDescription.Type()) { |
|
1307 |
|
1308 case PrimitiveType::Empty: |
|
1309 return nsIntRect(); |
|
1310 |
|
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); |
|
1319 |
|
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 } |
|
1342 |
|
1343 case PrimitiveType::Flood: |
|
1344 { |
|
1345 if (atts.GetColor(eFloodColor).a == 0.0f) { |
|
1346 return nsIntRect(); |
|
1347 } |
|
1348 return ThebesIntRect(aDescription.PrimitiveSubregion()); |
|
1349 } |
|
1350 |
|
1351 case PrimitiveType::Turbulence: |
|
1352 case PrimitiveType::Image: |
|
1353 { |
|
1354 return ThebesIntRect(aDescription.PrimitiveSubregion()); |
|
1355 } |
|
1356 |
|
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 } |
|
1368 |
|
1369 default: |
|
1370 return ResultChangeRegionForPrimitive(aDescription, aInputExtents); |
|
1371 } |
|
1372 } |
|
1373 |
|
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; |
|
1381 |
|
1382 for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) { |
|
1383 const FilterPrimitiveDescription& descr = primitives[i]; |
|
1384 |
|
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 } |
|
1400 |
|
1401 return postFilterExtents[postFilterExtents.Length() - 1]; |
|
1402 } |
|
1403 |
|
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()) { |
|
1411 |
|
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(); |
|
1417 |
|
1418 case PrimitiveType::Empty: |
|
1419 return nsIntRegion(); |
|
1420 |
|
1421 case PrimitiveType::Blend: |
|
1422 case PrimitiveType::Composite: |
|
1423 case PrimitiveType::Merge: |
|
1424 case PrimitiveType::ColorMatrix: |
|
1425 case PrimitiveType::ComponentTransfer: |
|
1426 return aResultNeededRegion; |
|
1427 |
|
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 } |
|
1435 |
|
1436 case PrimitiveType::Tile: |
|
1437 return nsIntRect(INT32_MIN/2, INT32_MIN/2, INT32_MAX, INT32_MAX); |
|
1438 |
|
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 } |
|
1450 |
|
1451 case PrimitiveType::Offset: |
|
1452 { |
|
1453 IntPoint offset = atts.GetIntPoint(eOffsetOffset); |
|
1454 return aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y)); |
|
1455 } |
|
1456 |
|
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 } |
|
1465 |
|
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 } |
|
1473 |
|
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 } |
|
1486 |
|
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 } |
|
1495 |
|
1496 default: |
|
1497 return nsIntRegion(); |
|
1498 } |
|
1499 |
|
1500 } |
|
1501 |
|
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()); |
|
1512 |
|
1513 primitiveNeededRegions[primitives.Length() - 1] = aResultNeededRegion; |
|
1514 |
|
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())); |
|
1519 |
|
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 } |
|
1531 |
|
1532 aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion, |
|
1533 ThebesIntRect(aFilter.mFilterSpaceBounds)); |
|
1534 } |
|
1535 |
|
1536 // FilterPrimitiveDescription |
|
1537 |
|
1538 FilterPrimitiveDescription::FilterPrimitiveDescription() |
|
1539 : mType(PrimitiveType::Empty) |
|
1540 , mOutputColorSpace(ColorSpace::SRGB) |
|
1541 , mIsTainted(false) |
|
1542 { |
|
1543 } |
|
1544 |
|
1545 FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType) |
|
1546 : mType(aType) |
|
1547 , mOutputColorSpace(ColorSpace::SRGB) |
|
1548 , mIsTainted(false) |
|
1549 { |
|
1550 } |
|
1551 |
|
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 } |
|
1562 |
|
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 } |
|
1577 |
|
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 } |
|
1589 |
|
1590 // FilterDescription |
|
1591 |
|
1592 bool |
|
1593 FilterDescription::operator==(const FilterDescription& aOther) const |
|
1594 { |
|
1595 return mFilterSpaceBounds.IsEqualInterior(aOther.mFilterSpaceBounds) && |
|
1596 mPrimitives == aOther.mPrimitives; |
|
1597 } |
|
1598 |
|
1599 // AttributeMap |
|
1600 |
|
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(); |
|
1606 |
|
1607 bool operator==(const FilterAttribute& aOther) const; |
|
1608 bool operator!=(const FilterAttribute& aOther) const |
|
1609 { |
|
1610 return !(*this == aOther); |
|
1611 } |
|
1612 |
|
1613 AttributeType Type() const { return mType; } |
|
1614 |
|
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 } |
|
1623 |
|
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 } |
|
1632 |
|
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) |
|
1644 |
|
1645 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC |
|
1646 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS |
|
1647 |
|
1648 FilterAttribute(const float* aValue, uint32_t aLength) |
|
1649 : mType(AttributeType::eFloats) |
|
1650 { |
|
1651 mFloats = new nsTArray<float>(); |
|
1652 mFloats->AppendElements(aValue, aLength); |
|
1653 } |
|
1654 |
|
1655 const nsTArray<float>& AsFloats() const { |
|
1656 MOZ_ASSERT(mType == AttributeType::eFloats); |
|
1657 return *mFloats; |
|
1658 } |
|
1659 |
|
1660 private: |
|
1661 const AttributeType mType; |
|
1662 |
|
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 }; |
|
1678 |
|
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; |
|
1692 |
|
1693 #define HANDLE_CLASS(className) \ |
|
1694 case AttributeType::e##className: \ |
|
1695 m##className = new className(*aOther.m##className); \ |
|
1696 break; |
|
1697 |
|
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) |
|
1706 |
|
1707 #undef HANDLE_CLASS |
|
1708 |
|
1709 case AttributeType::eFloats: |
|
1710 mFloats = new nsTArray<float>(*aOther.mFloats); |
|
1711 break; |
|
1712 case AttributeType::Max: |
|
1713 break; |
|
1714 } |
|
1715 } |
|
1716 |
|
1717 FilterAttribute::~FilterAttribute() { |
|
1718 switch (mType) { |
|
1719 case AttributeType::Max: |
|
1720 case AttributeType::eBool: |
|
1721 case AttributeType::eUint: |
|
1722 case AttributeType::eFloat: |
|
1723 break; |
|
1724 |
|
1725 #define HANDLE_CLASS(className) \ |
|
1726 case AttributeType::e##className: \ |
|
1727 delete m##className; \ |
|
1728 break; |
|
1729 |
|
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) |
|
1738 |
|
1739 #undef HANDLE_CLASS |
|
1740 |
|
1741 case AttributeType::eFloats: |
|
1742 delete mFloats; |
|
1743 break; |
|
1744 } |
|
1745 } |
|
1746 |
|
1747 bool |
|
1748 FilterAttribute::operator==(const FilterAttribute& aOther) const |
|
1749 { |
|
1750 if (mType != aOther.mType) { |
|
1751 return false; |
|
1752 } |
|
1753 |
|
1754 switch (mType) { |
|
1755 |
|
1756 #define HANDLE_TYPE(typeName) \ |
|
1757 case AttributeType::e##typeName: \ |
|
1758 return m##typeName == aOther.m##typeName; |
|
1759 |
|
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) |
|
1772 |
|
1773 #undef HANDLE_TYPE |
|
1774 |
|
1775 default: |
|
1776 return false; |
|
1777 } |
|
1778 } |
|
1779 |
|
1780 typedef FilterAttribute Attribute; |
|
1781 |
|
1782 AttributeMap::AttributeMap() |
|
1783 { |
|
1784 } |
|
1785 |
|
1786 AttributeMap::~AttributeMap() |
|
1787 { |
|
1788 } |
|
1789 |
|
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 } |
|
1800 |
|
1801 AttributeMap::AttributeMap(const AttributeMap& aOther) |
|
1802 { |
|
1803 aOther.mMap.EnumerateRead(CopyAttribute, &mMap); |
|
1804 } |
|
1805 |
|
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 } |
|
1815 |
|
1816 namespace { |
|
1817 struct MatchingMap { |
|
1818 typedef nsClassHashtable<nsUint32HashKey, Attribute> Map; |
|
1819 const Map& map; |
|
1820 bool matches; |
|
1821 }; |
|
1822 } |
|
1823 |
|
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 } |
|
1838 |
|
1839 bool |
|
1840 AttributeMap::operator==(const AttributeMap& aOther) const |
|
1841 { |
|
1842 if (mMap.Count() != aOther.mMap.Count()) { |
|
1843 return false; |
|
1844 } |
|
1845 |
|
1846 MatchingMap matchingMap = { mMap, true }; |
|
1847 aOther.mMap.EnumerateRead(CheckAttributeEquality, &matchingMap); |
|
1848 return matchingMap.matches; |
|
1849 } |
|
1850 |
|
1851 namespace { |
|
1852 struct HandlerWithUserData |
|
1853 { |
|
1854 AttributeMap::AttributeHandleCallback handler; |
|
1855 void* userData; |
|
1856 }; |
|
1857 } |
|
1858 |
|
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 } |
|
1871 |
|
1872 void |
|
1873 AttributeMap::EnumerateRead(AttributeMap::AttributeHandleCallback aCallback, void* aUserData) const |
|
1874 { |
|
1875 HandlerWithUserData handlerWithUserData = { aCallback, aUserData }; |
|
1876 mMap.EnumerateRead(PassAttributeToHandleCallback, &handlerWithUserData); |
|
1877 } |
|
1878 |
|
1879 uint32_t |
|
1880 AttributeMap::Count() const |
|
1881 { |
|
1882 return mMap.Count(); |
|
1883 } |
|
1884 |
|
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 } |
|
1896 |
|
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 } |
|
1908 |
|
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) |
|
1920 |
|
1921 #undef MAKE_ATTRIBUTE_HANDLERS_BASIC |
|
1922 #undef MAKE_ATTRIBUTE_HANDLERS_CLASS |
|
1923 |
|
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 } |
|
1934 |
|
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 } |
|
1941 |
|
1942 } |
|
1943 } |