Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "FilterNodeD2D1.h"
8 #include "Logging.h"
10 #include "SourceSurfaceD2D1.h"
11 #include "SourceSurfaceD2D.h"
12 #include "SourceSurfaceD2DTarget.h"
13 #include "DrawTargetD2D.h"
14 #include "DrawTargetD2D1.h"
16 namespace mozilla {
17 namespace gfx {
19 D2D1_COLORMATRIX_ALPHA_MODE D2DAlphaMode(uint32_t aMode)
20 {
21 switch (aMode) {
22 case ALPHA_MODE_PREMULTIPLIED:
23 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED;
24 case ALPHA_MODE_STRAIGHT:
25 return D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT;
26 default:
27 MOZ_CRASH("Unknown enum value!");
28 }
30 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED;
31 }
33 D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE D2DAffineTransformInterpolationMode(Filter aFilter)
34 {
35 switch (aFilter) {
36 case Filter::GOOD:
37 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR;
38 case Filter::LINEAR:
39 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR;
40 case Filter::POINT:
41 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
42 default:
43 MOZ_CRASH("Unknown enum value!");
44 }
46 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR;
47 }
49 D2D1_BLEND_MODE D2DBlendMode(uint32_t aMode)
50 {
51 switch (aMode) {
52 case BLEND_MODE_DARKEN:
53 return D2D1_BLEND_MODE_DARKEN;
54 case BLEND_MODE_LIGHTEN:
55 return D2D1_BLEND_MODE_LIGHTEN;
56 case BLEND_MODE_MULTIPLY:
57 return D2D1_BLEND_MODE_MULTIPLY;
58 case BLEND_MODE_SCREEN:
59 return D2D1_BLEND_MODE_SCREEN;
60 default:
61 MOZ_CRASH("Unknown enum value!");
62 }
64 return D2D1_BLEND_MODE_DARKEN;
65 }
67 D2D1_MORPHOLOGY_MODE D2DMorphologyMode(uint32_t aMode)
68 {
69 switch (aMode) {
70 case MORPHOLOGY_OPERATOR_DILATE:
71 return D2D1_MORPHOLOGY_MODE_DILATE;
72 case MORPHOLOGY_OPERATOR_ERODE:
73 return D2D1_MORPHOLOGY_MODE_ERODE;
74 }
76 MOZ_CRASH("Unknown enum value!");
77 return D2D1_MORPHOLOGY_MODE_DILATE;
78 }
80 D2D1_TURBULENCE_NOISE D2DTurbulenceNoise(uint32_t aMode)
81 {
82 switch (aMode) {
83 case TURBULENCE_TYPE_FRACTAL_NOISE:
84 return D2D1_TURBULENCE_NOISE_FRACTAL_SUM;
85 case TURBULENCE_TYPE_TURBULENCE:
86 return D2D1_TURBULENCE_NOISE_TURBULENCE;
87 }
89 MOZ_CRASH("Unknown enum value!");
90 return D2D1_TURBULENCE_NOISE_TURBULENCE;
91 }
93 D2D1_COMPOSITE_MODE D2DFilterCompositionMode(uint32_t aMode)
94 {
95 switch (aMode) {
96 case COMPOSITE_OPERATOR_OVER:
97 return D2D1_COMPOSITE_MODE_SOURCE_OVER;
98 case COMPOSITE_OPERATOR_IN:
99 return D2D1_COMPOSITE_MODE_SOURCE_IN;
100 case COMPOSITE_OPERATOR_OUT:
101 return D2D1_COMPOSITE_MODE_SOURCE_OUT;
102 case COMPOSITE_OPERATOR_ATOP:
103 return D2D1_COMPOSITE_MODE_SOURCE_ATOP;
104 case COMPOSITE_OPERATOR_XOR:
105 return D2D1_COMPOSITE_MODE_XOR;
106 }
108 MOZ_CRASH("Unknown enum value!");
109 return D2D1_COMPOSITE_MODE_SOURCE_OVER;
110 }
112 D2D1_CHANNEL_SELECTOR D2DChannelSelector(uint32_t aMode)
113 {
114 switch (aMode) {
115 case COLOR_CHANNEL_R:
116 return D2D1_CHANNEL_SELECTOR_R;
117 case COLOR_CHANNEL_G:
118 return D2D1_CHANNEL_SELECTOR_G;
119 case COLOR_CHANNEL_B:
120 return D2D1_CHANNEL_SELECTOR_B;
121 case COLOR_CHANNEL_A:
122 return D2D1_CHANNEL_SELECTOR_A;
123 }
125 MOZ_CRASH("Unknown enum value!");
126 return D2D1_CHANNEL_SELECTOR_R;
127 }
129 TemporaryRef<ID2D1Image> GetImageForSourceSurface(DrawTarget *aDT, SourceSurface *aSurface)
130 {
131 switch (aDT->GetType()) {
132 case BackendType::DIRECT2D1_1:
133 return static_cast<DrawTargetD2D1*>(aDT)->GetImageForSurface(aSurface, ExtendMode::CLAMP);
134 case BackendType::DIRECT2D:
135 return static_cast<DrawTargetD2D*>(aDT)->GetImageForSurface(aSurface);
136 default:
137 MOZ_CRASH("Unknown draw target type!");
138 return nullptr;
139 }
140 }
142 uint32_t ConvertValue(FilterType aType, uint32_t aAttribute, uint32_t aValue)
143 {
144 switch (aType) {
145 case FilterType::COLOR_MATRIX:
146 if (aAttribute == ATT_COLOR_MATRIX_ALPHA_MODE) {
147 aValue = D2DAlphaMode(aValue);
148 }
149 break;
150 case FilterType::TRANSFORM:
151 if (aAttribute == ATT_TRANSFORM_FILTER) {
152 aValue = D2DAffineTransformInterpolationMode(Filter(aValue));
153 }
154 break;
155 case FilterType::BLEND:
156 if (aAttribute == ATT_BLEND_BLENDMODE) {
157 aValue = D2DBlendMode(aValue);
158 }
159 break;
160 case FilterType::MORPHOLOGY:
161 if (aAttribute == ATT_MORPHOLOGY_OPERATOR) {
162 aValue = D2DMorphologyMode(aValue);
163 }
164 break;
165 case FilterType::DISPLACEMENT_MAP:
166 if (aAttribute == ATT_DISPLACEMENT_MAP_X_CHANNEL ||
167 aAttribute == ATT_DISPLACEMENT_MAP_Y_CHANNEL) {
168 aValue = D2DChannelSelector(aValue);
169 }
170 break;
171 case FilterType::TURBULENCE:
172 if (aAttribute == ATT_TURBULENCE_TYPE) {
173 aValue = D2DTurbulenceNoise(aValue);
174 }
175 break;
176 case FilterType::COMPOSITE:
177 if (aAttribute == ATT_COMPOSITE_OPERATOR) {
178 aValue = D2DFilterCompositionMode(aValue);
179 }
180 break;
181 }
183 return aValue;
184 }
186 void ConvertValue(FilterType aType, uint32_t aAttribute, IntSize &aValue)
187 {
188 switch (aType) {
189 case FilterType::MORPHOLOGY:
190 if (aAttribute == ATT_MORPHOLOGY_RADII) {
191 aValue.width *= 2;
192 aValue.width += 1;
193 aValue.height *= 2;
194 aValue.height += 1;
195 }
196 break;
197 }
198 }
200 UINT32
201 GetD2D1InputForInput(FilterType aType, uint32_t aIndex)
202 {
203 return aIndex;
204 }
206 #define CONVERT_PROP(moz2dname, d2dname) \
207 case ATT_##moz2dname: \
208 return D2D1_##d2dname
210 UINT32
211 GetD2D1PropForAttribute(FilterType aType, uint32_t aIndex)
212 {
213 switch (aType) {
214 case FilterType::COLOR_MATRIX:
215 switch (aIndex) {
216 CONVERT_PROP(COLOR_MATRIX_MATRIX, COLORMATRIX_PROP_COLOR_MATRIX);
217 CONVERT_PROP(COLOR_MATRIX_ALPHA_MODE, COLORMATRIX_PROP_ALPHA_MODE);
218 }
219 break;
220 case FilterType::TRANSFORM:
221 switch (aIndex) {
222 CONVERT_PROP(TRANSFORM_MATRIX, 2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX);
223 CONVERT_PROP(TRANSFORM_FILTER, 2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE);
224 }
225 case FilterType::BLEND:
226 switch (aIndex) {
227 CONVERT_PROP(BLEND_BLENDMODE, BLEND_PROP_MODE);
228 }
229 break;
230 case FilterType::MORPHOLOGY:
231 switch (aIndex) {
232 CONVERT_PROP(MORPHOLOGY_OPERATOR, MORPHOLOGY_PROP_MODE);
233 }
234 break;
235 case FilterType::FLOOD:
236 switch (aIndex) {
237 CONVERT_PROP(FLOOD_COLOR, FLOOD_PROP_COLOR);
238 }
239 break;
240 case FilterType::TILE:
241 switch (aIndex) {
242 CONVERT_PROP(TILE_SOURCE_RECT, TILE_PROP_RECT);
243 }
244 break;
245 case FilterType::TABLE_TRANSFER:
246 switch (aIndex) {
247 CONVERT_PROP(TABLE_TRANSFER_DISABLE_R, TABLETRANSFER_PROP_RED_DISABLE);
248 CONVERT_PROP(TABLE_TRANSFER_DISABLE_G, TABLETRANSFER_PROP_GREEN_DISABLE);
249 CONVERT_PROP(TABLE_TRANSFER_DISABLE_B, TABLETRANSFER_PROP_BLUE_DISABLE);
250 CONVERT_PROP(TABLE_TRANSFER_DISABLE_A, TABLETRANSFER_PROP_ALPHA_DISABLE);
251 CONVERT_PROP(TABLE_TRANSFER_TABLE_R, TABLETRANSFER_PROP_RED_TABLE);
252 CONVERT_PROP(TABLE_TRANSFER_TABLE_G, TABLETRANSFER_PROP_GREEN_TABLE);
253 CONVERT_PROP(TABLE_TRANSFER_TABLE_B, TABLETRANSFER_PROP_BLUE_TABLE);
254 CONVERT_PROP(TABLE_TRANSFER_TABLE_A, TABLETRANSFER_PROP_ALPHA_TABLE);
255 }
256 break;
257 case FilterType::DISCRETE_TRANSFER:
258 switch (aIndex) {
259 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_R, DISCRETETRANSFER_PROP_RED_DISABLE);
260 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_G, DISCRETETRANSFER_PROP_GREEN_DISABLE);
261 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_B, DISCRETETRANSFER_PROP_BLUE_DISABLE);
262 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_A, DISCRETETRANSFER_PROP_ALPHA_DISABLE);
263 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_R, DISCRETETRANSFER_PROP_RED_TABLE);
264 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_G, DISCRETETRANSFER_PROP_GREEN_TABLE);
265 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_B, DISCRETETRANSFER_PROP_BLUE_TABLE);
266 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_A, DISCRETETRANSFER_PROP_ALPHA_TABLE);
267 }
268 break;
269 case FilterType::LINEAR_TRANSFER:
270 switch (aIndex) {
271 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_R, LINEARTRANSFER_PROP_RED_DISABLE);
272 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_G, LINEARTRANSFER_PROP_GREEN_DISABLE);
273 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_B, LINEARTRANSFER_PROP_BLUE_DISABLE);
274 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_A, LINEARTRANSFER_PROP_ALPHA_DISABLE);
275 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_R, LINEARTRANSFER_PROP_RED_Y_INTERCEPT);
276 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_G, LINEARTRANSFER_PROP_GREEN_Y_INTERCEPT);
277 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_B, LINEARTRANSFER_PROP_BLUE_Y_INTERCEPT);
278 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_A, LINEARTRANSFER_PROP_ALPHA_Y_INTERCEPT);
279 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_R, LINEARTRANSFER_PROP_RED_SLOPE);
280 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_G, LINEARTRANSFER_PROP_GREEN_SLOPE);
281 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_B, LINEARTRANSFER_PROP_BLUE_SLOPE);
282 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_A, LINEARTRANSFER_PROP_ALPHA_SLOPE);
283 }
284 break;
285 case FilterType::GAMMA_TRANSFER:
286 switch (aIndex) {
287 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_R, GAMMATRANSFER_PROP_RED_DISABLE);
288 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_G, GAMMATRANSFER_PROP_GREEN_DISABLE);
289 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_B, GAMMATRANSFER_PROP_BLUE_DISABLE);
290 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_A, GAMMATRANSFER_PROP_ALPHA_DISABLE);
291 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_R, GAMMATRANSFER_PROP_RED_AMPLITUDE);
292 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_G, GAMMATRANSFER_PROP_GREEN_AMPLITUDE);
293 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_B, GAMMATRANSFER_PROP_BLUE_AMPLITUDE);
294 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_A, GAMMATRANSFER_PROP_ALPHA_AMPLITUDE);
295 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_R, GAMMATRANSFER_PROP_RED_EXPONENT);
296 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_G, GAMMATRANSFER_PROP_GREEN_EXPONENT);
297 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_B, GAMMATRANSFER_PROP_BLUE_EXPONENT);
298 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_A, GAMMATRANSFER_PROP_ALPHA_EXPONENT);
299 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_R, GAMMATRANSFER_PROP_RED_OFFSET);
300 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_G, GAMMATRANSFER_PROP_GREEN_OFFSET);
301 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_B, GAMMATRANSFER_PROP_BLUE_OFFSET);
302 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_A, GAMMATRANSFER_PROP_ALPHA_OFFSET);
303 }
304 break;
305 case FilterType::CONVOLVE_MATRIX:
306 switch (aIndex) {
307 CONVERT_PROP(CONVOLVE_MATRIX_BIAS, CONVOLVEMATRIX_PROP_BIAS);
308 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_MATRIX, CONVOLVEMATRIX_PROP_KERNEL_MATRIX);
309 CONVERT_PROP(CONVOLVE_MATRIX_DIVISOR, CONVOLVEMATRIX_PROP_DIVISOR);
310 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, CONVOLVEMATRIX_PROP_KERNEL_UNIT_LENGTH);
311 CONVERT_PROP(CONVOLVE_MATRIX_PRESERVE_ALPHA, CONVOLVEMATRIX_PROP_PRESERVE_ALPHA);
312 }
313 case FilterType::DISPLACEMENT_MAP:
314 switch (aIndex) {
315 CONVERT_PROP(DISPLACEMENT_MAP_SCALE, DISPLACEMENTMAP_PROP_SCALE);
316 CONVERT_PROP(DISPLACEMENT_MAP_X_CHANNEL, DISPLACEMENTMAP_PROP_X_CHANNEL_SELECT);
317 CONVERT_PROP(DISPLACEMENT_MAP_Y_CHANNEL, DISPLACEMENTMAP_PROP_Y_CHANNEL_SELECT);
318 }
319 break;
320 case FilterType::TURBULENCE:
321 switch (aIndex) {
322 CONVERT_PROP(TURBULENCE_BASE_FREQUENCY, TURBULENCE_PROP_BASE_FREQUENCY);
323 CONVERT_PROP(TURBULENCE_NUM_OCTAVES, TURBULENCE_PROP_NUM_OCTAVES);
324 CONVERT_PROP(TURBULENCE_SEED, TURBULENCE_PROP_SEED);
325 CONVERT_PROP(TURBULENCE_STITCHABLE, TURBULENCE_PROP_STITCHABLE);
326 CONVERT_PROP(TURBULENCE_TYPE, TURBULENCE_PROP_NOISE);
327 }
328 break;
329 case FilterType::ARITHMETIC_COMBINE:
330 switch (aIndex) {
331 CONVERT_PROP(ARITHMETIC_COMBINE_COEFFICIENTS, ARITHMETICCOMPOSITE_PROP_COEFFICIENTS);
332 }
333 break;
334 case FilterType::COMPOSITE:
335 switch (aIndex) {
336 CONVERT_PROP(COMPOSITE_OPERATOR, COMPOSITE_PROP_MODE);
337 }
338 break;
339 case FilterType::GAUSSIAN_BLUR:
340 switch (aIndex) {
341 CONVERT_PROP(GAUSSIAN_BLUR_STD_DEVIATION, GAUSSIANBLUR_PROP_STANDARD_DEVIATION);
342 }
343 break;
344 case FilterType::DIRECTIONAL_BLUR:
345 switch (aIndex) {
346 CONVERT_PROP(DIRECTIONAL_BLUR_STD_DEVIATION, DIRECTIONALBLUR_PROP_STANDARD_DEVIATION);
347 CONVERT_PROP(DIRECTIONAL_BLUR_DIRECTION, DIRECTIONALBLUR_PROP_ANGLE);
348 }
349 break;
350 case FilterType::POINT_DIFFUSE:
351 switch (aIndex) {
352 CONVERT_PROP(POINT_DIFFUSE_DIFFUSE_CONSTANT, POINTDIFFUSE_PROP_DIFFUSE_CONSTANT);
353 CONVERT_PROP(POINT_DIFFUSE_POSITION, POINTDIFFUSE_PROP_LIGHT_POSITION);
354 CONVERT_PROP(POINT_DIFFUSE_COLOR, POINTDIFFUSE_PROP_COLOR);
355 CONVERT_PROP(POINT_DIFFUSE_SURFACE_SCALE, POINTDIFFUSE_PROP_SURFACE_SCALE);
356 CONVERT_PROP(POINT_DIFFUSE_KERNEL_UNIT_LENGTH, POINTDIFFUSE_PROP_KERNEL_UNIT_LENGTH);
357 }
358 break;
359 case FilterType::SPOT_DIFFUSE:
360 switch (aIndex) {
361 CONVERT_PROP(SPOT_DIFFUSE_DIFFUSE_CONSTANT, SPOTDIFFUSE_PROP_DIFFUSE_CONSTANT);
362 CONVERT_PROP(SPOT_DIFFUSE_POINTS_AT, SPOTDIFFUSE_PROP_POINTS_AT);
363 CONVERT_PROP(SPOT_DIFFUSE_FOCUS, SPOTDIFFUSE_PROP_FOCUS);
364 CONVERT_PROP(SPOT_DIFFUSE_LIMITING_CONE_ANGLE, SPOTDIFFUSE_PROP_LIMITING_CONE_ANGLE);
365 CONVERT_PROP(SPOT_DIFFUSE_POSITION, SPOTDIFFUSE_PROP_LIGHT_POSITION);
366 CONVERT_PROP(SPOT_DIFFUSE_COLOR, SPOTDIFFUSE_PROP_COLOR);
367 CONVERT_PROP(SPOT_DIFFUSE_SURFACE_SCALE, SPOTDIFFUSE_PROP_SURFACE_SCALE);
368 CONVERT_PROP(SPOT_DIFFUSE_KERNEL_UNIT_LENGTH, SPOTDIFFUSE_PROP_KERNEL_UNIT_LENGTH);
369 }
370 break;
371 case FilterType::DISTANT_DIFFUSE:
372 switch (aIndex) {
373 CONVERT_PROP(DISTANT_DIFFUSE_DIFFUSE_CONSTANT, DISTANTDIFFUSE_PROP_DIFFUSE_CONSTANT);
374 CONVERT_PROP(DISTANT_DIFFUSE_AZIMUTH, DISTANTDIFFUSE_PROP_AZIMUTH);
375 CONVERT_PROP(DISTANT_DIFFUSE_ELEVATION, DISTANTDIFFUSE_PROP_ELEVATION);
376 CONVERT_PROP(DISTANT_DIFFUSE_COLOR, DISTANTDIFFUSE_PROP_COLOR);
377 CONVERT_PROP(DISTANT_DIFFUSE_SURFACE_SCALE, DISTANTDIFFUSE_PROP_SURFACE_SCALE);
378 CONVERT_PROP(DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH, DISTANTDIFFUSE_PROP_KERNEL_UNIT_LENGTH);
379 }
380 break;
381 case FilterType::POINT_SPECULAR:
382 switch (aIndex) {
383 CONVERT_PROP(POINT_SPECULAR_SPECULAR_CONSTANT, POINTSPECULAR_PROP_SPECULAR_CONSTANT);
384 CONVERT_PROP(POINT_SPECULAR_SPECULAR_EXPONENT, POINTSPECULAR_PROP_SPECULAR_EXPONENT);
385 CONVERT_PROP(POINT_SPECULAR_POSITION, POINTSPECULAR_PROP_LIGHT_POSITION);
386 CONVERT_PROP(POINT_SPECULAR_COLOR, POINTSPECULAR_PROP_COLOR);
387 CONVERT_PROP(POINT_SPECULAR_SURFACE_SCALE, POINTSPECULAR_PROP_SURFACE_SCALE);
388 CONVERT_PROP(POINT_SPECULAR_KERNEL_UNIT_LENGTH, POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH);
389 }
390 break;
391 case FilterType::SPOT_SPECULAR:
392 switch (aIndex) {
393 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_CONSTANT, SPOTSPECULAR_PROP_SPECULAR_CONSTANT);
394 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_EXPONENT, SPOTSPECULAR_PROP_SPECULAR_EXPONENT);
395 CONVERT_PROP(SPOT_SPECULAR_POINTS_AT, SPOTSPECULAR_PROP_POINTS_AT);
396 CONVERT_PROP(SPOT_SPECULAR_FOCUS, SPOTSPECULAR_PROP_FOCUS);
397 CONVERT_PROP(SPOT_SPECULAR_LIMITING_CONE_ANGLE, SPOTSPECULAR_PROP_LIMITING_CONE_ANGLE);
398 CONVERT_PROP(SPOT_SPECULAR_POSITION, SPOTSPECULAR_PROP_LIGHT_POSITION);
399 CONVERT_PROP(SPOT_SPECULAR_COLOR, SPOTSPECULAR_PROP_COLOR);
400 CONVERT_PROP(SPOT_SPECULAR_SURFACE_SCALE, SPOTSPECULAR_PROP_SURFACE_SCALE);
401 CONVERT_PROP(SPOT_SPECULAR_KERNEL_UNIT_LENGTH, SPOTSPECULAR_PROP_KERNEL_UNIT_LENGTH);
402 }
403 break;
404 case FilterType::DISTANT_SPECULAR:
405 switch (aIndex) {
406 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_CONSTANT, DISTANTSPECULAR_PROP_SPECULAR_CONSTANT);
407 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_EXPONENT, DISTANTSPECULAR_PROP_SPECULAR_EXPONENT);
408 CONVERT_PROP(DISTANT_SPECULAR_AZIMUTH, DISTANTSPECULAR_PROP_AZIMUTH);
409 CONVERT_PROP(DISTANT_SPECULAR_ELEVATION, DISTANTSPECULAR_PROP_ELEVATION);
410 CONVERT_PROP(DISTANT_SPECULAR_COLOR, DISTANTSPECULAR_PROP_COLOR);
411 CONVERT_PROP(DISTANT_SPECULAR_SURFACE_SCALE, DISTANTSPECULAR_PROP_SURFACE_SCALE);
412 CONVERT_PROP(DISTANT_SPECULAR_KERNEL_UNIT_LENGTH, DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH);
413 }
414 break;
415 case FilterType::CROP:
416 switch (aIndex) {
417 CONVERT_PROP(CROP_RECT, CROP_PROP_RECT);
418 }
419 break;
420 }
422 return UINT32_MAX;
423 }
425 bool
426 GetD2D1PropsForIntSize(FilterType aType, uint32_t aIndex, UINT32 *aPropWidth, UINT32 *aPropHeight)
427 {
428 switch (aType) {
429 case FilterType::MORPHOLOGY:
430 if (aIndex == ATT_MORPHOLOGY_RADII) {
431 *aPropWidth = D2D1_MORPHOLOGY_PROP_WIDTH;
432 *aPropHeight = D2D1_MORPHOLOGY_PROP_HEIGHT;
433 return true;
434 }
435 break;
436 }
437 return false;
438 }
440 static inline REFCLSID GetCLDIDForFilterType(FilterType aType)
441 {
442 switch (aType) {
443 case FilterType::COLOR_MATRIX:
444 return CLSID_D2D1ColorMatrix;
445 case FilterType::TRANSFORM:
446 return CLSID_D2D12DAffineTransform;
447 case FilterType::BLEND:
448 return CLSID_D2D1Blend;
449 case FilterType::MORPHOLOGY:
450 return CLSID_D2D1Morphology;
451 case FilterType::FLOOD:
452 return CLSID_D2D1Flood;
453 case FilterType::TILE:
454 return CLSID_D2D1Tile;
455 case FilterType::TABLE_TRANSFER:
456 return CLSID_D2D1TableTransfer;
457 case FilterType::LINEAR_TRANSFER:
458 return CLSID_D2D1LinearTransfer;
459 case FilterType::DISCRETE_TRANSFER:
460 return CLSID_D2D1DiscreteTransfer;
461 case FilterType::GAMMA_TRANSFER:
462 return CLSID_D2D1GammaTransfer;
463 case FilterType::DISPLACEMENT_MAP:
464 return CLSID_D2D1DisplacementMap;
465 case FilterType::TURBULENCE:
466 return CLSID_D2D1Turbulence;
467 case FilterType::ARITHMETIC_COMBINE:
468 return CLSID_D2D1ArithmeticComposite;
469 case FilterType::COMPOSITE:
470 return CLSID_D2D1Composite;
471 case FilterType::GAUSSIAN_BLUR:
472 return CLSID_D2D1GaussianBlur;
473 case FilterType::DIRECTIONAL_BLUR:
474 return CLSID_D2D1DirectionalBlur;
475 case FilterType::POINT_DIFFUSE:
476 return CLSID_D2D1PointDiffuse;
477 case FilterType::POINT_SPECULAR:
478 return CLSID_D2D1PointSpecular;
479 case FilterType::SPOT_DIFFUSE:
480 return CLSID_D2D1SpotDiffuse;
481 case FilterType::SPOT_SPECULAR:
482 return CLSID_D2D1SpotSpecular;
483 case FilterType::DISTANT_DIFFUSE:
484 return CLSID_D2D1DistantDiffuse;
485 case FilterType::DISTANT_SPECULAR:
486 return CLSID_D2D1DistantSpecular;
487 case FilterType::CROP:
488 return CLSID_D2D1Crop;
489 case FilterType::PREMULTIPLY:
490 return CLSID_D2D1Premultiply;
491 case FilterType::UNPREMULTIPLY:
492 return CLSID_D2D1UnPremultiply;
493 }
494 return GUID_NULL;
495 }
497 /* static */
498 TemporaryRef<FilterNode>
499 FilterNodeD2D1::Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aType)
500 {
501 if (aType == FilterType::CONVOLVE_MATRIX) {
502 return new FilterNodeConvolveD2D1(aDT, aDC);
503 }
505 RefPtr<ID2D1Effect> effect;
506 HRESULT hr;
508 hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), byRef(effect));
510 if (FAILED(hr)) {
511 gfxWarning() << "Failed to create effect for FilterType: " << hr;
512 return nullptr;
513 }
515 switch (aType) {
516 case FilterType::LINEAR_TRANSFER:
517 case FilterType::GAMMA_TRANSFER:
518 case FilterType::TABLE_TRANSFER:
519 case FilterType::DISCRETE_TRANSFER:
520 return new FilterNodeComponentTransferD2D1(aDT, aDC, effect, aType);
521 default:
522 return new FilterNodeD2D1(aDT, effect, aType);
523 }
524 }
526 void
527 FilterNodeD2D1::InitUnmappedProperties()
528 {
529 switch (mType) {
530 case FilterType::TRANSFORM:
531 mEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE, D2D1_BORDER_MODE_HARD);
532 break;
533 default:
534 break;
535 }
536 }
538 void
539 FilterNodeD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface)
540 {
541 UINT32 input = GetD2D1InputForInput(mType, aIndex);
542 ID2D1Effect* effect = InputEffect();
543 MOZ_ASSERT(input < effect->GetInputCount());
545 if (mType == FilterType::COMPOSITE) {
546 UINT32 inputCount = effect->GetInputCount();
548 if (aIndex == inputCount - 1 && aSurface == nullptr) {
549 effect->SetInputCount(inputCount - 1);
550 } else if (aIndex >= inputCount && aSurface) {
551 effect->SetInputCount(aIndex + 1);
552 }
553 }
555 RefPtr<ID2D1Image> image = GetImageForSourceSurface(mDT, aSurface);
556 effect->SetInput(input, image);
557 }
559 void
560 FilterNodeD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
561 {
562 UINT32 input = GetD2D1InputForInput(mType, aIndex);
563 ID2D1Effect* effect = InputEffect();
565 if (mType == FilterType::COMPOSITE) {
566 UINT32 inputCount = effect->GetInputCount();
568 if (aIndex == inputCount - 1 && aFilter == nullptr) {
569 effect->SetInputCount(inputCount - 1);
570 } else if (aIndex >= inputCount && aFilter) {
571 effect->SetInputCount(aIndex + 1);
572 }
573 }
575 MOZ_ASSERT(input < effect->GetInputCount());
577 if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
578 gfxWarning() << "Unknown input SourceSurface set on effect.";
579 MOZ_ASSERT(0);
580 return;
581 }
583 effect->SetInputEffect(input, static_cast<FilterNodeD2D1*>(aFilter)->OutputEffect());
584 }
586 void
587 FilterNodeD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue)
588 {
589 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
590 MOZ_ASSERT(input < mEffect->GetPropertyCount());
592 if (mType == FilterType::TURBULENCE && aIndex == ATT_TURBULENCE_BASE_FREQUENCY) {
593 mEffect->SetValue(input, D2D1::Vector2F(FLOAT(aValue), FLOAT(aValue)));
594 return;
595 } else if (mType == FilterType::DIRECTIONAL_BLUR && aIndex == ATT_DIRECTIONAL_BLUR_DIRECTION) {
596 mEffect->SetValue(input, aValue == BLUR_DIRECTION_X ? 0 : 90.0f);
597 return;
598 }
600 mEffect->SetValue(input, ConvertValue(mType, aIndex, aValue));
601 }
603 void
604 FilterNodeD2D1::SetAttribute(uint32_t aIndex, Float aValue)
605 {
606 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
607 MOZ_ASSERT(input < mEffect->GetPropertyCount());
609 mEffect->SetValue(input, aValue);
610 }
612 void
613 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point &aValue)
614 {
615 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
616 MOZ_ASSERT(input < mEffect->GetPropertyCount());
618 mEffect->SetValue(input, D2DPoint(aValue));
619 }
621 void
622 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix5x4 &aValue)
623 {
624 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
625 MOZ_ASSERT(input < mEffect->GetPropertyCount());
627 mEffect->SetValue(input, D2DMatrix5x4(aValue));
628 }
630 void
631 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point3D &aValue)
632 {
633 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
634 MOZ_ASSERT(input < mEffect->GetPropertyCount());
636 mEffect->SetValue(input, D2DVector3D(aValue));
637 }
639 void
640 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Size &aValue)
641 {
642 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
643 MOZ_ASSERT(input < mEffect->GetPropertyCount());
645 mEffect->SetValue(input, D2D1::Vector2F(aValue.width, aValue.height));
646 }
648 void
649 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue)
650 {
651 UINT32 widthProp, heightProp;
653 if (!GetD2D1PropsForIntSize(mType, aIndex, &widthProp, &heightProp)) {
654 return;
655 }
657 IntSize value = aValue;
658 ConvertValue(mType, aIndex, value);
660 mEffect->SetValue(widthProp, (UINT)value.width);
661 mEffect->SetValue(heightProp, (UINT)value.height);
662 }
664 void
665 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Color &aValue)
666 {
667 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
668 MOZ_ASSERT(input < mEffect->GetPropertyCount());
670 switch (mType) {
671 case FilterType::POINT_DIFFUSE:
672 case FilterType::SPOT_DIFFUSE:
673 case FilterType::DISTANT_DIFFUSE:
674 case FilterType::POINT_SPECULAR:
675 case FilterType::SPOT_SPECULAR:
676 case FilterType::DISTANT_SPECULAR:
677 mEffect->SetValue(input, D2D1::Vector3F(aValue.r, aValue.g, aValue.b));
678 break;
679 default:
680 mEffect->SetValue(input, D2D1::Vector4F(aValue.r * aValue.a, aValue.g * aValue.a, aValue.b * aValue.a, aValue.a));
681 }
682 }
684 void
685 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Rect &aValue)
686 {
687 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
688 MOZ_ASSERT(input < mEffect->GetPropertyCount());
690 mEffect->SetValue(input, D2DRect(aValue));
691 }
693 void
694 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue)
695 {
696 if (mType == FilterType::TURBULENCE) {
697 MOZ_ASSERT(aIndex == ATT_TURBULENCE_RECT);
699 mEffect->SetValue(D2D1_TURBULENCE_PROP_OFFSET, D2D1::Vector2F(Float(aValue.x), Float(aValue.y)));
700 mEffect->SetValue(D2D1_TURBULENCE_PROP_SIZE, D2D1::Vector2F(Float(aValue.width), Float(aValue.height)));
701 return;
702 }
704 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
705 MOZ_ASSERT(input < mEffect->GetPropertyCount());
707 mEffect->SetValue(input, D2D1::RectF(Float(aValue.x), Float(aValue.y),
708 Float(aValue.XMost()), Float(aValue.YMost())));
709 }
711 void
712 FilterNodeD2D1::SetAttribute(uint32_t aIndex, bool aValue)
713 {
714 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
715 MOZ_ASSERT(input < mEffect->GetPropertyCount());
717 mEffect->SetValue(input, (BOOL)aValue);
718 }
720 void
721 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Float *aValues, uint32_t aSize)
722 {
723 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
724 MOZ_ASSERT(input < mEffect->GetPropertyCount());
726 mEffect->SetValue(input, (BYTE*)aValues, sizeof(Float) * aSize);
727 }
729 void
730 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue)
731 {
732 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
733 MOZ_ASSERT(input < mEffect->GetPropertyCount());
735 mEffect->SetValue(input, D2DPoint(aValue));
736 }
738 void
739 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix)
740 {
741 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
742 MOZ_ASSERT(input < mEffect->GetPropertyCount());
744 mEffect->SetValue(input, D2DMatrix(aMatrix));
745 }
747 FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC)
748 : FilterNodeD2D1(aDT, nullptr, FilterType::CONVOLVE_MATRIX)
749 , mEdgeMode(EDGE_MODE_DUPLICATE)
750 {
751 // Correctly handling the interaction of edge mode and source rect is a bit
752 // tricky with D2D1 effects. We want the edge mode to only apply outside of
753 // the source rect (as specified by the ATT_CONVOLVE_MATRIX_SOURCE_RECT
754 // attribute). So if our input surface or filter is smaller than the source
755 // rect, we need to add transparency around it until we reach the edges of
756 // the source rect, and only then do any repeating or edge duplicating.
757 // Unfortunately, D2D1 does not have any "extend with transparency" effect.
758 // (The crop effect can only cut off parts, it can't make the output rect
759 // bigger.) And the border effect does not have a source rect attribute -
760 // it only looks at the output rect of its input filter or surface.
761 // So we use the following trick to extend the input size to the source rect:
762 // Instead of feeding the input directly into the border effect, we first
763 // composite it with a transparent flood effect (which is infinite-sized) and
764 // use a crop effect on the result in order to get the right size. Then we
765 // feed the cropped composition into the border effect, which then finally
766 // feeds into the convolve matrix effect.
767 // All of this is only necessary when our edge mode is not EDGE_MODE_NONE, so
768 // we update the filter chain dynamically in UpdateChain().
770 HRESULT hr;
772 hr = aDC->CreateEffect(CLSID_D2D1ConvolveMatrix, byRef(mEffect));
774 if (FAILED(hr)) {
775 gfxWarning() << "Failed to create ConvolveMatrix filter!";
776 return;
777 }
779 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE, D2D1_BORDER_MODE_SOFT);
781 hr = aDC->CreateEffect(CLSID_D2D1Flood, byRef(mFloodEffect));
783 if (FAILED(hr)) {
784 gfxWarning() << "Failed to create ConvolveMatrix filter!";
785 return;
786 }
788 mFloodEffect->SetValue(D2D1_FLOOD_PROP_COLOR, D2D1::Vector4F(0.0f, 0.0f, 0.0f, 0.0f));
790 hr = aDC->CreateEffect(CLSID_D2D1Composite, byRef(mCompositeEffect));
792 if (FAILED(hr)) {
793 gfxWarning() << "Failed to create ConvolveMatrix filter!";
794 return;
795 }
797 mCompositeEffect->SetInputEffect(1, mFloodEffect.get());
799 hr = aDC->CreateEffect(CLSID_D2D1Crop, byRef(mCropEffect));
801 if (FAILED(hr)) {
802 gfxWarning() << "Failed to create ConvolveMatrix filter!";
803 return;
804 }
806 mCropEffect->SetInputEffect(0, mCompositeEffect.get());
808 hr = aDC->CreateEffect(CLSID_D2D1Border, byRef(mBorderEffect));
810 if (FAILED(hr)) {
811 gfxWarning() << "Failed to create ConvolveMatrix filter!";
812 return;
813 }
815 mBorderEffect->SetInputEffect(0, mCropEffect.get());
817 UpdateChain();
818 UpdateSourceRect();
819 }
821 void
822 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface)
823 {
824 MOZ_ASSERT(aIndex == 0);
826 mInput = GetImageForSourceSurface(mDT, aSurface);
828 mInputEffect = nullptr;
830 UpdateChain();
831 }
833 void
834 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
835 {
836 MOZ_ASSERT(aIndex == 0);
838 if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
839 gfxWarning() << "Unknown input SourceSurface set on effect.";
840 MOZ_ASSERT(0);
841 return;
842 }
844 mInput = nullptr;
845 mInputEffect = static_cast<FilterNodeD2D1*>(aFilter)->mEffect;
847 UpdateChain();
848 }
850 void
851 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue)
852 {
853 if (aIndex != ATT_CONVOLVE_MATRIX_EDGE_MODE) {
854 return FilterNodeD2D1::SetAttribute(aIndex, aValue);
855 }
857 mEdgeMode = (ConvolveMatrixEdgeMode)aValue;
859 UpdateChain();
860 }
862 void
863 FilterNodeConvolveD2D1::UpdateChain()
864 {
865 // The shape of the filter graph:
866 //
867 // EDGE_MODE_NONE:
868 // input --> convolvematrix
869 //
870 // EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP:
871 // input -------v
872 // flood --> composite --> crop --> border --> convolvematrix
874 ID2D1Effect *firstEffect = mCompositeEffect;
875 if (mEdgeMode == EDGE_MODE_NONE) {
876 firstEffect = mEffect;
877 } else {
878 mEffect->SetInputEffect(0, mBorderEffect.get());
879 }
881 if (mInputEffect) {
882 firstEffect->SetInputEffect(0, mInputEffect);
883 } else {
884 firstEffect->SetInput(0, mInput);
885 }
887 if (mEdgeMode == EDGE_MODE_DUPLICATE) {
888 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_CLAMP);
889 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_CLAMP);
890 } else if (mEdgeMode == EDGE_MODE_WRAP) {
891 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_WRAP);
892 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_WRAP);
893 }
894 }
896 void
897 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue)
898 {
899 if (aIndex != ATT_CONVOLVE_MATRIX_KERNEL_SIZE) {
900 MOZ_ASSERT(false);
901 return;
902 }
904 mKernelSize = aValue;
906 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X, aValue.width);
907 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y, aValue.height);
909 UpdateOffset();
910 }
912 void
913 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue)
914 {
915 if (aIndex != ATT_CONVOLVE_MATRIX_TARGET) {
916 MOZ_ASSERT(false);
917 return;
918 }
920 mTarget = aValue;
922 UpdateOffset();
923 }
925 void
926 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue)
927 {
928 if (aIndex != ATT_CONVOLVE_MATRIX_SOURCE_RECT) {
929 MOZ_ASSERT(false);
930 return;
931 }
933 mSourceRect = aValue;
935 UpdateSourceRect();
936 }
938 void
939 FilterNodeConvolveD2D1::UpdateOffset()
940 {
941 D2D1_VECTOR_2F vector =
942 D2D1::Vector2F((Float(mKernelSize.width) - 1.0f) / 2.0f - Float(mTarget.x),
943 (Float(mKernelSize.height) - 1.0f) / 2.0f - Float(mTarget.y));
945 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET, vector);
946 }
948 void
949 FilterNodeConvolveD2D1::UpdateSourceRect()
950 {
951 mCropEffect->SetValue(D2D1_CROP_PROP_RECT,
952 D2D1::RectF(Float(mSourceRect.x), Float(mSourceRect.y),
953 Float(mSourceRect.XMost()), Float(mSourceRect.YMost())));
954 }
956 FilterNodeComponentTransferD2D1::FilterNodeComponentTransferD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC,
957 ID2D1Effect *aEffect, FilterType aType)
958 : FilterNodeD2D1(aDT, aEffect, aType)
959 {
960 // D2D1 component transfer effects do strange things when it comes to
961 // premultiplication.
962 // For our purposes we only need the transfer filters to apply straight to
963 // unpremultiplied source channels and output unpremultiplied results.
964 // However, the D2D1 effects are designed differently: They can apply to both
965 // premultiplied and unpremultiplied inputs, and they always premultiply
966 // their result - at least in those color channels that have not been
967 // disabled.
968 // In order to determine whether the input needs to be unpremultiplied as
969 // part of the transfer, the effect consults the alpha mode metadata of the
970 // input surface or the input effect. We don't have such a concept in Moz2D,
971 // and giving Moz2D users different results based on something that cannot be
972 // influenced through Moz2D APIs seems like a bad idea.
973 // We solve this by applying a premultiply effect to the input before feeding
974 // it into the transfer effect. The premultiply effect always premultiplies
975 // regardless of any alpha mode metadata on inputs, and it always marks its
976 // output as premultiplied so that the transfer effect will unpremultiply
977 // consistently. Feeding always-premultiplied input into the transfer effect
978 // also avoids another problem that would appear when individual color
979 // channels disable the transfer: In that case, the disabled channels would
980 // pass through unchanged in their unpremultiplied form and the other
981 // channels would be premultiplied, giving a mixed result.
982 // But since we now ensure that the input is premultiplied, disabled channels
983 // will pass premultiplied values through to the result, which is consistent
984 // with the enabled channels.
985 // We also add an unpremultiply effect that postprocesses the result of the
986 // transfer effect because getting unpremultiplied results from the transfer
987 // filters is part of the FilterNode API.
988 HRESULT hr;
990 hr = aDC->CreateEffect(CLSID_D2D1Premultiply, byRef(mPrePremultiplyEffect));
992 if (FAILED(hr)) {
993 gfxWarning() << "Failed to create ComponentTransfer filter!";
994 return;
995 }
997 hr = aDC->CreateEffect(CLSID_D2D1UnPremultiply, byRef(mPostUnpremultiplyEffect));
999 if (FAILED(hr)) {
1000 gfxWarning() << "Failed to create ComponentTransfer filter!";
1001 return;
1002 }
1004 mEffect->SetInputEffect(0, mPrePremultiplyEffect.get());
1005 mPostUnpremultiplyEffect->SetInputEffect(0, mEffect.get());
1006 }
1008 }
1009 }