Bumping manifests a=b2g-bump
[gecko.git] / gfx / 2d / FilterNodeD2D1.cpp
blob2b1f0d3165dbdb4e54510a3bf3335f7e1d83d3e5
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)
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!");
30 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED;
33 D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE D2DAffineTransformInterpolationMode(Filter aFilter)
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!");
46 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR;
49 D2D1_BLEND_MODE D2DBlendMode(uint32_t aMode)
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!");
64 return D2D1_BLEND_MODE_DARKEN;
67 D2D1_MORPHOLOGY_MODE D2DMorphologyMode(uint32_t aMode)
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;
76 MOZ_CRASH("Unknown enum value!");
77 return D2D1_MORPHOLOGY_MODE_DILATE;
80 D2D1_TURBULENCE_NOISE D2DTurbulenceNoise(uint32_t aMode)
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;
89 MOZ_CRASH("Unknown enum value!");
90 return D2D1_TURBULENCE_NOISE_TURBULENCE;
93 D2D1_COMPOSITE_MODE D2DFilterCompositionMode(uint32_t aMode)
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;
108 MOZ_CRASH("Unknown enum value!");
109 return D2D1_COMPOSITE_MODE_SOURCE_OVER;
112 D2D1_CHANNEL_SELECTOR D2DChannelSelector(uint32_t aMode)
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;
125 MOZ_CRASH("Unknown enum value!");
126 return D2D1_CHANNEL_SELECTOR_R;
129 TemporaryRef<ID2D1Image> GetImageForSourceSurface(DrawTarget *aDT, SourceSurface *aSurface)
131 if (aDT->IsTiledDrawTarget() || aDT->IsDualDrawTarget()) {
132 MOZ_CRASH("Incompatible draw target type!");
133 return nullptr;
135 switch (aDT->GetBackendType()) {
136 case BackendType::DIRECT2D1_1:
137 return static_cast<DrawTargetD2D1*>(aDT)->GetImageForSurface(aSurface, ExtendMode::CLAMP);
138 case BackendType::DIRECT2D:
139 return static_cast<DrawTargetD2D*>(aDT)->GetImageForSurface(aSurface);
140 default:
141 MOZ_CRASH("Unknown draw target type!");
142 return nullptr;
146 uint32_t ConvertValue(FilterType aType, uint32_t aAttribute, uint32_t aValue)
148 switch (aType) {
149 case FilterType::COLOR_MATRIX:
150 if (aAttribute == ATT_COLOR_MATRIX_ALPHA_MODE) {
151 aValue = D2DAlphaMode(aValue);
153 break;
154 case FilterType::TRANSFORM:
155 if (aAttribute == ATT_TRANSFORM_FILTER) {
156 aValue = D2DAffineTransformInterpolationMode(Filter(aValue));
158 break;
159 case FilterType::BLEND:
160 if (aAttribute == ATT_BLEND_BLENDMODE) {
161 aValue = D2DBlendMode(aValue);
163 break;
164 case FilterType::MORPHOLOGY:
165 if (aAttribute == ATT_MORPHOLOGY_OPERATOR) {
166 aValue = D2DMorphologyMode(aValue);
168 break;
169 case FilterType::DISPLACEMENT_MAP:
170 if (aAttribute == ATT_DISPLACEMENT_MAP_X_CHANNEL ||
171 aAttribute == ATT_DISPLACEMENT_MAP_Y_CHANNEL) {
172 aValue = D2DChannelSelector(aValue);
174 break;
175 case FilterType::TURBULENCE:
176 if (aAttribute == ATT_TURBULENCE_TYPE) {
177 aValue = D2DTurbulenceNoise(aValue);
179 break;
180 case FilterType::COMPOSITE:
181 if (aAttribute == ATT_COMPOSITE_OPERATOR) {
182 aValue = D2DFilterCompositionMode(aValue);
184 break;
187 return aValue;
190 void ConvertValue(FilterType aType, uint32_t aAttribute, IntSize &aValue)
192 switch (aType) {
193 case FilterType::MORPHOLOGY:
194 if (aAttribute == ATT_MORPHOLOGY_RADII) {
195 aValue.width *= 2;
196 aValue.width += 1;
197 aValue.height *= 2;
198 aValue.height += 1;
200 break;
204 UINT32
205 GetD2D1InputForInput(FilterType aType, uint32_t aIndex)
207 return aIndex;
210 #define CONVERT_PROP(moz2dname, d2dname) \
211 case ATT_##moz2dname: \
212 return D2D1_##d2dname
214 UINT32
215 GetD2D1PropForAttribute(FilterType aType, uint32_t aIndex)
217 switch (aType) {
218 case FilterType::COLOR_MATRIX:
219 switch (aIndex) {
220 CONVERT_PROP(COLOR_MATRIX_MATRIX, COLORMATRIX_PROP_COLOR_MATRIX);
221 CONVERT_PROP(COLOR_MATRIX_ALPHA_MODE, COLORMATRIX_PROP_ALPHA_MODE);
223 break;
224 case FilterType::TRANSFORM:
225 switch (aIndex) {
226 CONVERT_PROP(TRANSFORM_MATRIX, 2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX);
227 CONVERT_PROP(TRANSFORM_FILTER, 2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE);
229 case FilterType::BLEND:
230 switch (aIndex) {
231 CONVERT_PROP(BLEND_BLENDMODE, BLEND_PROP_MODE);
233 break;
234 case FilterType::MORPHOLOGY:
235 switch (aIndex) {
236 CONVERT_PROP(MORPHOLOGY_OPERATOR, MORPHOLOGY_PROP_MODE);
238 break;
239 case FilterType::FLOOD:
240 switch (aIndex) {
241 CONVERT_PROP(FLOOD_COLOR, FLOOD_PROP_COLOR);
243 break;
244 case FilterType::TILE:
245 switch (aIndex) {
246 CONVERT_PROP(TILE_SOURCE_RECT, TILE_PROP_RECT);
248 break;
249 case FilterType::TABLE_TRANSFER:
250 switch (aIndex) {
251 CONVERT_PROP(TABLE_TRANSFER_DISABLE_R, TABLETRANSFER_PROP_RED_DISABLE);
252 CONVERT_PROP(TABLE_TRANSFER_DISABLE_G, TABLETRANSFER_PROP_GREEN_DISABLE);
253 CONVERT_PROP(TABLE_TRANSFER_DISABLE_B, TABLETRANSFER_PROP_BLUE_DISABLE);
254 CONVERT_PROP(TABLE_TRANSFER_DISABLE_A, TABLETRANSFER_PROP_ALPHA_DISABLE);
255 CONVERT_PROP(TABLE_TRANSFER_TABLE_R, TABLETRANSFER_PROP_RED_TABLE);
256 CONVERT_PROP(TABLE_TRANSFER_TABLE_G, TABLETRANSFER_PROP_GREEN_TABLE);
257 CONVERT_PROP(TABLE_TRANSFER_TABLE_B, TABLETRANSFER_PROP_BLUE_TABLE);
258 CONVERT_PROP(TABLE_TRANSFER_TABLE_A, TABLETRANSFER_PROP_ALPHA_TABLE);
260 break;
261 case FilterType::DISCRETE_TRANSFER:
262 switch (aIndex) {
263 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_R, DISCRETETRANSFER_PROP_RED_DISABLE);
264 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_G, DISCRETETRANSFER_PROP_GREEN_DISABLE);
265 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_B, DISCRETETRANSFER_PROP_BLUE_DISABLE);
266 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_A, DISCRETETRANSFER_PROP_ALPHA_DISABLE);
267 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_R, DISCRETETRANSFER_PROP_RED_TABLE);
268 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_G, DISCRETETRANSFER_PROP_GREEN_TABLE);
269 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_B, DISCRETETRANSFER_PROP_BLUE_TABLE);
270 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_A, DISCRETETRANSFER_PROP_ALPHA_TABLE);
272 break;
273 case FilterType::LINEAR_TRANSFER:
274 switch (aIndex) {
275 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_R, LINEARTRANSFER_PROP_RED_DISABLE);
276 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_G, LINEARTRANSFER_PROP_GREEN_DISABLE);
277 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_B, LINEARTRANSFER_PROP_BLUE_DISABLE);
278 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_A, LINEARTRANSFER_PROP_ALPHA_DISABLE);
279 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_R, LINEARTRANSFER_PROP_RED_Y_INTERCEPT);
280 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_G, LINEARTRANSFER_PROP_GREEN_Y_INTERCEPT);
281 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_B, LINEARTRANSFER_PROP_BLUE_Y_INTERCEPT);
282 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_A, LINEARTRANSFER_PROP_ALPHA_Y_INTERCEPT);
283 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_R, LINEARTRANSFER_PROP_RED_SLOPE);
284 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_G, LINEARTRANSFER_PROP_GREEN_SLOPE);
285 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_B, LINEARTRANSFER_PROP_BLUE_SLOPE);
286 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_A, LINEARTRANSFER_PROP_ALPHA_SLOPE);
288 break;
289 case FilterType::GAMMA_TRANSFER:
290 switch (aIndex) {
291 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_R, GAMMATRANSFER_PROP_RED_DISABLE);
292 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_G, GAMMATRANSFER_PROP_GREEN_DISABLE);
293 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_B, GAMMATRANSFER_PROP_BLUE_DISABLE);
294 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_A, GAMMATRANSFER_PROP_ALPHA_DISABLE);
295 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_R, GAMMATRANSFER_PROP_RED_AMPLITUDE);
296 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_G, GAMMATRANSFER_PROP_GREEN_AMPLITUDE);
297 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_B, GAMMATRANSFER_PROP_BLUE_AMPLITUDE);
298 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_A, GAMMATRANSFER_PROP_ALPHA_AMPLITUDE);
299 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_R, GAMMATRANSFER_PROP_RED_EXPONENT);
300 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_G, GAMMATRANSFER_PROP_GREEN_EXPONENT);
301 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_B, GAMMATRANSFER_PROP_BLUE_EXPONENT);
302 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_A, GAMMATRANSFER_PROP_ALPHA_EXPONENT);
303 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_R, GAMMATRANSFER_PROP_RED_OFFSET);
304 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_G, GAMMATRANSFER_PROP_GREEN_OFFSET);
305 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_B, GAMMATRANSFER_PROP_BLUE_OFFSET);
306 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_A, GAMMATRANSFER_PROP_ALPHA_OFFSET);
308 break;
309 case FilterType::CONVOLVE_MATRIX:
310 switch (aIndex) {
311 CONVERT_PROP(CONVOLVE_MATRIX_BIAS, CONVOLVEMATRIX_PROP_BIAS);
312 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_MATRIX, CONVOLVEMATRIX_PROP_KERNEL_MATRIX);
313 CONVERT_PROP(CONVOLVE_MATRIX_DIVISOR, CONVOLVEMATRIX_PROP_DIVISOR);
314 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, CONVOLVEMATRIX_PROP_KERNEL_UNIT_LENGTH);
315 CONVERT_PROP(CONVOLVE_MATRIX_PRESERVE_ALPHA, CONVOLVEMATRIX_PROP_PRESERVE_ALPHA);
317 case FilterType::DISPLACEMENT_MAP:
318 switch (aIndex) {
319 CONVERT_PROP(DISPLACEMENT_MAP_SCALE, DISPLACEMENTMAP_PROP_SCALE);
320 CONVERT_PROP(DISPLACEMENT_MAP_X_CHANNEL, DISPLACEMENTMAP_PROP_X_CHANNEL_SELECT);
321 CONVERT_PROP(DISPLACEMENT_MAP_Y_CHANNEL, DISPLACEMENTMAP_PROP_Y_CHANNEL_SELECT);
323 break;
324 case FilterType::TURBULENCE:
325 switch (aIndex) {
326 CONVERT_PROP(TURBULENCE_BASE_FREQUENCY, TURBULENCE_PROP_BASE_FREQUENCY);
327 CONVERT_PROP(TURBULENCE_NUM_OCTAVES, TURBULENCE_PROP_NUM_OCTAVES);
328 CONVERT_PROP(TURBULENCE_SEED, TURBULENCE_PROP_SEED);
329 CONVERT_PROP(TURBULENCE_STITCHABLE, TURBULENCE_PROP_STITCHABLE);
330 CONVERT_PROP(TURBULENCE_TYPE, TURBULENCE_PROP_NOISE);
332 break;
333 case FilterType::ARITHMETIC_COMBINE:
334 switch (aIndex) {
335 CONVERT_PROP(ARITHMETIC_COMBINE_COEFFICIENTS, ARITHMETICCOMPOSITE_PROP_COEFFICIENTS);
337 break;
338 case FilterType::COMPOSITE:
339 switch (aIndex) {
340 CONVERT_PROP(COMPOSITE_OPERATOR, COMPOSITE_PROP_MODE);
342 break;
343 case FilterType::GAUSSIAN_BLUR:
344 switch (aIndex) {
345 CONVERT_PROP(GAUSSIAN_BLUR_STD_DEVIATION, GAUSSIANBLUR_PROP_STANDARD_DEVIATION);
347 break;
348 case FilterType::DIRECTIONAL_BLUR:
349 switch (aIndex) {
350 CONVERT_PROP(DIRECTIONAL_BLUR_STD_DEVIATION, DIRECTIONALBLUR_PROP_STANDARD_DEVIATION);
351 CONVERT_PROP(DIRECTIONAL_BLUR_DIRECTION, DIRECTIONALBLUR_PROP_ANGLE);
353 break;
354 case FilterType::POINT_DIFFUSE:
355 switch (aIndex) {
356 CONVERT_PROP(POINT_DIFFUSE_DIFFUSE_CONSTANT, POINTDIFFUSE_PROP_DIFFUSE_CONSTANT);
357 CONVERT_PROP(POINT_DIFFUSE_POSITION, POINTDIFFUSE_PROP_LIGHT_POSITION);
358 CONVERT_PROP(POINT_DIFFUSE_COLOR, POINTDIFFUSE_PROP_COLOR);
359 CONVERT_PROP(POINT_DIFFUSE_SURFACE_SCALE, POINTDIFFUSE_PROP_SURFACE_SCALE);
360 CONVERT_PROP(POINT_DIFFUSE_KERNEL_UNIT_LENGTH, POINTDIFFUSE_PROP_KERNEL_UNIT_LENGTH);
362 break;
363 case FilterType::SPOT_DIFFUSE:
364 switch (aIndex) {
365 CONVERT_PROP(SPOT_DIFFUSE_DIFFUSE_CONSTANT, SPOTDIFFUSE_PROP_DIFFUSE_CONSTANT);
366 CONVERT_PROP(SPOT_DIFFUSE_POINTS_AT, SPOTDIFFUSE_PROP_POINTS_AT);
367 CONVERT_PROP(SPOT_DIFFUSE_FOCUS, SPOTDIFFUSE_PROP_FOCUS);
368 CONVERT_PROP(SPOT_DIFFUSE_LIMITING_CONE_ANGLE, SPOTDIFFUSE_PROP_LIMITING_CONE_ANGLE);
369 CONVERT_PROP(SPOT_DIFFUSE_POSITION, SPOTDIFFUSE_PROP_LIGHT_POSITION);
370 CONVERT_PROP(SPOT_DIFFUSE_COLOR, SPOTDIFFUSE_PROP_COLOR);
371 CONVERT_PROP(SPOT_DIFFUSE_SURFACE_SCALE, SPOTDIFFUSE_PROP_SURFACE_SCALE);
372 CONVERT_PROP(SPOT_DIFFUSE_KERNEL_UNIT_LENGTH, SPOTDIFFUSE_PROP_KERNEL_UNIT_LENGTH);
374 break;
375 case FilterType::DISTANT_DIFFUSE:
376 switch (aIndex) {
377 CONVERT_PROP(DISTANT_DIFFUSE_DIFFUSE_CONSTANT, DISTANTDIFFUSE_PROP_DIFFUSE_CONSTANT);
378 CONVERT_PROP(DISTANT_DIFFUSE_AZIMUTH, DISTANTDIFFUSE_PROP_AZIMUTH);
379 CONVERT_PROP(DISTANT_DIFFUSE_ELEVATION, DISTANTDIFFUSE_PROP_ELEVATION);
380 CONVERT_PROP(DISTANT_DIFFUSE_COLOR, DISTANTDIFFUSE_PROP_COLOR);
381 CONVERT_PROP(DISTANT_DIFFUSE_SURFACE_SCALE, DISTANTDIFFUSE_PROP_SURFACE_SCALE);
382 CONVERT_PROP(DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH, DISTANTDIFFUSE_PROP_KERNEL_UNIT_LENGTH);
384 break;
385 case FilterType::POINT_SPECULAR:
386 switch (aIndex) {
387 CONVERT_PROP(POINT_SPECULAR_SPECULAR_CONSTANT, POINTSPECULAR_PROP_SPECULAR_CONSTANT);
388 CONVERT_PROP(POINT_SPECULAR_SPECULAR_EXPONENT, POINTSPECULAR_PROP_SPECULAR_EXPONENT);
389 CONVERT_PROP(POINT_SPECULAR_POSITION, POINTSPECULAR_PROP_LIGHT_POSITION);
390 CONVERT_PROP(POINT_SPECULAR_COLOR, POINTSPECULAR_PROP_COLOR);
391 CONVERT_PROP(POINT_SPECULAR_SURFACE_SCALE, POINTSPECULAR_PROP_SURFACE_SCALE);
392 CONVERT_PROP(POINT_SPECULAR_KERNEL_UNIT_LENGTH, POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH);
394 break;
395 case FilterType::SPOT_SPECULAR:
396 switch (aIndex) {
397 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_CONSTANT, SPOTSPECULAR_PROP_SPECULAR_CONSTANT);
398 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_EXPONENT, SPOTSPECULAR_PROP_SPECULAR_EXPONENT);
399 CONVERT_PROP(SPOT_SPECULAR_POINTS_AT, SPOTSPECULAR_PROP_POINTS_AT);
400 CONVERT_PROP(SPOT_SPECULAR_FOCUS, SPOTSPECULAR_PROP_FOCUS);
401 CONVERT_PROP(SPOT_SPECULAR_LIMITING_CONE_ANGLE, SPOTSPECULAR_PROP_LIMITING_CONE_ANGLE);
402 CONVERT_PROP(SPOT_SPECULAR_POSITION, SPOTSPECULAR_PROP_LIGHT_POSITION);
403 CONVERT_PROP(SPOT_SPECULAR_COLOR, SPOTSPECULAR_PROP_COLOR);
404 CONVERT_PROP(SPOT_SPECULAR_SURFACE_SCALE, SPOTSPECULAR_PROP_SURFACE_SCALE);
405 CONVERT_PROP(SPOT_SPECULAR_KERNEL_UNIT_LENGTH, SPOTSPECULAR_PROP_KERNEL_UNIT_LENGTH);
407 break;
408 case FilterType::DISTANT_SPECULAR:
409 switch (aIndex) {
410 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_CONSTANT, DISTANTSPECULAR_PROP_SPECULAR_CONSTANT);
411 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_EXPONENT, DISTANTSPECULAR_PROP_SPECULAR_EXPONENT);
412 CONVERT_PROP(DISTANT_SPECULAR_AZIMUTH, DISTANTSPECULAR_PROP_AZIMUTH);
413 CONVERT_PROP(DISTANT_SPECULAR_ELEVATION, DISTANTSPECULAR_PROP_ELEVATION);
414 CONVERT_PROP(DISTANT_SPECULAR_COLOR, DISTANTSPECULAR_PROP_COLOR);
415 CONVERT_PROP(DISTANT_SPECULAR_SURFACE_SCALE, DISTANTSPECULAR_PROP_SURFACE_SCALE);
416 CONVERT_PROP(DISTANT_SPECULAR_KERNEL_UNIT_LENGTH, DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH);
418 break;
419 case FilterType::CROP:
420 switch (aIndex) {
421 CONVERT_PROP(CROP_RECT, CROP_PROP_RECT);
423 break;
426 return UINT32_MAX;
429 bool
430 GetD2D1PropsForIntSize(FilterType aType, uint32_t aIndex, UINT32 *aPropWidth, UINT32 *aPropHeight)
432 switch (aType) {
433 case FilterType::MORPHOLOGY:
434 if (aIndex == ATT_MORPHOLOGY_RADII) {
435 *aPropWidth = D2D1_MORPHOLOGY_PROP_WIDTH;
436 *aPropHeight = D2D1_MORPHOLOGY_PROP_HEIGHT;
437 return true;
439 break;
441 return false;
444 static inline REFCLSID GetCLDIDForFilterType(FilterType aType)
446 switch (aType) {
447 case FilterType::COLOR_MATRIX:
448 return CLSID_D2D1ColorMatrix;
449 case FilterType::TRANSFORM:
450 return CLSID_D2D12DAffineTransform;
451 case FilterType::BLEND:
452 return CLSID_D2D1Blend;
453 case FilterType::MORPHOLOGY:
454 return CLSID_D2D1Morphology;
455 case FilterType::FLOOD:
456 return CLSID_D2D1Flood;
457 case FilterType::TILE:
458 return CLSID_D2D1Tile;
459 case FilterType::TABLE_TRANSFER:
460 return CLSID_D2D1TableTransfer;
461 case FilterType::LINEAR_TRANSFER:
462 return CLSID_D2D1LinearTransfer;
463 case FilterType::DISCRETE_TRANSFER:
464 return CLSID_D2D1DiscreteTransfer;
465 case FilterType::GAMMA_TRANSFER:
466 return CLSID_D2D1GammaTransfer;
467 case FilterType::DISPLACEMENT_MAP:
468 return CLSID_D2D1DisplacementMap;
469 case FilterType::TURBULENCE:
470 return CLSID_D2D1Turbulence;
471 case FilterType::ARITHMETIC_COMBINE:
472 return CLSID_D2D1ArithmeticComposite;
473 case FilterType::COMPOSITE:
474 return CLSID_D2D1Composite;
475 case FilterType::GAUSSIAN_BLUR:
476 return CLSID_D2D1GaussianBlur;
477 case FilterType::DIRECTIONAL_BLUR:
478 return CLSID_D2D1DirectionalBlur;
479 case FilterType::POINT_DIFFUSE:
480 return CLSID_D2D1PointDiffuse;
481 case FilterType::POINT_SPECULAR:
482 return CLSID_D2D1PointSpecular;
483 case FilterType::SPOT_DIFFUSE:
484 return CLSID_D2D1SpotDiffuse;
485 case FilterType::SPOT_SPECULAR:
486 return CLSID_D2D1SpotSpecular;
487 case FilterType::DISTANT_DIFFUSE:
488 return CLSID_D2D1DistantDiffuse;
489 case FilterType::DISTANT_SPECULAR:
490 return CLSID_D2D1DistantSpecular;
491 case FilterType::CROP:
492 return CLSID_D2D1Crop;
493 case FilterType::PREMULTIPLY:
494 return CLSID_D2D1Premultiply;
495 case FilterType::UNPREMULTIPLY:
496 return CLSID_D2D1UnPremultiply;
498 return GUID_NULL;
501 /* static */
502 TemporaryRef<FilterNode>
503 FilterNodeD2D1::Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aType)
505 if (aType == FilterType::CONVOLVE_MATRIX) {
506 return new FilterNodeConvolveD2D1(aDT, aDC);
509 RefPtr<ID2D1Effect> effect;
510 HRESULT hr;
512 hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), byRef(effect));
514 if (FAILED(hr)) {
515 gfxWarning() << "Failed to create effect for FilterType: " << hr;
516 return nullptr;
519 switch (aType) {
520 case FilterType::LINEAR_TRANSFER:
521 case FilterType::GAMMA_TRANSFER:
522 case FilterType::TABLE_TRANSFER:
523 case FilterType::DISCRETE_TRANSFER:
524 return new FilterNodeComponentTransferD2D1(aDT, aDC, effect, aType);
525 default:
526 return new FilterNodeD2D1(aDT, effect, aType);
530 void
531 FilterNodeD2D1::InitUnmappedProperties()
533 switch (mType) {
534 case FilterType::TRANSFORM:
535 mEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE, D2D1_BORDER_MODE_HARD);
536 break;
537 default:
538 break;
542 void
543 FilterNodeD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface)
545 UINT32 input = GetD2D1InputForInput(mType, aIndex);
546 ID2D1Effect* effect = InputEffect();
547 MOZ_ASSERT(input < effect->GetInputCount());
549 if (mType == FilterType::COMPOSITE) {
550 UINT32 inputCount = effect->GetInputCount();
552 if (aIndex == inputCount - 1 && aSurface == nullptr) {
553 effect->SetInputCount(inputCount - 1);
554 } else if (aIndex >= inputCount && aSurface) {
555 effect->SetInputCount(aIndex + 1);
559 RefPtr<ID2D1Image> image = GetImageForSourceSurface(mDT, aSurface);
560 effect->SetInput(input, image);
563 void
564 FilterNodeD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
566 UINT32 input = GetD2D1InputForInput(mType, aIndex);
567 ID2D1Effect* effect = InputEffect();
569 if (mType == FilterType::COMPOSITE) {
570 UINT32 inputCount = effect->GetInputCount();
572 if (aIndex == inputCount - 1 && aFilter == nullptr) {
573 effect->SetInputCount(inputCount - 1);
574 } else if (aIndex >= inputCount && aFilter) {
575 effect->SetInputCount(aIndex + 1);
579 MOZ_ASSERT(input < effect->GetInputCount());
581 if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
582 gfxWarning() << "Unknown input SourceSurface set on effect.";
583 MOZ_ASSERT(0);
584 return;
587 effect->SetInputEffect(input, static_cast<FilterNodeD2D1*>(aFilter)->OutputEffect());
590 void
591 FilterNodeD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue)
593 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
594 MOZ_ASSERT(input < mEffect->GetPropertyCount());
596 if (mType == FilterType::TURBULENCE && aIndex == ATT_TURBULENCE_BASE_FREQUENCY) {
597 mEffect->SetValue(input, D2D1::Vector2F(FLOAT(aValue), FLOAT(aValue)));
598 return;
599 } else if (mType == FilterType::DIRECTIONAL_BLUR && aIndex == ATT_DIRECTIONAL_BLUR_DIRECTION) {
600 mEffect->SetValue(input, aValue == BLUR_DIRECTION_X ? 0 : 90.0f);
601 return;
604 mEffect->SetValue(input, ConvertValue(mType, aIndex, aValue));
607 void
608 FilterNodeD2D1::SetAttribute(uint32_t aIndex, Float aValue)
610 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
611 MOZ_ASSERT(input < mEffect->GetPropertyCount());
613 mEffect->SetValue(input, aValue);
616 void
617 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point &aValue)
619 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
620 MOZ_ASSERT(input < mEffect->GetPropertyCount());
622 mEffect->SetValue(input, D2DPoint(aValue));
625 void
626 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix5x4 &aValue)
628 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
629 MOZ_ASSERT(input < mEffect->GetPropertyCount());
631 mEffect->SetValue(input, D2DMatrix5x4(aValue));
634 void
635 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point3D &aValue)
637 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
638 MOZ_ASSERT(input < mEffect->GetPropertyCount());
640 mEffect->SetValue(input, D2DVector3D(aValue));
643 void
644 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Size &aValue)
646 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
647 MOZ_ASSERT(input < mEffect->GetPropertyCount());
649 mEffect->SetValue(input, D2D1::Vector2F(aValue.width, aValue.height));
652 void
653 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue)
655 UINT32 widthProp, heightProp;
657 if (!GetD2D1PropsForIntSize(mType, aIndex, &widthProp, &heightProp)) {
658 return;
661 IntSize value = aValue;
662 ConvertValue(mType, aIndex, value);
664 mEffect->SetValue(widthProp, (UINT)value.width);
665 mEffect->SetValue(heightProp, (UINT)value.height);
668 void
669 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Color &aValue)
671 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
672 MOZ_ASSERT(input < mEffect->GetPropertyCount());
674 switch (mType) {
675 case FilterType::POINT_DIFFUSE:
676 case FilterType::SPOT_DIFFUSE:
677 case FilterType::DISTANT_DIFFUSE:
678 case FilterType::POINT_SPECULAR:
679 case FilterType::SPOT_SPECULAR:
680 case FilterType::DISTANT_SPECULAR:
681 mEffect->SetValue(input, D2D1::Vector3F(aValue.r, aValue.g, aValue.b));
682 break;
683 default:
684 mEffect->SetValue(input, D2D1::Vector4F(aValue.r * aValue.a, aValue.g * aValue.a, aValue.b * aValue.a, aValue.a));
688 void
689 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Rect &aValue)
691 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
692 MOZ_ASSERT(input < mEffect->GetPropertyCount());
694 mEffect->SetValue(input, D2DRect(aValue));
697 void
698 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue)
700 if (mType == FilterType::TURBULENCE) {
701 MOZ_ASSERT(aIndex == ATT_TURBULENCE_RECT);
703 mEffect->SetValue(D2D1_TURBULENCE_PROP_OFFSET, D2D1::Vector2F(Float(aValue.x), Float(aValue.y)));
704 mEffect->SetValue(D2D1_TURBULENCE_PROP_SIZE, D2D1::Vector2F(Float(aValue.width), Float(aValue.height)));
705 return;
708 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
709 MOZ_ASSERT(input < mEffect->GetPropertyCount());
711 mEffect->SetValue(input, D2D1::RectF(Float(aValue.x), Float(aValue.y),
712 Float(aValue.XMost()), Float(aValue.YMost())));
715 void
716 FilterNodeD2D1::SetAttribute(uint32_t aIndex, bool aValue)
718 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
719 MOZ_ASSERT(input < mEffect->GetPropertyCount());
721 mEffect->SetValue(input, (BOOL)aValue);
724 void
725 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Float *aValues, uint32_t aSize)
727 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
728 MOZ_ASSERT(input < mEffect->GetPropertyCount());
730 mEffect->SetValue(input, (BYTE*)aValues, sizeof(Float) * aSize);
733 void
734 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue)
736 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
737 MOZ_ASSERT(input < mEffect->GetPropertyCount());
739 mEffect->SetValue(input, D2DPoint(aValue));
742 void
743 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix)
745 UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
746 MOZ_ASSERT(input < mEffect->GetPropertyCount());
748 mEffect->SetValue(input, D2DMatrix(aMatrix));
751 FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC)
752 : FilterNodeD2D1(aDT, nullptr, FilterType::CONVOLVE_MATRIX)
753 , mEdgeMode(EDGE_MODE_DUPLICATE)
755 // Correctly handling the interaction of edge mode and source rect is a bit
756 // tricky with D2D1 effects. We want the edge mode to only apply outside of
757 // the source rect (as specified by the ATT_CONVOLVE_MATRIX_SOURCE_RECT
758 // attribute). So if our input surface or filter is smaller than the source
759 // rect, we need to add transparency around it until we reach the edges of
760 // the source rect, and only then do any repeating or edge duplicating.
761 // Unfortunately, D2D1 does not have any "extend with transparency" effect.
762 // (The crop effect can only cut off parts, it can't make the output rect
763 // bigger.) And the border effect does not have a source rect attribute -
764 // it only looks at the output rect of its input filter or surface.
765 // So we use the following trick to extend the input size to the source rect:
766 // Instead of feeding the input directly into the border effect, we first
767 // composite it with a transparent flood effect (which is infinite-sized) and
768 // use a crop effect on the result in order to get the right size. Then we
769 // feed the cropped composition into the border effect, which then finally
770 // feeds into the convolve matrix effect.
771 // All of this is only necessary when our edge mode is not EDGE_MODE_NONE, so
772 // we update the filter chain dynamically in UpdateChain().
774 HRESULT hr;
776 hr = aDC->CreateEffect(CLSID_D2D1ConvolveMatrix, byRef(mEffect));
778 if (FAILED(hr)) {
779 gfxWarning() << "Failed to create ConvolveMatrix filter!";
780 return;
783 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE, D2D1_BORDER_MODE_SOFT);
785 hr = aDC->CreateEffect(CLSID_D2D1Flood, byRef(mFloodEffect));
787 if (FAILED(hr)) {
788 gfxWarning() << "Failed to create ConvolveMatrix filter!";
789 return;
792 mFloodEffect->SetValue(D2D1_FLOOD_PROP_COLOR, D2D1::Vector4F(0.0f, 0.0f, 0.0f, 0.0f));
794 hr = aDC->CreateEffect(CLSID_D2D1Composite, byRef(mCompositeEffect));
796 if (FAILED(hr)) {
797 gfxWarning() << "Failed to create ConvolveMatrix filter!";
798 return;
801 mCompositeEffect->SetInputEffect(1, mFloodEffect.get());
803 hr = aDC->CreateEffect(CLSID_D2D1Crop, byRef(mCropEffect));
805 if (FAILED(hr)) {
806 gfxWarning() << "Failed to create ConvolveMatrix filter!";
807 return;
810 mCropEffect->SetInputEffect(0, mCompositeEffect.get());
812 hr = aDC->CreateEffect(CLSID_D2D1Border, byRef(mBorderEffect));
814 if (FAILED(hr)) {
815 gfxWarning() << "Failed to create ConvolveMatrix filter!";
816 return;
819 mBorderEffect->SetInputEffect(0, mCropEffect.get());
821 UpdateChain();
822 UpdateSourceRect();
825 void
826 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface)
828 MOZ_ASSERT(aIndex == 0);
830 mInput = GetImageForSourceSurface(mDT, aSurface);
832 mInputEffect = nullptr;
834 UpdateChain();
837 void
838 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
840 MOZ_ASSERT(aIndex == 0);
842 if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
843 gfxWarning() << "Unknown input SourceSurface set on effect.";
844 MOZ_ASSERT(0);
845 return;
848 mInput = nullptr;
849 mInputEffect = static_cast<FilterNodeD2D1*>(aFilter)->mEffect;
851 UpdateChain();
854 void
855 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue)
857 if (aIndex != ATT_CONVOLVE_MATRIX_EDGE_MODE) {
858 return FilterNodeD2D1::SetAttribute(aIndex, aValue);
861 mEdgeMode = (ConvolveMatrixEdgeMode)aValue;
863 UpdateChain();
866 void
867 FilterNodeConvolveD2D1::UpdateChain()
869 // The shape of the filter graph:
871 // EDGE_MODE_NONE:
872 // input --> convolvematrix
874 // EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP:
875 // input -------v
876 // flood --> composite --> crop --> border --> convolvematrix
878 ID2D1Effect *firstEffect = mCompositeEffect;
879 if (mEdgeMode == EDGE_MODE_NONE) {
880 firstEffect = mEffect;
881 } else {
882 mEffect->SetInputEffect(0, mBorderEffect.get());
885 if (mInputEffect) {
886 firstEffect->SetInputEffect(0, mInputEffect);
887 } else {
888 firstEffect->SetInput(0, mInput);
891 if (mEdgeMode == EDGE_MODE_DUPLICATE) {
892 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_CLAMP);
893 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_CLAMP);
894 } else if (mEdgeMode == EDGE_MODE_WRAP) {
895 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_WRAP);
896 mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_WRAP);
900 void
901 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue)
903 if (aIndex != ATT_CONVOLVE_MATRIX_KERNEL_SIZE) {
904 MOZ_ASSERT(false);
905 return;
908 mKernelSize = aValue;
910 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X, aValue.width);
911 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y, aValue.height);
913 UpdateOffset();
916 void
917 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue)
919 if (aIndex != ATT_CONVOLVE_MATRIX_TARGET) {
920 MOZ_ASSERT(false);
921 return;
924 mTarget = aValue;
926 UpdateOffset();
929 void
930 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue)
932 if (aIndex != ATT_CONVOLVE_MATRIX_SOURCE_RECT) {
933 MOZ_ASSERT(false);
934 return;
937 mSourceRect = aValue;
939 UpdateSourceRect();
942 void
943 FilterNodeConvolveD2D1::UpdateOffset()
945 D2D1_VECTOR_2F vector =
946 D2D1::Vector2F((Float(mKernelSize.width) - 1.0f) / 2.0f - Float(mTarget.x),
947 (Float(mKernelSize.height) - 1.0f) / 2.0f - Float(mTarget.y));
949 mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET, vector);
952 void
953 FilterNodeConvolveD2D1::UpdateSourceRect()
955 mCropEffect->SetValue(D2D1_CROP_PROP_RECT,
956 D2D1::RectF(Float(mSourceRect.x), Float(mSourceRect.y),
957 Float(mSourceRect.XMost()), Float(mSourceRect.YMost())));
960 FilterNodeComponentTransferD2D1::FilterNodeComponentTransferD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC,
961 ID2D1Effect *aEffect, FilterType aType)
962 : FilterNodeD2D1(aDT, aEffect, aType)
964 // D2D1 component transfer effects do strange things when it comes to
965 // premultiplication.
966 // For our purposes we only need the transfer filters to apply straight to
967 // unpremultiplied source channels and output unpremultiplied results.
968 // However, the D2D1 effects are designed differently: They can apply to both
969 // premultiplied and unpremultiplied inputs, and they always premultiply
970 // their result - at least in those color channels that have not been
971 // disabled.
972 // In order to determine whether the input needs to be unpremultiplied as
973 // part of the transfer, the effect consults the alpha mode metadata of the
974 // input surface or the input effect. We don't have such a concept in Moz2D,
975 // and giving Moz2D users different results based on something that cannot be
976 // influenced through Moz2D APIs seems like a bad idea.
977 // We solve this by applying a premultiply effect to the input before feeding
978 // it into the transfer effect. The premultiply effect always premultiplies
979 // regardless of any alpha mode metadata on inputs, and it always marks its
980 // output as premultiplied so that the transfer effect will unpremultiply
981 // consistently. Feeding always-premultiplied input into the transfer effect
982 // also avoids another problem that would appear when individual color
983 // channels disable the transfer: In that case, the disabled channels would
984 // pass through unchanged in their unpremultiplied form and the other
985 // channels would be premultiplied, giving a mixed result.
986 // But since we now ensure that the input is premultiplied, disabled channels
987 // will pass premultiplied values through to the result, which is consistent
988 // with the enabled channels.
989 // We also add an unpremultiply effect that postprocesses the result of the
990 // transfer effect because getting unpremultiplied results from the transfer
991 // filters is part of the FilterNode API.
992 HRESULT hr;
994 hr = aDC->CreateEffect(CLSID_D2D1Premultiply, byRef(mPrePremultiplyEffect));
996 if (FAILED(hr)) {
997 gfxWarning() << "Failed to create ComponentTransfer filter!";
998 return;
1001 hr = aDC->CreateEffect(CLSID_D2D1UnPremultiply, byRef(mPostUnpremultiplyEffect));
1003 if (FAILED(hr)) {
1004 gfxWarning() << "Failed to create ComponentTransfer filter!";
1005 return;
1008 mEffect->SetInputEffect(0, mPrePremultiplyEffect.get());
1009 mPostUnpremultiplyEffect->SetInputEffect(0, mEffect.get());