1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FilterNodeD2D1.h"
11 #include "SourceSurfaceD2D1.h"
12 #include "DrawTargetD2D1.h"
13 #include "ExtendInputEffectD2D1.h"
18 D2D1_COLORMATRIX_ALPHA_MODE
D2DAlphaMode(uint32_t aMode
) {
20 case ALPHA_MODE_PREMULTIPLIED
:
21 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED
;
22 case ALPHA_MODE_STRAIGHT
:
23 return D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT
;
25 MOZ_CRASH("GFX: Unknown enum value D2DAlphaMode!");
28 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED
;
31 D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE
D2DAffineTransformInterpolationMode(
32 SamplingFilter aSamplingFilter
) {
33 switch (aSamplingFilter
) {
34 case SamplingFilter::GOOD
:
35 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
36 case SamplingFilter::LINEAR
:
37 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
38 case SamplingFilter::POINT
:
39 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR
;
41 MOZ_CRASH("GFX: Unknown enum value D2DAffineTIM!");
44 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
47 D2D1_BLEND_MODE
D2DBlendMode(uint32_t aMode
) {
49 case BLEND_MODE_DARKEN
:
50 return D2D1_BLEND_MODE_DARKEN
;
51 case BLEND_MODE_LIGHTEN
:
52 return D2D1_BLEND_MODE_LIGHTEN
;
53 case BLEND_MODE_MULTIPLY
:
54 return D2D1_BLEND_MODE_MULTIPLY
;
55 case BLEND_MODE_SCREEN
:
56 return D2D1_BLEND_MODE_SCREEN
;
57 case BLEND_MODE_OVERLAY
:
58 return D2D1_BLEND_MODE_OVERLAY
;
59 case BLEND_MODE_COLOR_DODGE
:
60 return D2D1_BLEND_MODE_COLOR_DODGE
;
61 case BLEND_MODE_COLOR_BURN
:
62 return D2D1_BLEND_MODE_COLOR_BURN
;
63 case BLEND_MODE_HARD_LIGHT
:
64 return D2D1_BLEND_MODE_HARD_LIGHT
;
65 case BLEND_MODE_SOFT_LIGHT
:
66 return D2D1_BLEND_MODE_SOFT_LIGHT
;
67 case BLEND_MODE_DIFFERENCE
:
68 return D2D1_BLEND_MODE_DIFFERENCE
;
69 case BLEND_MODE_EXCLUSION
:
70 return D2D1_BLEND_MODE_EXCLUSION
;
72 return D2D1_BLEND_MODE_HUE
;
73 case BLEND_MODE_SATURATION
:
74 return D2D1_BLEND_MODE_SATURATION
;
75 case BLEND_MODE_COLOR
:
76 return D2D1_BLEND_MODE_COLOR
;
77 case BLEND_MODE_LUMINOSITY
:
78 return D2D1_BLEND_MODE_LUMINOSITY
;
81 MOZ_CRASH("GFX: Unknown enum value D2DBlendMode!");
84 return D2D1_BLEND_MODE_DARKEN
;
87 D2D1_MORPHOLOGY_MODE
D2DMorphologyMode(uint32_t aMode
) {
89 case MORPHOLOGY_OPERATOR_DILATE
:
90 return D2D1_MORPHOLOGY_MODE_DILATE
;
91 case MORPHOLOGY_OPERATOR_ERODE
:
92 return D2D1_MORPHOLOGY_MODE_ERODE
;
95 MOZ_CRASH("GFX: Unknown enum value D2DMorphologyMode!");
96 return D2D1_MORPHOLOGY_MODE_DILATE
;
99 D2D1_TURBULENCE_NOISE
D2DTurbulenceNoise(uint32_t aMode
) {
101 case TURBULENCE_TYPE_FRACTAL_NOISE
:
102 return D2D1_TURBULENCE_NOISE_FRACTAL_SUM
;
103 case TURBULENCE_TYPE_TURBULENCE
:
104 return D2D1_TURBULENCE_NOISE_TURBULENCE
;
107 MOZ_CRASH("GFX: Unknown enum value D2DTurbulenceNoise!");
108 return D2D1_TURBULENCE_NOISE_TURBULENCE
;
111 D2D1_COMPOSITE_MODE
D2DFilterCompositionMode(uint32_t aMode
) {
113 case COMPOSITE_OPERATOR_OVER
:
114 return D2D1_COMPOSITE_MODE_SOURCE_OVER
;
115 case COMPOSITE_OPERATOR_IN
:
116 return D2D1_COMPOSITE_MODE_SOURCE_IN
;
117 case COMPOSITE_OPERATOR_OUT
:
118 return D2D1_COMPOSITE_MODE_SOURCE_OUT
;
119 case COMPOSITE_OPERATOR_ATOP
:
120 return D2D1_COMPOSITE_MODE_SOURCE_ATOP
;
121 case COMPOSITE_OPERATOR_XOR
:
122 return D2D1_COMPOSITE_MODE_XOR
;
123 case COMPOSITE_OPERATOR_LIGHTER
:
124 return D2D1_COMPOSITE_MODE_PLUS
;
127 MOZ_CRASH("GFX: Unknown enum value D2DFilterCompositionMode!");
128 return D2D1_COMPOSITE_MODE_SOURCE_OVER
;
131 D2D1_CHANNEL_SELECTOR
D2DChannelSelector(uint32_t aMode
) {
133 case COLOR_CHANNEL_R
:
134 return D2D1_CHANNEL_SELECTOR_R
;
135 case COLOR_CHANNEL_G
:
136 return D2D1_CHANNEL_SELECTOR_G
;
137 case COLOR_CHANNEL_B
:
138 return D2D1_CHANNEL_SELECTOR_B
;
139 case COLOR_CHANNEL_A
:
140 return D2D1_CHANNEL_SELECTOR_A
;
143 MOZ_CRASH("GFX: Unknown enum value D2DChannelSelector!");
144 return D2D1_CHANNEL_SELECTOR_R
;
147 already_AddRefed
<ID2D1Image
> GetImageForSourceSurface(DrawTarget
* aDT
,
148 SourceSurface
* aSurface
) {
149 if (aDT
->IsTiledDrawTarget()) {
150 gfxDevCrash(LogReason::FilterNodeD2D1Target
)
151 << "Incompatible draw target type! " << (int)aDT
->IsTiledDrawTarget();
154 switch (aDT
->GetBackendType()) {
155 case BackendType::DIRECT2D1_1
:
156 return static_cast<DrawTargetD2D1
*>(aDT
)->GetImageForSurface(
157 aSurface
, ExtendMode::CLAMP
);
159 gfxDevCrash(LogReason::FilterNodeD2D1Backend
)
160 << "Unknown draw target type! " << (int)aDT
->GetBackendType();
165 uint32_t ConvertValue(FilterType aType
, uint32_t aAttribute
, uint32_t aValue
) {
167 case FilterType::COLOR_MATRIX
:
168 if (aAttribute
== ATT_COLOR_MATRIX_ALPHA_MODE
) {
169 aValue
= D2DAlphaMode(aValue
);
172 case FilterType::TRANSFORM
:
173 if (aAttribute
== ATT_TRANSFORM_FILTER
) {
174 aValue
= D2DAffineTransformInterpolationMode(SamplingFilter(aValue
));
177 case FilterType::BLEND
:
178 if (aAttribute
== ATT_BLEND_BLENDMODE
) {
179 aValue
= D2DBlendMode(aValue
);
182 case FilterType::MORPHOLOGY
:
183 if (aAttribute
== ATT_MORPHOLOGY_OPERATOR
) {
184 aValue
= D2DMorphologyMode(aValue
);
187 case FilterType::DISPLACEMENT_MAP
:
188 if (aAttribute
== ATT_DISPLACEMENT_MAP_X_CHANNEL
||
189 aAttribute
== ATT_DISPLACEMENT_MAP_Y_CHANNEL
) {
190 aValue
= D2DChannelSelector(aValue
);
193 case FilterType::TURBULENCE
:
194 if (aAttribute
== ATT_TURBULENCE_TYPE
) {
195 aValue
= D2DTurbulenceNoise(aValue
);
198 case FilterType::COMPOSITE
:
199 if (aAttribute
== ATT_COMPOSITE_OPERATOR
) {
200 aValue
= D2DFilterCompositionMode(aValue
);
210 void ConvertValue(FilterType aType
, uint32_t aAttribute
, IntSize
& aValue
) {
212 case FilterType::MORPHOLOGY
:
213 if (aAttribute
== ATT_MORPHOLOGY_RADII
) {
226 GetD2D1InputForInput(FilterType aType
, uint32_t aIndex
) { return aIndex
; }
228 #define CONVERT_PROP(moz2dname, d2dname) \
229 case ATT_##moz2dname: \
230 return D2D1_##d2dname
233 GetD2D1PropForAttribute(FilterType aType
, uint32_t aIndex
) {
235 case FilterType::COLOR_MATRIX
:
237 CONVERT_PROP(COLOR_MATRIX_MATRIX
, COLORMATRIX_PROP_COLOR_MATRIX
);
238 CONVERT_PROP(COLOR_MATRIX_ALPHA_MODE
, COLORMATRIX_PROP_ALPHA_MODE
);
241 case FilterType::TRANSFORM
:
243 CONVERT_PROP(TRANSFORM_MATRIX
, 2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX
);
244 CONVERT_PROP(TRANSFORM_FILTER
,
245 2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE
);
247 case FilterType::BLEND
:
248 switch (aIndex
) { CONVERT_PROP(BLEND_BLENDMODE
, BLEND_PROP_MODE
); }
250 case FilterType::MORPHOLOGY
:
252 CONVERT_PROP(MORPHOLOGY_OPERATOR
, MORPHOLOGY_PROP_MODE
);
255 case FilterType::FLOOD
:
256 switch (aIndex
) { CONVERT_PROP(FLOOD_COLOR
, FLOOD_PROP_COLOR
); }
258 case FilterType::TILE
:
259 switch (aIndex
) { CONVERT_PROP(TILE_SOURCE_RECT
, TILE_PROP_RECT
); }
261 case FilterType::TABLE_TRANSFER
:
263 CONVERT_PROP(TABLE_TRANSFER_DISABLE_R
, TABLETRANSFER_PROP_RED_DISABLE
);
264 CONVERT_PROP(TABLE_TRANSFER_DISABLE_G
,
265 TABLETRANSFER_PROP_GREEN_DISABLE
);
266 CONVERT_PROP(TABLE_TRANSFER_DISABLE_B
, TABLETRANSFER_PROP_BLUE_DISABLE
);
267 CONVERT_PROP(TABLE_TRANSFER_DISABLE_A
,
268 TABLETRANSFER_PROP_ALPHA_DISABLE
);
269 CONVERT_PROP(TABLE_TRANSFER_TABLE_R
, TABLETRANSFER_PROP_RED_TABLE
);
270 CONVERT_PROP(TABLE_TRANSFER_TABLE_G
, TABLETRANSFER_PROP_GREEN_TABLE
);
271 CONVERT_PROP(TABLE_TRANSFER_TABLE_B
, TABLETRANSFER_PROP_BLUE_TABLE
);
272 CONVERT_PROP(TABLE_TRANSFER_TABLE_A
, TABLETRANSFER_PROP_ALPHA_TABLE
);
275 case FilterType::DISCRETE_TRANSFER
:
277 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_R
,
278 DISCRETETRANSFER_PROP_RED_DISABLE
);
279 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_G
,
280 DISCRETETRANSFER_PROP_GREEN_DISABLE
);
281 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_B
,
282 DISCRETETRANSFER_PROP_BLUE_DISABLE
);
283 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_A
,
284 DISCRETETRANSFER_PROP_ALPHA_DISABLE
);
285 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_R
,
286 DISCRETETRANSFER_PROP_RED_TABLE
);
287 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_G
,
288 DISCRETETRANSFER_PROP_GREEN_TABLE
);
289 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_B
,
290 DISCRETETRANSFER_PROP_BLUE_TABLE
);
291 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_A
,
292 DISCRETETRANSFER_PROP_ALPHA_TABLE
);
295 case FilterType::LINEAR_TRANSFER
:
297 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_R
,
298 LINEARTRANSFER_PROP_RED_DISABLE
);
299 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_G
,
300 LINEARTRANSFER_PROP_GREEN_DISABLE
);
301 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_B
,
302 LINEARTRANSFER_PROP_BLUE_DISABLE
);
303 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_A
,
304 LINEARTRANSFER_PROP_ALPHA_DISABLE
);
305 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_R
,
306 LINEARTRANSFER_PROP_RED_Y_INTERCEPT
);
307 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_G
,
308 LINEARTRANSFER_PROP_GREEN_Y_INTERCEPT
);
309 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_B
,
310 LINEARTRANSFER_PROP_BLUE_Y_INTERCEPT
);
311 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_A
,
312 LINEARTRANSFER_PROP_ALPHA_Y_INTERCEPT
);
313 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_R
, LINEARTRANSFER_PROP_RED_SLOPE
);
314 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_G
, LINEARTRANSFER_PROP_GREEN_SLOPE
);
315 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_B
, LINEARTRANSFER_PROP_BLUE_SLOPE
);
316 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_A
, LINEARTRANSFER_PROP_ALPHA_SLOPE
);
319 case FilterType::GAMMA_TRANSFER
:
321 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_R
, GAMMATRANSFER_PROP_RED_DISABLE
);
322 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_G
,
323 GAMMATRANSFER_PROP_GREEN_DISABLE
);
324 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_B
, GAMMATRANSFER_PROP_BLUE_DISABLE
);
325 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_A
,
326 GAMMATRANSFER_PROP_ALPHA_DISABLE
);
327 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_R
,
328 GAMMATRANSFER_PROP_RED_AMPLITUDE
);
329 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_G
,
330 GAMMATRANSFER_PROP_GREEN_AMPLITUDE
);
331 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_B
,
332 GAMMATRANSFER_PROP_BLUE_AMPLITUDE
);
333 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_A
,
334 GAMMATRANSFER_PROP_ALPHA_AMPLITUDE
);
335 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_R
,
336 GAMMATRANSFER_PROP_RED_EXPONENT
);
337 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_G
,
338 GAMMATRANSFER_PROP_GREEN_EXPONENT
);
339 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_B
,
340 GAMMATRANSFER_PROP_BLUE_EXPONENT
);
341 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_A
,
342 GAMMATRANSFER_PROP_ALPHA_EXPONENT
);
343 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_R
, GAMMATRANSFER_PROP_RED_OFFSET
);
344 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_G
, GAMMATRANSFER_PROP_GREEN_OFFSET
);
345 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_B
, GAMMATRANSFER_PROP_BLUE_OFFSET
);
346 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_A
, GAMMATRANSFER_PROP_ALPHA_OFFSET
);
349 case FilterType::CONVOLVE_MATRIX
:
351 CONVERT_PROP(CONVOLVE_MATRIX_BIAS
, CONVOLVEMATRIX_PROP_BIAS
);
352 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_MATRIX
,
353 CONVOLVEMATRIX_PROP_KERNEL_MATRIX
);
354 CONVERT_PROP(CONVOLVE_MATRIX_DIVISOR
, CONVOLVEMATRIX_PROP_DIVISOR
);
355 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH
,
356 CONVOLVEMATRIX_PROP_KERNEL_UNIT_LENGTH
);
357 CONVERT_PROP(CONVOLVE_MATRIX_PRESERVE_ALPHA
,
358 CONVOLVEMATRIX_PROP_PRESERVE_ALPHA
);
360 case FilterType::DISPLACEMENT_MAP
:
362 CONVERT_PROP(DISPLACEMENT_MAP_SCALE
, DISPLACEMENTMAP_PROP_SCALE
);
363 CONVERT_PROP(DISPLACEMENT_MAP_X_CHANNEL
,
364 DISPLACEMENTMAP_PROP_X_CHANNEL_SELECT
);
365 CONVERT_PROP(DISPLACEMENT_MAP_Y_CHANNEL
,
366 DISPLACEMENTMAP_PROP_Y_CHANNEL_SELECT
);
369 case FilterType::TURBULENCE
:
371 CONVERT_PROP(TURBULENCE_BASE_FREQUENCY
, TURBULENCE_PROP_BASE_FREQUENCY
);
372 CONVERT_PROP(TURBULENCE_NUM_OCTAVES
, TURBULENCE_PROP_NUM_OCTAVES
);
373 CONVERT_PROP(TURBULENCE_SEED
, TURBULENCE_PROP_SEED
);
374 CONVERT_PROP(TURBULENCE_STITCHABLE
, TURBULENCE_PROP_STITCHABLE
);
375 CONVERT_PROP(TURBULENCE_TYPE
, TURBULENCE_PROP_NOISE
);
378 case FilterType::ARITHMETIC_COMBINE
:
380 CONVERT_PROP(ARITHMETIC_COMBINE_COEFFICIENTS
,
381 ARITHMETICCOMPOSITE_PROP_COEFFICIENTS
);
384 case FilterType::COMPOSITE
:
385 switch (aIndex
) { CONVERT_PROP(COMPOSITE_OPERATOR
, COMPOSITE_PROP_MODE
); }
387 case FilterType::GAUSSIAN_BLUR
:
389 CONVERT_PROP(GAUSSIAN_BLUR_STD_DEVIATION
,
390 GAUSSIANBLUR_PROP_STANDARD_DEVIATION
);
393 case FilterType::DIRECTIONAL_BLUR
:
395 CONVERT_PROP(DIRECTIONAL_BLUR_STD_DEVIATION
,
396 DIRECTIONALBLUR_PROP_STANDARD_DEVIATION
);
397 CONVERT_PROP(DIRECTIONAL_BLUR_DIRECTION
, DIRECTIONALBLUR_PROP_ANGLE
);
400 case FilterType::POINT_DIFFUSE
:
402 CONVERT_PROP(POINT_DIFFUSE_DIFFUSE_CONSTANT
,
403 POINTDIFFUSE_PROP_DIFFUSE_CONSTANT
);
404 CONVERT_PROP(POINT_DIFFUSE_POSITION
, POINTDIFFUSE_PROP_LIGHT_POSITION
);
405 CONVERT_PROP(POINT_DIFFUSE_COLOR
, POINTDIFFUSE_PROP_COLOR
);
406 CONVERT_PROP(POINT_DIFFUSE_SURFACE_SCALE
,
407 POINTDIFFUSE_PROP_SURFACE_SCALE
);
408 CONVERT_PROP(POINT_DIFFUSE_KERNEL_UNIT_LENGTH
,
409 POINTDIFFUSE_PROP_KERNEL_UNIT_LENGTH
);
412 case FilterType::SPOT_DIFFUSE
:
414 CONVERT_PROP(SPOT_DIFFUSE_DIFFUSE_CONSTANT
,
415 SPOTDIFFUSE_PROP_DIFFUSE_CONSTANT
);
416 CONVERT_PROP(SPOT_DIFFUSE_POINTS_AT
, SPOTDIFFUSE_PROP_POINTS_AT
);
417 CONVERT_PROP(SPOT_DIFFUSE_FOCUS
, SPOTDIFFUSE_PROP_FOCUS
);
418 CONVERT_PROP(SPOT_DIFFUSE_LIMITING_CONE_ANGLE
,
419 SPOTDIFFUSE_PROP_LIMITING_CONE_ANGLE
);
420 CONVERT_PROP(SPOT_DIFFUSE_POSITION
, SPOTDIFFUSE_PROP_LIGHT_POSITION
);
421 CONVERT_PROP(SPOT_DIFFUSE_COLOR
, SPOTDIFFUSE_PROP_COLOR
);
422 CONVERT_PROP(SPOT_DIFFUSE_SURFACE_SCALE
,
423 SPOTDIFFUSE_PROP_SURFACE_SCALE
);
424 CONVERT_PROP(SPOT_DIFFUSE_KERNEL_UNIT_LENGTH
,
425 SPOTDIFFUSE_PROP_KERNEL_UNIT_LENGTH
);
428 case FilterType::DISTANT_DIFFUSE
:
430 CONVERT_PROP(DISTANT_DIFFUSE_DIFFUSE_CONSTANT
,
431 DISTANTDIFFUSE_PROP_DIFFUSE_CONSTANT
);
432 CONVERT_PROP(DISTANT_DIFFUSE_AZIMUTH
, DISTANTDIFFUSE_PROP_AZIMUTH
);
433 CONVERT_PROP(DISTANT_DIFFUSE_ELEVATION
, DISTANTDIFFUSE_PROP_ELEVATION
);
434 CONVERT_PROP(DISTANT_DIFFUSE_COLOR
, DISTANTDIFFUSE_PROP_COLOR
);
435 CONVERT_PROP(DISTANT_DIFFUSE_SURFACE_SCALE
,
436 DISTANTDIFFUSE_PROP_SURFACE_SCALE
);
437 CONVERT_PROP(DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH
,
438 DISTANTDIFFUSE_PROP_KERNEL_UNIT_LENGTH
);
441 case FilterType::POINT_SPECULAR
:
443 CONVERT_PROP(POINT_SPECULAR_SPECULAR_CONSTANT
,
444 POINTSPECULAR_PROP_SPECULAR_CONSTANT
);
445 CONVERT_PROP(POINT_SPECULAR_SPECULAR_EXPONENT
,
446 POINTSPECULAR_PROP_SPECULAR_EXPONENT
);
447 CONVERT_PROP(POINT_SPECULAR_POSITION
,
448 POINTSPECULAR_PROP_LIGHT_POSITION
);
449 CONVERT_PROP(POINT_SPECULAR_COLOR
, POINTSPECULAR_PROP_COLOR
);
450 CONVERT_PROP(POINT_SPECULAR_SURFACE_SCALE
,
451 POINTSPECULAR_PROP_SURFACE_SCALE
);
452 CONVERT_PROP(POINT_SPECULAR_KERNEL_UNIT_LENGTH
,
453 POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH
);
456 case FilterType::SPOT_SPECULAR
:
458 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_CONSTANT
,
459 SPOTSPECULAR_PROP_SPECULAR_CONSTANT
);
460 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_EXPONENT
,
461 SPOTSPECULAR_PROP_SPECULAR_EXPONENT
);
462 CONVERT_PROP(SPOT_SPECULAR_POINTS_AT
, SPOTSPECULAR_PROP_POINTS_AT
);
463 CONVERT_PROP(SPOT_SPECULAR_FOCUS
, SPOTSPECULAR_PROP_FOCUS
);
464 CONVERT_PROP(SPOT_SPECULAR_LIMITING_CONE_ANGLE
,
465 SPOTSPECULAR_PROP_LIMITING_CONE_ANGLE
);
466 CONVERT_PROP(SPOT_SPECULAR_POSITION
, SPOTSPECULAR_PROP_LIGHT_POSITION
);
467 CONVERT_PROP(SPOT_SPECULAR_COLOR
, SPOTSPECULAR_PROP_COLOR
);
468 CONVERT_PROP(SPOT_SPECULAR_SURFACE_SCALE
,
469 SPOTSPECULAR_PROP_SURFACE_SCALE
);
470 CONVERT_PROP(SPOT_SPECULAR_KERNEL_UNIT_LENGTH
,
471 SPOTSPECULAR_PROP_KERNEL_UNIT_LENGTH
);
474 case FilterType::DISTANT_SPECULAR
:
476 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_CONSTANT
,
477 DISTANTSPECULAR_PROP_SPECULAR_CONSTANT
);
478 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_EXPONENT
,
479 DISTANTSPECULAR_PROP_SPECULAR_EXPONENT
);
480 CONVERT_PROP(DISTANT_SPECULAR_AZIMUTH
, DISTANTSPECULAR_PROP_AZIMUTH
);
481 CONVERT_PROP(DISTANT_SPECULAR_ELEVATION
,
482 DISTANTSPECULAR_PROP_ELEVATION
);
483 CONVERT_PROP(DISTANT_SPECULAR_COLOR
, DISTANTSPECULAR_PROP_COLOR
);
484 CONVERT_PROP(DISTANT_SPECULAR_SURFACE_SCALE
,
485 DISTANTSPECULAR_PROP_SURFACE_SCALE
);
486 CONVERT_PROP(DISTANT_SPECULAR_KERNEL_UNIT_LENGTH
,
487 DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH
);
490 case FilterType::CROP
:
491 switch (aIndex
) { CONVERT_PROP(CROP_RECT
, CROP_PROP_RECT
); }
500 bool GetD2D1PropsForIntSize(FilterType aType
, uint32_t aIndex
,
501 UINT32
* aPropWidth
, UINT32
* aPropHeight
) {
503 case FilterType::MORPHOLOGY
:
504 if (aIndex
== ATT_MORPHOLOGY_RADII
) {
505 *aPropWidth
= D2D1_MORPHOLOGY_PROP_WIDTH
;
506 *aPropHeight
= D2D1_MORPHOLOGY_PROP_HEIGHT
;
516 static inline REFCLSID
GetCLDIDForFilterType(FilterType aType
) {
518 case FilterType::OPACITY
:
519 case FilterType::COLOR_MATRIX
:
520 return CLSID_D2D1ColorMatrix
;
521 case FilterType::TRANSFORM
:
522 return CLSID_D2D12DAffineTransform
;
523 case FilterType::BLEND
:
524 return CLSID_D2D1Blend
;
525 case FilterType::MORPHOLOGY
:
526 return CLSID_D2D1Morphology
;
527 case FilterType::FLOOD
:
528 return CLSID_D2D1Flood
;
529 case FilterType::TILE
:
530 return CLSID_D2D1Tile
;
531 case FilterType::TABLE_TRANSFER
:
532 return CLSID_D2D1TableTransfer
;
533 case FilterType::LINEAR_TRANSFER
:
534 return CLSID_D2D1LinearTransfer
;
535 case FilterType::DISCRETE_TRANSFER
:
536 return CLSID_D2D1DiscreteTransfer
;
537 case FilterType::GAMMA_TRANSFER
:
538 return CLSID_D2D1GammaTransfer
;
539 case FilterType::DISPLACEMENT_MAP
:
540 return CLSID_D2D1DisplacementMap
;
541 case FilterType::TURBULENCE
:
542 return CLSID_D2D1Turbulence
;
543 case FilterType::ARITHMETIC_COMBINE
:
544 return CLSID_D2D1ArithmeticComposite
;
545 case FilterType::COMPOSITE
:
546 return CLSID_D2D1Composite
;
547 case FilterType::GAUSSIAN_BLUR
:
548 return CLSID_D2D1GaussianBlur
;
549 case FilterType::DIRECTIONAL_BLUR
:
550 return CLSID_D2D1DirectionalBlur
;
551 case FilterType::POINT_DIFFUSE
:
552 return CLSID_D2D1PointDiffuse
;
553 case FilterType::POINT_SPECULAR
:
554 return CLSID_D2D1PointSpecular
;
555 case FilterType::SPOT_DIFFUSE
:
556 return CLSID_D2D1SpotDiffuse
;
557 case FilterType::SPOT_SPECULAR
:
558 return CLSID_D2D1SpotSpecular
;
559 case FilterType::DISTANT_DIFFUSE
:
560 return CLSID_D2D1DistantDiffuse
;
561 case FilterType::DISTANT_SPECULAR
:
562 return CLSID_D2D1DistantSpecular
;
563 case FilterType::CROP
:
564 return CLSID_D2D1Crop
;
565 case FilterType::PREMULTIPLY
:
566 return CLSID_D2D1Premultiply
;
567 case FilterType::UNPREMULTIPLY
:
568 return CLSID_D2D1UnPremultiply
;
575 static bool IsTransferFilterType(FilterType aType
) {
577 case FilterType::LINEAR_TRANSFER
:
578 case FilterType::GAMMA_TRANSFER
:
579 case FilterType::TABLE_TRANSFER
:
580 case FilterType::DISCRETE_TRANSFER
:
587 static bool HasUnboundedOutputRegion(FilterType aType
) {
588 if (IsTransferFilterType(aType
)) {
593 case FilterType::COLOR_MATRIX
:
594 case FilterType::POINT_DIFFUSE
:
595 case FilterType::SPOT_DIFFUSE
:
596 case FilterType::DISTANT_DIFFUSE
:
597 case FilterType::POINT_SPECULAR
:
598 case FilterType::SPOT_SPECULAR
:
599 case FilterType::DISTANT_SPECULAR
:
607 already_AddRefed
<FilterNode
> FilterNodeD2D1::Create(ID2D1DeviceContext
* aDC
,
609 if (aType
== FilterType::CONVOLVE_MATRIX
) {
610 return MakeAndAddRef
<FilterNodeConvolveD2D1
>(aDC
);
613 RefPtr
<ID2D1Effect
> effect
;
616 hr
= aDC
->CreateEffect(GetCLDIDForFilterType(aType
), getter_AddRefs(effect
));
618 if (FAILED(hr
) || !effect
) {
619 gfxCriticalErrorOnce() << "Failed to create effect for FilterType: "
624 if (aType
== FilterType::ARITHMETIC_COMBINE
) {
625 effect
->SetValue(D2D1_ARITHMETICCOMPOSITE_PROP_CLAMP_OUTPUT
, TRUE
);
628 if (aType
== FilterType::OPACITY
) {
629 return MakeAndAddRef
<FilterNodeOpacityD2D1
>(effect
, aType
);
632 RefPtr
<FilterNodeD2D1
> filter
= new FilterNodeD2D1(effect
, aType
);
634 if (HasUnboundedOutputRegion(aType
)) {
635 // These filters can produce non-transparent output from transparent
636 // input pixels, and we want them to have an unbounded output region.
637 filter
= new FilterNodeExtendInputAdapterD2D1(aDC
, filter
, aType
);
640 if (IsTransferFilterType(aType
)) {
641 // Component transfer filters should appear to apply on unpremultiplied
642 // colors, but the D2D1 effects apply on premultiplied colors.
643 filter
= new FilterNodePremultiplyAdapterD2D1(aDC
, filter
, aType
);
646 return filter
.forget();
649 void FilterNodeD2D1::InitUnmappedProperties() {
651 case FilterType::COLOR_MATRIX
:
652 mEffect
->SetValue(D2D1_COLORMATRIX_PROP_CLAMP_OUTPUT
, TRUE
);
654 case FilterType::TRANSFORM
:
655 mEffect
->SetValue(D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE
,
656 D2D1_BORDER_MODE_HARD
);
663 void FilterNodeD2D1::SetInput(uint32_t aIndex
, SourceSurface
* aSurface
) {
664 UINT32 input
= GetD2D1InputForInput(mType
, aIndex
);
665 ID2D1Effect
* effect
= InputEffect();
667 if (mType
== FilterType::COMPOSITE
) {
668 UINT32 inputCount
= effect
->GetInputCount();
670 if (aIndex
== inputCount
- 1 && aSurface
== nullptr) {
671 effect
->SetInputCount(inputCount
- 1);
672 } else if (aIndex
>= inputCount
&& aSurface
) {
673 effect
->SetInputCount(aIndex
+ 1);
677 auto inputCount
= effect
->GetInputCount();
678 MOZ_RELEASE_ASSERT(input
< inputCount
);
680 mInputSurfaces
.resize(inputCount
);
681 mInputFilters
.resize(inputCount
);
683 // In order to convert aSurface into an ID2D1Image, we need to know what
684 // DrawTarget we paint into. However, the same FilterNode object can be
685 // used on different DrawTargets, so we need to hold on to the SourceSurface
686 // objects and delay the conversion until we're actually painted and know
687 // our target DrawTarget.
688 // The conversion happens in WillDraw().
690 mInputSurfaces
[input
] = aSurface
;
691 mInputFilters
[input
] = nullptr;
693 // Clear the existing image from the effect.
694 effect
->SetInput(input
, nullptr);
697 void FilterNodeD2D1::SetInput(uint32_t aIndex
, FilterNode
* aFilter
) {
698 UINT32 input
= GetD2D1InputForInput(mType
, aIndex
);
699 ID2D1Effect
* effect
= InputEffect();
701 if (mType
== FilterType::COMPOSITE
) {
702 UINT32 inputCount
= effect
->GetInputCount();
704 if (aIndex
== inputCount
- 1 && aFilter
== nullptr) {
705 effect
->SetInputCount(inputCount
- 1);
706 } else if (aIndex
>= inputCount
&& aFilter
) {
707 effect
->SetInputCount(aIndex
+ 1);
711 auto inputCount
= effect
->GetInputCount();
712 MOZ_RELEASE_ASSERT(input
< inputCount
);
714 if (aFilter
&& aFilter
->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1
) {
715 gfxWarning() << "Unknown input FilterNode set on effect.";
720 FilterNodeD2D1
* filter
= static_cast<FilterNodeD2D1
*>(aFilter
);
722 mInputSurfaces
.resize(inputCount
);
723 mInputFilters
.resize(inputCount
);
725 // We hold on to the FilterNode object so that we can call WillDraw() on it.
726 mInputSurfaces
[input
] = nullptr;
727 mInputFilters
[input
] = filter
;
730 effect
->SetInputEffect(input
, filter
->OutputEffect());
734 void FilterNodeD2D1::WillDraw(DrawTarget
* aDT
) {
735 // Convert input SourceSurfaces into ID2D1Images and set them on the effect.
736 for (size_t inputIndex
= 0; inputIndex
< mInputSurfaces
.size();
738 if (mInputSurfaces
[inputIndex
]) {
739 ID2D1Effect
* effect
= InputEffect();
740 RefPtr
<ID2D1Image
> image
=
741 GetImageForSourceSurface(aDT
, mInputSurfaces
[inputIndex
]);
742 effect
->SetInput(inputIndex
, image
);
746 // Call WillDraw() on our input filters.
747 for (std::vector
<RefPtr
<FilterNodeD2D1
>>::iterator it
= mInputFilters
.begin();
748 it
!= mInputFilters
.end(); it
++) {
750 (*it
)->WillDraw(aDT
);
755 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, uint32_t aValue
) {
756 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
757 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
759 if (mType
== FilterType::TURBULENCE
&&
760 aIndex
== ATT_TURBULENCE_BASE_FREQUENCY
) {
761 mEffect
->SetValue(input
, D2D1::Vector2F(FLOAT(aValue
), FLOAT(aValue
)));
763 } else if (mType
== FilterType::DIRECTIONAL_BLUR
&&
764 aIndex
== ATT_DIRECTIONAL_BLUR_DIRECTION
) {
765 mEffect
->SetValue(input
, aValue
== BLUR_DIRECTION_X
? 0 : 90.0f
);
769 mEffect
->SetValue(input
, ConvertValue(mType
, aIndex
, aValue
));
772 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, Float aValue
) {
773 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
774 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
776 mEffect
->SetValue(input
, aValue
);
779 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Point
& aValue
) {
780 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
781 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
783 mEffect
->SetValue(input
, D2DPoint(aValue
));
786 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Matrix5x4
& aValue
) {
787 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
788 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
790 mEffect
->SetValue(input
, D2DMatrix5x4(aValue
));
793 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Point3D
& aValue
) {
794 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
795 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
797 mEffect
->SetValue(input
, D2DVector3D(aValue
));
800 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Size
& aValue
) {
801 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
802 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
804 mEffect
->SetValue(input
, D2D1::Vector2F(aValue
.width
, aValue
.height
));
807 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const IntSize
& aValue
) {
808 UINT32 widthProp
, heightProp
;
810 if (!GetD2D1PropsForIntSize(mType
, aIndex
, &widthProp
, &heightProp
)) {
814 IntSize value
= aValue
;
815 ConvertValue(mType
, aIndex
, value
);
817 mEffect
->SetValue(widthProp
, (UINT
)value
.width
);
818 mEffect
->SetValue(heightProp
, (UINT
)value
.height
);
821 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const DeviceColor
& aValue
) {
822 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
823 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
826 case FilterType::POINT_DIFFUSE
:
827 case FilterType::SPOT_DIFFUSE
:
828 case FilterType::DISTANT_DIFFUSE
:
829 case FilterType::POINT_SPECULAR
:
830 case FilterType::SPOT_SPECULAR
:
831 case FilterType::DISTANT_SPECULAR
:
832 mEffect
->SetValue(input
, D2D1::Vector3F(aValue
.r
, aValue
.g
, aValue
.b
));
835 mEffect
->SetValue(input
,
836 D2D1::Vector4F(aValue
.r
* aValue
.a
, aValue
.g
* aValue
.a
,
837 aValue
.b
* aValue
.a
, aValue
.a
));
841 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Rect
& aValue
) {
842 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
843 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
845 mEffect
->SetValue(input
, D2DRect(aValue
));
848 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const IntRect
& aValue
) {
849 if (mType
== FilterType::TURBULENCE
) {
850 MOZ_ASSERT(aIndex
== ATT_TURBULENCE_RECT
);
852 mEffect
->SetValue(D2D1_TURBULENCE_PROP_OFFSET
,
853 D2D1::Vector2F(Float(aValue
.X()), Float(aValue
.Y())));
855 D2D1_TURBULENCE_PROP_SIZE
,
856 D2D1::Vector2F(Float(aValue
.Width()), Float(aValue
.Height())));
860 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
861 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
863 mEffect
->SetValue(input
,
864 D2D1::RectF(Float(aValue
.X()), Float(aValue
.Y()),
865 Float(aValue
.XMost()), Float(aValue
.YMost())));
868 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, bool aValue
) {
869 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
870 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
872 mEffect
->SetValue(input
, (BOOL
)aValue
);
875 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Float
* aValues
,
877 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
878 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
880 mEffect
->SetValue(input
, (BYTE
*)aValues
, sizeof(Float
) * aSize
);
883 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const IntPoint
& aValue
) {
884 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
885 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
887 mEffect
->SetValue(input
, D2DPoint(aValue
));
890 void FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Matrix
& aMatrix
) {
891 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
892 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
894 mEffect
->SetValue(input
, D2DMatrix(aMatrix
));
897 void FilterNodeOpacityD2D1::SetAttribute(uint32_t aIndex
, Float aValue
) {
898 D2D1_MATRIX_5X4_F matrix
=
899 D2D1::Matrix5x4F(aValue
, 0, 0, 0, 0, aValue
, 0, 0, 0, 0, aValue
, 0, 0, 0,
900 0, aValue
, 0, 0, 0, 0);
902 mEffect
->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX
, matrix
);
903 mEffect
->SetValue(D2D1_COLORMATRIX_PROP_ALPHA_MODE
,
904 D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT
);
907 FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(ID2D1DeviceContext
* aDC
)
908 : FilterNodeD2D1(nullptr, FilterType::CONVOLVE_MATRIX
),
909 mEdgeMode(EDGE_MODE_DUPLICATE
) {
910 // Correctly handling the interaction of edge mode and source rect is a bit
911 // tricky with D2D1 effects. We want the edge mode to only apply outside of
912 // the source rect (as specified by the ATT_CONVOLVE_MATRIX_SOURCE_RECT
913 // attribute). So if our input surface or filter is smaller than the source
914 // rect, we need to add transparency around it until we reach the edges of
915 // the source rect, and only then do any repeating or edge duplicating.
916 // Unfortunately, the border effect does not have a source rect attribute -
917 // it only looks at the output rect of its input filter or surface. So we use
918 // our custom ExtendInput effect to adjust the output rect of our input.
919 // All of this is only necessary when our edge mode is not EDGE_MODE_NONE, so
920 // we update the filter chain dynamically in UpdateChain().
924 hr
= aDC
->CreateEffect(CLSID_D2D1ConvolveMatrix
, getter_AddRefs(mEffect
));
926 if (FAILED(hr
) || !mEffect
) {
927 gfxWarning() << "Failed to create ConvolveMatrix filter!";
931 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE
,
932 D2D1_BORDER_MODE_SOFT
);
934 hr
= aDC
->CreateEffect(CLSID_ExtendInputEffect
,
935 getter_AddRefs(mExtendInputEffect
));
937 if (FAILED(hr
) || !mExtendInputEffect
) {
938 gfxWarning() << "Failed to create ConvolveMatrix filter!";
942 hr
= aDC
->CreateEffect(CLSID_D2D1Border
, getter_AddRefs(mBorderEffect
));
944 if (FAILED(hr
) || !mBorderEffect
) {
945 gfxWarning() << "Failed to create ConvolveMatrix filter!";
949 mBorderEffect
->SetInputEffect(0, mExtendInputEffect
.get());
955 void FilterNodeConvolveD2D1::SetInput(uint32_t aIndex
, FilterNode
* aFilter
) {
956 FilterNodeD2D1::SetInput(aIndex
, aFilter
);
961 void FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, uint32_t aValue
) {
962 if (aIndex
!= ATT_CONVOLVE_MATRIX_EDGE_MODE
) {
963 return FilterNodeD2D1::SetAttribute(aIndex
, aValue
);
966 mEdgeMode
= (ConvolveMatrixEdgeMode
)aValue
;
971 ID2D1Effect
* FilterNodeConvolveD2D1::InputEffect() {
972 return mEdgeMode
== EDGE_MODE_NONE
? mEffect
.get() : mExtendInputEffect
.get();
975 void FilterNodeConvolveD2D1::UpdateChain() {
976 // The shape of the filter graph:
979 // input --> convolvematrix
981 // EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP:
982 // input --> extendinput --> border --> convolvematrix
984 // mEffect is convolvematrix.
986 if (mEdgeMode
!= EDGE_MODE_NONE
) {
987 mEffect
->SetInputEffect(0, mBorderEffect
.get());
990 RefPtr
<ID2D1Effect
> inputEffect
;
991 if (mInputFilters
.size() > 0 && mInputFilters
[0]) {
992 inputEffect
= mInputFilters
[0]->OutputEffect();
994 InputEffect()->SetInputEffect(0, inputEffect
);
996 if (mEdgeMode
== EDGE_MODE_DUPLICATE
) {
997 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X
,
998 D2D1_BORDER_EDGE_MODE_CLAMP
);
999 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y
,
1000 D2D1_BORDER_EDGE_MODE_CLAMP
);
1001 } else if (mEdgeMode
== EDGE_MODE_WRAP
) {
1002 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X
,
1003 D2D1_BORDER_EDGE_MODE_WRAP
);
1004 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y
,
1005 D2D1_BORDER_EDGE_MODE_WRAP
);
1009 void FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
,
1010 const IntSize
& aValue
) {
1011 if (aIndex
!= ATT_CONVOLVE_MATRIX_KERNEL_SIZE
) {
1016 mKernelSize
= aValue
;
1018 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X
, aValue
.width
);
1019 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y
, aValue
.height
);
1024 void FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
,
1025 const IntPoint
& aValue
) {
1026 if (aIndex
!= ATT_CONVOLVE_MATRIX_TARGET
) {
1036 void FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
,
1037 const IntRect
& aValue
) {
1038 if (aIndex
!= ATT_CONVOLVE_MATRIX_SOURCE_RECT
) {
1043 mSourceRect
= aValue
;
1048 void FilterNodeConvolveD2D1::UpdateOffset() {
1049 D2D1_VECTOR_2F vector
= D2D1::Vector2F(
1050 (Float(mKernelSize
.width
) - 1.0f
) / 2.0f
- Float(mTarget
.x
),
1051 (Float(mKernelSize
.height
) - 1.0f
) / 2.0f
- Float(mTarget
.y
));
1053 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET
, vector
);
1056 void FilterNodeConvolveD2D1::UpdateSourceRect() {
1057 mExtendInputEffect
->SetValue(
1058 EXTENDINPUT_PROP_OUTPUT_RECT
,
1059 D2D1::Vector4F(Float(mSourceRect
.X()), Float(mSourceRect
.Y()),
1060 Float(mSourceRect
.XMost()), Float(mSourceRect
.YMost())));
1063 FilterNodeExtendInputAdapterD2D1::FilterNodeExtendInputAdapterD2D1(
1064 ID2D1DeviceContext
* aDC
, FilterNodeD2D1
* aFilterNode
, FilterType aType
)
1065 : FilterNodeD2D1(aFilterNode
->MainEffect(), aType
),
1066 mWrappedFilterNode(aFilterNode
) {
1067 // We have an mEffect that looks at the bounds of the input effect, and we
1068 // want mEffect to regard its input as unbounded. So we take the input,
1069 // pipe it through an ExtendInput effect (which has an infinite output rect
1070 // by default), and feed the resulting unbounded composition into mEffect.
1074 hr
= aDC
->CreateEffect(CLSID_ExtendInputEffect
,
1075 getter_AddRefs(mExtendInputEffect
));
1077 if (FAILED(hr
) || !mExtendInputEffect
) {
1078 gfxWarning() << "Failed to create extend input effect for filter: "
1083 aFilterNode
->InputEffect()->SetInputEffect(0, mExtendInputEffect
.get());
1086 FilterNodePremultiplyAdapterD2D1::FilterNodePremultiplyAdapterD2D1(
1087 ID2D1DeviceContext
* aDC
, FilterNodeD2D1
* aFilterNode
, FilterType aType
)
1088 : FilterNodeD2D1(aFilterNode
->MainEffect(), aType
) {
1089 // D2D1 component transfer effects do strange things when it comes to
1090 // premultiplication.
1091 // For our purposes we only need the transfer filters to apply straight to
1092 // unpremultiplied source channels and output unpremultiplied results.
1093 // However, the D2D1 effects are designed differently: They can apply to both
1094 // premultiplied and unpremultiplied inputs, and they always premultiply
1095 // their result - at least in those color channels that have not been
1097 // In order to determine whether the input needs to be unpremultiplied as
1098 // part of the transfer, the effect consults the alpha mode metadata of the
1099 // input surface or the input effect. We don't have such a concept in Moz2D,
1100 // and giving Moz2D users different results based on something that cannot be
1101 // influenced through Moz2D APIs seems like a bad idea.
1102 // We solve this by applying a premultiply effect to the input before feeding
1103 // it into the transfer effect. The premultiply effect always premultiplies
1104 // regardless of any alpha mode metadata on inputs, and it always marks its
1105 // output as premultiplied so that the transfer effect will unpremultiply
1106 // consistently. Feeding always-premultiplied input into the transfer effect
1107 // also avoids another problem that would appear when individual color
1108 // channels disable the transfer: In that case, the disabled channels would
1109 // pass through unchanged in their unpremultiplied form and the other
1110 // channels would be premultiplied, giving a mixed result.
1111 // But since we now ensure that the input is premultiplied, disabled channels
1112 // will pass premultiplied values through to the result, which is consistent
1113 // with the enabled channels.
1114 // We also add an unpremultiply effect that postprocesses the result of the
1115 // transfer effect because getting unpremultiplied results from the transfer
1116 // filters is part of the FilterNode API.
1119 hr
= aDC
->CreateEffect(CLSID_D2D1Premultiply
,
1120 getter_AddRefs(mPrePremultiplyEffect
));
1122 if (FAILED(hr
) || !mPrePremultiplyEffect
) {
1123 gfxWarning() << "Failed to create ComponentTransfer filter!";
1127 hr
= aDC
->CreateEffect(CLSID_D2D1UnPremultiply
,
1128 getter_AddRefs(mPostUnpremultiplyEffect
));
1130 if (FAILED(hr
) || !mPostUnpremultiplyEffect
) {
1131 gfxWarning() << "Failed to create ComponentTransfer filter!";
1135 aFilterNode
->InputEffect()->SetInputEffect(0, mPrePremultiplyEffect
.get());
1136 mPostUnpremultiplyEffect
->SetInputEffect(0, aFilterNode
->OutputEffect());
1140 } // namespace mozilla