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"
10 #include "SourceSurfaceD2D1.h"
11 #include "SourceSurfaceD2D.h"
12 #include "SourceSurfaceD2DTarget.h"
13 #include "DrawTargetD2D.h"
14 #include "DrawTargetD2D1.h"
19 D2D1_COLORMATRIX_ALPHA_MODE
D2DAlphaMode(uint32_t 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
;
27 MOZ_CRASH("Unknown enum value!");
30 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED
;
33 D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE
D2DAffineTransformInterpolationMode(Filter aFilter
)
37 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
39 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
41 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR
;
43 MOZ_CRASH("Unknown enum value!");
46 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
49 D2D1_BLEND_MODE
D2DBlendMode(uint32_t 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
;
61 MOZ_CRASH("Unknown enum value!");
64 return D2D1_BLEND_MODE_DARKEN
;
67 D2D1_MORPHOLOGY_MODE
D2DMorphologyMode(uint32_t 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
)
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
)
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
)
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!");
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
);
141 MOZ_CRASH("Unknown draw target type!");
146 uint32_t ConvertValue(FilterType aType
, uint32_t aAttribute
, uint32_t aValue
)
149 case FilterType::COLOR_MATRIX
:
150 if (aAttribute
== ATT_COLOR_MATRIX_ALPHA_MODE
) {
151 aValue
= D2DAlphaMode(aValue
);
154 case FilterType::TRANSFORM
:
155 if (aAttribute
== ATT_TRANSFORM_FILTER
) {
156 aValue
= D2DAffineTransformInterpolationMode(Filter(aValue
));
159 case FilterType::BLEND
:
160 if (aAttribute
== ATT_BLEND_BLENDMODE
) {
161 aValue
= D2DBlendMode(aValue
);
164 case FilterType::MORPHOLOGY
:
165 if (aAttribute
== ATT_MORPHOLOGY_OPERATOR
) {
166 aValue
= D2DMorphologyMode(aValue
);
169 case FilterType::DISPLACEMENT_MAP
:
170 if (aAttribute
== ATT_DISPLACEMENT_MAP_X_CHANNEL
||
171 aAttribute
== ATT_DISPLACEMENT_MAP_Y_CHANNEL
) {
172 aValue
= D2DChannelSelector(aValue
);
175 case FilterType::TURBULENCE
:
176 if (aAttribute
== ATT_TURBULENCE_TYPE
) {
177 aValue
= D2DTurbulenceNoise(aValue
);
180 case FilterType::COMPOSITE
:
181 if (aAttribute
== ATT_COMPOSITE_OPERATOR
) {
182 aValue
= D2DFilterCompositionMode(aValue
);
190 void ConvertValue(FilterType aType
, uint32_t aAttribute
, IntSize
&aValue
)
193 case FilterType::MORPHOLOGY
:
194 if (aAttribute
== ATT_MORPHOLOGY_RADII
) {
205 GetD2D1InputForInput(FilterType aType
, uint32_t aIndex
)
210 #define CONVERT_PROP(moz2dname, d2dname) \
211 case ATT_##moz2dname: \
212 return D2D1_##d2dname
215 GetD2D1PropForAttribute(FilterType aType
, uint32_t aIndex
)
218 case FilterType::COLOR_MATRIX
:
220 CONVERT_PROP(COLOR_MATRIX_MATRIX
, COLORMATRIX_PROP_COLOR_MATRIX
);
221 CONVERT_PROP(COLOR_MATRIX_ALPHA_MODE
, COLORMATRIX_PROP_ALPHA_MODE
);
224 case FilterType::TRANSFORM
:
226 CONVERT_PROP(TRANSFORM_MATRIX
, 2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX
);
227 CONVERT_PROP(TRANSFORM_FILTER
, 2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE
);
229 case FilterType::BLEND
:
231 CONVERT_PROP(BLEND_BLENDMODE
, BLEND_PROP_MODE
);
234 case FilterType::MORPHOLOGY
:
236 CONVERT_PROP(MORPHOLOGY_OPERATOR
, MORPHOLOGY_PROP_MODE
);
239 case FilterType::FLOOD
:
241 CONVERT_PROP(FLOOD_COLOR
, FLOOD_PROP_COLOR
);
244 case FilterType::TILE
:
246 CONVERT_PROP(TILE_SOURCE_RECT
, TILE_PROP_RECT
);
249 case FilterType::TABLE_TRANSFER
:
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
);
261 case FilterType::DISCRETE_TRANSFER
:
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
);
273 case FilterType::LINEAR_TRANSFER
:
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
);
289 case FilterType::GAMMA_TRANSFER
:
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
);
309 case FilterType::CONVOLVE_MATRIX
:
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
:
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
);
324 case FilterType::TURBULENCE
:
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
);
333 case FilterType::ARITHMETIC_COMBINE
:
335 CONVERT_PROP(ARITHMETIC_COMBINE_COEFFICIENTS
, ARITHMETICCOMPOSITE_PROP_COEFFICIENTS
);
338 case FilterType::COMPOSITE
:
340 CONVERT_PROP(COMPOSITE_OPERATOR
, COMPOSITE_PROP_MODE
);
343 case FilterType::GAUSSIAN_BLUR
:
345 CONVERT_PROP(GAUSSIAN_BLUR_STD_DEVIATION
, GAUSSIANBLUR_PROP_STANDARD_DEVIATION
);
348 case FilterType::DIRECTIONAL_BLUR
:
350 CONVERT_PROP(DIRECTIONAL_BLUR_STD_DEVIATION
, DIRECTIONALBLUR_PROP_STANDARD_DEVIATION
);
351 CONVERT_PROP(DIRECTIONAL_BLUR_DIRECTION
, DIRECTIONALBLUR_PROP_ANGLE
);
354 case FilterType::POINT_DIFFUSE
:
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
);
363 case FilterType::SPOT_DIFFUSE
:
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
);
375 case FilterType::DISTANT_DIFFUSE
:
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
);
385 case FilterType::POINT_SPECULAR
:
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
);
395 case FilterType::SPOT_SPECULAR
:
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
);
408 case FilterType::DISTANT_SPECULAR
:
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
);
419 case FilterType::CROP
:
421 CONVERT_PROP(CROP_RECT
, CROP_PROP_RECT
);
430 GetD2D1PropsForIntSize(FilterType aType
, uint32_t aIndex
, UINT32
*aPropWidth
, UINT32
*aPropHeight
)
433 case FilterType::MORPHOLOGY
:
434 if (aIndex
== ATT_MORPHOLOGY_RADII
) {
435 *aPropWidth
= D2D1_MORPHOLOGY_PROP_WIDTH
;
436 *aPropHeight
= D2D1_MORPHOLOGY_PROP_HEIGHT
;
444 static inline REFCLSID
GetCLDIDForFilterType(FilterType 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
;
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
;
512 hr
= aDC
->CreateEffect(GetCLDIDForFilterType(aType
), byRef(effect
));
515 gfxWarning() << "Failed to create effect for FilterType: " << hr
;
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
);
526 return new FilterNodeD2D1(aDT
, effect
, aType
);
531 FilterNodeD2D1::InitUnmappedProperties()
534 case FilterType::TRANSFORM
:
535 mEffect
->SetValue(D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE
, D2D1_BORDER_MODE_HARD
);
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
);
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.";
587 effect
->SetInputEffect(input
, static_cast<FilterNodeD2D1
*>(aFilter
)->OutputEffect());
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
)));
599 } else if (mType
== FilterType::DIRECTIONAL_BLUR
&& aIndex
== ATT_DIRECTIONAL_BLUR_DIRECTION
) {
600 mEffect
->SetValue(input
, aValue
== BLUR_DIRECTION_X
? 0 : 90.0f
);
604 mEffect
->SetValue(input
, ConvertValue(mType
, aIndex
, aValue
));
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
);
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
));
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
));
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
));
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
));
653 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const IntSize
&aValue
)
655 UINT32 widthProp
, heightProp
;
657 if (!GetD2D1PropsForIntSize(mType
, aIndex
, &widthProp
, &heightProp
)) {
661 IntSize value
= aValue
;
662 ConvertValue(mType
, aIndex
, value
);
664 mEffect
->SetValue(widthProp
, (UINT
)value
.width
);
665 mEffect
->SetValue(heightProp
, (UINT
)value
.height
);
669 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Color
&aValue
)
671 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
672 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
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
));
684 mEffect
->SetValue(input
, D2D1::Vector4F(aValue
.r
* aValue
.a
, aValue
.g
* aValue
.a
, aValue
.b
* aValue
.a
, aValue
.a
));
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
));
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
)));
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())));
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
);
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
);
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
));
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().
776 hr
= aDC
->CreateEffect(CLSID_D2D1ConvolveMatrix
, byRef(mEffect
));
779 gfxWarning() << "Failed to create ConvolveMatrix filter!";
783 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE
, D2D1_BORDER_MODE_SOFT
);
785 hr
= aDC
->CreateEffect(CLSID_D2D1Flood
, byRef(mFloodEffect
));
788 gfxWarning() << "Failed to create ConvolveMatrix filter!";
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
));
797 gfxWarning() << "Failed to create ConvolveMatrix filter!";
801 mCompositeEffect
->SetInputEffect(1, mFloodEffect
.get());
803 hr
= aDC
->CreateEffect(CLSID_D2D1Crop
, byRef(mCropEffect
));
806 gfxWarning() << "Failed to create ConvolveMatrix filter!";
810 mCropEffect
->SetInputEffect(0, mCompositeEffect
.get());
812 hr
= aDC
->CreateEffect(CLSID_D2D1Border
, byRef(mBorderEffect
));
815 gfxWarning() << "Failed to create ConvolveMatrix filter!";
819 mBorderEffect
->SetInputEffect(0, mCropEffect
.get());
826 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex
, SourceSurface
*aSurface
)
828 MOZ_ASSERT(aIndex
== 0);
830 mInput
= GetImageForSourceSurface(mDT
, aSurface
);
832 mInputEffect
= nullptr;
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.";
849 mInputEffect
= static_cast<FilterNodeD2D1
*>(aFilter
)->mEffect
;
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
;
867 FilterNodeConvolveD2D1::UpdateChain()
869 // The shape of the filter graph:
872 // input --> convolvematrix
874 // EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP:
876 // flood --> composite --> crop --> border --> convolvematrix
878 ID2D1Effect
*firstEffect
= mCompositeEffect
;
879 if (mEdgeMode
== EDGE_MODE_NONE
) {
880 firstEffect
= mEffect
;
882 mEffect
->SetInputEffect(0, mBorderEffect
.get());
886 firstEffect
->SetInputEffect(0, mInputEffect
);
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
);
901 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, const IntSize
&aValue
)
903 if (aIndex
!= ATT_CONVOLVE_MATRIX_KERNEL_SIZE
) {
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
);
917 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, const IntPoint
&aValue
)
919 if (aIndex
!= ATT_CONVOLVE_MATRIX_TARGET
) {
930 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, const IntRect
&aValue
)
932 if (aIndex
!= ATT_CONVOLVE_MATRIX_SOURCE_RECT
) {
937 mSourceRect
= aValue
;
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
);
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
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.
994 hr
= aDC
->CreateEffect(CLSID_D2D1Premultiply
, byRef(mPrePremultiplyEffect
));
997 gfxWarning() << "Failed to create ComponentTransfer filter!";
1001 hr
= aDC
->CreateEffect(CLSID_D2D1UnPremultiply
, byRef(mPostUnpremultiplyEffect
));
1004 gfxWarning() << "Failed to create ComponentTransfer filter!";
1008 mEffect
->SetInputEffect(0, mPrePremultiplyEffect
.get());
1009 mPostUnpremultiplyEffect
->SetInputEffect(0, mEffect
.get());