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
)
21 case ALPHA_MODE_PREMULTIPLIED
:
22 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED
;
23 case ALPHA_MODE_STRAIGHT
:
24 return D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT
;
26 MOZ_CRASH("GFX: Unknown enum value D2DAlphaMode!");
29 return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED
;
32 D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE
D2DAffineTransformInterpolationMode(SamplingFilter aSamplingFilter
)
34 switch (aSamplingFilter
) {
35 case SamplingFilter::GOOD
:
36 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
37 case SamplingFilter::LINEAR
:
38 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
39 case SamplingFilter::POINT
:
40 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR
;
42 MOZ_CRASH("GFX: Unknown enum value D2DAffineTIM!");
45 return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR
;
48 D2D1_BLEND_MODE
D2DBlendMode(uint32_t aMode
)
51 case BLEND_MODE_DARKEN
:
52 return D2D1_BLEND_MODE_DARKEN
;
53 case BLEND_MODE_LIGHTEN
:
54 return D2D1_BLEND_MODE_LIGHTEN
;
55 case BLEND_MODE_MULTIPLY
:
56 return D2D1_BLEND_MODE_MULTIPLY
;
57 case BLEND_MODE_SCREEN
:
58 return D2D1_BLEND_MODE_SCREEN
;
59 case BLEND_MODE_OVERLAY
:
60 return D2D1_BLEND_MODE_OVERLAY
;
61 case BLEND_MODE_COLOR_DODGE
:
62 return D2D1_BLEND_MODE_COLOR_DODGE
;
63 case BLEND_MODE_COLOR_BURN
:
64 return D2D1_BLEND_MODE_COLOR_BURN
;
65 case BLEND_MODE_HARD_LIGHT
:
66 return D2D1_BLEND_MODE_HARD_LIGHT
;
67 case BLEND_MODE_SOFT_LIGHT
:
68 return D2D1_BLEND_MODE_SOFT_LIGHT
;
69 case BLEND_MODE_DIFFERENCE
:
70 return D2D1_BLEND_MODE_DIFFERENCE
;
71 case BLEND_MODE_EXCLUSION
:
72 return D2D1_BLEND_MODE_EXCLUSION
;
74 return D2D1_BLEND_MODE_HUE
;
75 case BLEND_MODE_SATURATION
:
76 return D2D1_BLEND_MODE_SATURATION
;
77 case BLEND_MODE_COLOR
:
78 return D2D1_BLEND_MODE_COLOR
;
79 case BLEND_MODE_LUMINOSITY
:
80 return D2D1_BLEND_MODE_LUMINOSITY
;
83 MOZ_CRASH("GFX: Unknown enum value D2DBlendMode!");
86 return D2D1_BLEND_MODE_DARKEN
;
89 D2D1_MORPHOLOGY_MODE
D2DMorphologyMode(uint32_t aMode
)
92 case MORPHOLOGY_OPERATOR_DILATE
:
93 return D2D1_MORPHOLOGY_MODE_DILATE
;
94 case MORPHOLOGY_OPERATOR_ERODE
:
95 return D2D1_MORPHOLOGY_MODE_ERODE
;
98 MOZ_CRASH("GFX: Unknown enum value D2DMorphologyMode!");
99 return D2D1_MORPHOLOGY_MODE_DILATE
;
102 D2D1_TURBULENCE_NOISE
D2DTurbulenceNoise(uint32_t aMode
)
105 case TURBULENCE_TYPE_FRACTAL_NOISE
:
106 return D2D1_TURBULENCE_NOISE_FRACTAL_SUM
;
107 case TURBULENCE_TYPE_TURBULENCE
:
108 return D2D1_TURBULENCE_NOISE_TURBULENCE
;
111 MOZ_CRASH("GFX: Unknown enum value D2DTurbulenceNoise!");
112 return D2D1_TURBULENCE_NOISE_TURBULENCE
;
115 D2D1_COMPOSITE_MODE
D2DFilterCompositionMode(uint32_t aMode
)
118 case COMPOSITE_OPERATOR_OVER
:
119 return D2D1_COMPOSITE_MODE_SOURCE_OVER
;
120 case COMPOSITE_OPERATOR_IN
:
121 return D2D1_COMPOSITE_MODE_SOURCE_IN
;
122 case COMPOSITE_OPERATOR_OUT
:
123 return D2D1_COMPOSITE_MODE_SOURCE_OUT
;
124 case COMPOSITE_OPERATOR_ATOP
:
125 return D2D1_COMPOSITE_MODE_SOURCE_ATOP
;
126 case COMPOSITE_OPERATOR_XOR
:
127 return D2D1_COMPOSITE_MODE_XOR
;
130 MOZ_CRASH("GFX: Unknown enum value D2DFilterCompositionMode!");
131 return D2D1_COMPOSITE_MODE_SOURCE_OVER
;
134 D2D1_CHANNEL_SELECTOR
D2DChannelSelector(uint32_t aMode
)
137 case COLOR_CHANNEL_R
:
138 return D2D1_CHANNEL_SELECTOR_R
;
139 case COLOR_CHANNEL_G
:
140 return D2D1_CHANNEL_SELECTOR_G
;
141 case COLOR_CHANNEL_B
:
142 return D2D1_CHANNEL_SELECTOR_B
;
143 case COLOR_CHANNEL_A
:
144 return D2D1_CHANNEL_SELECTOR_A
;
147 MOZ_CRASH("GFX: Unknown enum value D2DChannelSelector!");
148 return D2D1_CHANNEL_SELECTOR_R
;
151 already_AddRefed
<ID2D1Image
> GetImageForSourceSurface(DrawTarget
*aDT
, SourceSurface
*aSurface
)
153 if (aDT
->IsTiledDrawTarget() || aDT
->IsDualDrawTarget() || aDT
->IsCaptureDT()) {
154 gfxDevCrash(LogReason::FilterNodeD2D1Target
) << "Incompatible draw target type! " << (int)aDT
->IsTiledDrawTarget() << " " << (int)aDT
->IsDualDrawTarget();
157 switch (aDT
->GetBackendType()) {
158 case BackendType::DIRECT2D1_1
:
159 return static_cast<DrawTargetD2D1
*>(aDT
)->GetImageForSurface(aSurface
, ExtendMode::CLAMP
);
161 gfxDevCrash(LogReason::FilterNodeD2D1Backend
) << "Unknown draw target type! " << (int)aDT
->GetBackendType();
166 uint32_t ConvertValue(FilterType aType
, uint32_t aAttribute
, uint32_t aValue
)
169 case FilterType::COLOR_MATRIX
:
170 if (aAttribute
== ATT_COLOR_MATRIX_ALPHA_MODE
) {
171 aValue
= D2DAlphaMode(aValue
);
174 case FilterType::TRANSFORM
:
175 if (aAttribute
== ATT_TRANSFORM_FILTER
) {
176 aValue
= D2DAffineTransformInterpolationMode(SamplingFilter(aValue
));
179 case FilterType::BLEND
:
180 if (aAttribute
== ATT_BLEND_BLENDMODE
) {
181 aValue
= D2DBlendMode(aValue
);
184 case FilterType::MORPHOLOGY
:
185 if (aAttribute
== ATT_MORPHOLOGY_OPERATOR
) {
186 aValue
= D2DMorphologyMode(aValue
);
189 case FilterType::DISPLACEMENT_MAP
:
190 if (aAttribute
== ATT_DISPLACEMENT_MAP_X_CHANNEL
||
191 aAttribute
== ATT_DISPLACEMENT_MAP_Y_CHANNEL
) {
192 aValue
= D2DChannelSelector(aValue
);
195 case FilterType::TURBULENCE
:
196 if (aAttribute
== ATT_TURBULENCE_TYPE
) {
197 aValue
= D2DTurbulenceNoise(aValue
);
200 case FilterType::COMPOSITE
:
201 if (aAttribute
== ATT_COMPOSITE_OPERATOR
) {
202 aValue
= D2DFilterCompositionMode(aValue
);
212 void ConvertValue(FilterType aType
, uint32_t aAttribute
, IntSize
&aValue
)
215 case FilterType::MORPHOLOGY
:
216 if (aAttribute
== ATT_MORPHOLOGY_RADII
) {
229 GetD2D1InputForInput(FilterType aType
, uint32_t aIndex
)
234 #define CONVERT_PROP(moz2dname, d2dname) \
235 case ATT_##moz2dname: \
236 return D2D1_##d2dname
239 GetD2D1PropForAttribute(FilterType aType
, uint32_t aIndex
)
242 case FilterType::COLOR_MATRIX
:
244 CONVERT_PROP(COLOR_MATRIX_MATRIX
, COLORMATRIX_PROP_COLOR_MATRIX
);
245 CONVERT_PROP(COLOR_MATRIX_ALPHA_MODE
, COLORMATRIX_PROP_ALPHA_MODE
);
248 case FilterType::TRANSFORM
:
250 CONVERT_PROP(TRANSFORM_MATRIX
, 2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX
);
251 CONVERT_PROP(TRANSFORM_FILTER
, 2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE
);
253 case FilterType::BLEND
:
255 CONVERT_PROP(BLEND_BLENDMODE
, BLEND_PROP_MODE
);
258 case FilterType::MORPHOLOGY
:
260 CONVERT_PROP(MORPHOLOGY_OPERATOR
, MORPHOLOGY_PROP_MODE
);
263 case FilterType::FLOOD
:
265 CONVERT_PROP(FLOOD_COLOR
, FLOOD_PROP_COLOR
);
268 case FilterType::TILE
:
270 CONVERT_PROP(TILE_SOURCE_RECT
, TILE_PROP_RECT
);
273 case FilterType::TABLE_TRANSFER
:
275 CONVERT_PROP(TABLE_TRANSFER_DISABLE_R
, TABLETRANSFER_PROP_RED_DISABLE
);
276 CONVERT_PROP(TABLE_TRANSFER_DISABLE_G
, TABLETRANSFER_PROP_GREEN_DISABLE
);
277 CONVERT_PROP(TABLE_TRANSFER_DISABLE_B
, TABLETRANSFER_PROP_BLUE_DISABLE
);
278 CONVERT_PROP(TABLE_TRANSFER_DISABLE_A
, TABLETRANSFER_PROP_ALPHA_DISABLE
);
279 CONVERT_PROP(TABLE_TRANSFER_TABLE_R
, TABLETRANSFER_PROP_RED_TABLE
);
280 CONVERT_PROP(TABLE_TRANSFER_TABLE_G
, TABLETRANSFER_PROP_GREEN_TABLE
);
281 CONVERT_PROP(TABLE_TRANSFER_TABLE_B
, TABLETRANSFER_PROP_BLUE_TABLE
);
282 CONVERT_PROP(TABLE_TRANSFER_TABLE_A
, TABLETRANSFER_PROP_ALPHA_TABLE
);
285 case FilterType::DISCRETE_TRANSFER
:
287 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_R
, DISCRETETRANSFER_PROP_RED_DISABLE
);
288 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_G
, DISCRETETRANSFER_PROP_GREEN_DISABLE
);
289 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_B
, DISCRETETRANSFER_PROP_BLUE_DISABLE
);
290 CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_A
, DISCRETETRANSFER_PROP_ALPHA_DISABLE
);
291 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_R
, DISCRETETRANSFER_PROP_RED_TABLE
);
292 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_G
, DISCRETETRANSFER_PROP_GREEN_TABLE
);
293 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_B
, DISCRETETRANSFER_PROP_BLUE_TABLE
);
294 CONVERT_PROP(DISCRETE_TRANSFER_TABLE_A
, DISCRETETRANSFER_PROP_ALPHA_TABLE
);
297 case FilterType::LINEAR_TRANSFER
:
299 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_R
, LINEARTRANSFER_PROP_RED_DISABLE
);
300 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_G
, LINEARTRANSFER_PROP_GREEN_DISABLE
);
301 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_B
, LINEARTRANSFER_PROP_BLUE_DISABLE
);
302 CONVERT_PROP(LINEAR_TRANSFER_DISABLE_A
, LINEARTRANSFER_PROP_ALPHA_DISABLE
);
303 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_R
, LINEARTRANSFER_PROP_RED_Y_INTERCEPT
);
304 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_G
, LINEARTRANSFER_PROP_GREEN_Y_INTERCEPT
);
305 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_B
, LINEARTRANSFER_PROP_BLUE_Y_INTERCEPT
);
306 CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_A
, LINEARTRANSFER_PROP_ALPHA_Y_INTERCEPT
);
307 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_R
, LINEARTRANSFER_PROP_RED_SLOPE
);
308 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_G
, LINEARTRANSFER_PROP_GREEN_SLOPE
);
309 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_B
, LINEARTRANSFER_PROP_BLUE_SLOPE
);
310 CONVERT_PROP(LINEAR_TRANSFER_SLOPE_A
, LINEARTRANSFER_PROP_ALPHA_SLOPE
);
313 case FilterType::GAMMA_TRANSFER
:
315 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_R
, GAMMATRANSFER_PROP_RED_DISABLE
);
316 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_G
, GAMMATRANSFER_PROP_GREEN_DISABLE
);
317 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_B
, GAMMATRANSFER_PROP_BLUE_DISABLE
);
318 CONVERT_PROP(GAMMA_TRANSFER_DISABLE_A
, GAMMATRANSFER_PROP_ALPHA_DISABLE
);
319 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_R
, GAMMATRANSFER_PROP_RED_AMPLITUDE
);
320 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_G
, GAMMATRANSFER_PROP_GREEN_AMPLITUDE
);
321 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_B
, GAMMATRANSFER_PROP_BLUE_AMPLITUDE
);
322 CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_A
, GAMMATRANSFER_PROP_ALPHA_AMPLITUDE
);
323 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_R
, GAMMATRANSFER_PROP_RED_EXPONENT
);
324 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_G
, GAMMATRANSFER_PROP_GREEN_EXPONENT
);
325 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_B
, GAMMATRANSFER_PROP_BLUE_EXPONENT
);
326 CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_A
, GAMMATRANSFER_PROP_ALPHA_EXPONENT
);
327 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_R
, GAMMATRANSFER_PROP_RED_OFFSET
);
328 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_G
, GAMMATRANSFER_PROP_GREEN_OFFSET
);
329 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_B
, GAMMATRANSFER_PROP_BLUE_OFFSET
);
330 CONVERT_PROP(GAMMA_TRANSFER_OFFSET_A
, GAMMATRANSFER_PROP_ALPHA_OFFSET
);
333 case FilterType::CONVOLVE_MATRIX
:
335 CONVERT_PROP(CONVOLVE_MATRIX_BIAS
, CONVOLVEMATRIX_PROP_BIAS
);
336 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_MATRIX
, CONVOLVEMATRIX_PROP_KERNEL_MATRIX
);
337 CONVERT_PROP(CONVOLVE_MATRIX_DIVISOR
, CONVOLVEMATRIX_PROP_DIVISOR
);
338 CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH
, CONVOLVEMATRIX_PROP_KERNEL_UNIT_LENGTH
);
339 CONVERT_PROP(CONVOLVE_MATRIX_PRESERVE_ALPHA
, CONVOLVEMATRIX_PROP_PRESERVE_ALPHA
);
341 case FilterType::DISPLACEMENT_MAP
:
343 CONVERT_PROP(DISPLACEMENT_MAP_SCALE
, DISPLACEMENTMAP_PROP_SCALE
);
344 CONVERT_PROP(DISPLACEMENT_MAP_X_CHANNEL
, DISPLACEMENTMAP_PROP_X_CHANNEL_SELECT
);
345 CONVERT_PROP(DISPLACEMENT_MAP_Y_CHANNEL
, DISPLACEMENTMAP_PROP_Y_CHANNEL_SELECT
);
348 case FilterType::TURBULENCE
:
350 CONVERT_PROP(TURBULENCE_BASE_FREQUENCY
, TURBULENCE_PROP_BASE_FREQUENCY
);
351 CONVERT_PROP(TURBULENCE_NUM_OCTAVES
, TURBULENCE_PROP_NUM_OCTAVES
);
352 CONVERT_PROP(TURBULENCE_SEED
, TURBULENCE_PROP_SEED
);
353 CONVERT_PROP(TURBULENCE_STITCHABLE
, TURBULENCE_PROP_STITCHABLE
);
354 CONVERT_PROP(TURBULENCE_TYPE
, TURBULENCE_PROP_NOISE
);
357 case FilterType::ARITHMETIC_COMBINE
:
359 CONVERT_PROP(ARITHMETIC_COMBINE_COEFFICIENTS
, ARITHMETICCOMPOSITE_PROP_COEFFICIENTS
);
362 case FilterType::COMPOSITE
:
364 CONVERT_PROP(COMPOSITE_OPERATOR
, COMPOSITE_PROP_MODE
);
367 case FilterType::GAUSSIAN_BLUR
:
369 CONVERT_PROP(GAUSSIAN_BLUR_STD_DEVIATION
, GAUSSIANBLUR_PROP_STANDARD_DEVIATION
);
372 case FilterType::DIRECTIONAL_BLUR
:
374 CONVERT_PROP(DIRECTIONAL_BLUR_STD_DEVIATION
, DIRECTIONALBLUR_PROP_STANDARD_DEVIATION
);
375 CONVERT_PROP(DIRECTIONAL_BLUR_DIRECTION
, DIRECTIONALBLUR_PROP_ANGLE
);
378 case FilterType::POINT_DIFFUSE
:
380 CONVERT_PROP(POINT_DIFFUSE_DIFFUSE_CONSTANT
, POINTDIFFUSE_PROP_DIFFUSE_CONSTANT
);
381 CONVERT_PROP(POINT_DIFFUSE_POSITION
, POINTDIFFUSE_PROP_LIGHT_POSITION
);
382 CONVERT_PROP(POINT_DIFFUSE_COLOR
, POINTDIFFUSE_PROP_COLOR
);
383 CONVERT_PROP(POINT_DIFFUSE_SURFACE_SCALE
, POINTDIFFUSE_PROP_SURFACE_SCALE
);
384 CONVERT_PROP(POINT_DIFFUSE_KERNEL_UNIT_LENGTH
, POINTDIFFUSE_PROP_KERNEL_UNIT_LENGTH
);
387 case FilterType::SPOT_DIFFUSE
:
389 CONVERT_PROP(SPOT_DIFFUSE_DIFFUSE_CONSTANT
, SPOTDIFFUSE_PROP_DIFFUSE_CONSTANT
);
390 CONVERT_PROP(SPOT_DIFFUSE_POINTS_AT
, SPOTDIFFUSE_PROP_POINTS_AT
);
391 CONVERT_PROP(SPOT_DIFFUSE_FOCUS
, SPOTDIFFUSE_PROP_FOCUS
);
392 CONVERT_PROP(SPOT_DIFFUSE_LIMITING_CONE_ANGLE
, SPOTDIFFUSE_PROP_LIMITING_CONE_ANGLE
);
393 CONVERT_PROP(SPOT_DIFFUSE_POSITION
, SPOTDIFFUSE_PROP_LIGHT_POSITION
);
394 CONVERT_PROP(SPOT_DIFFUSE_COLOR
, SPOTDIFFUSE_PROP_COLOR
);
395 CONVERT_PROP(SPOT_DIFFUSE_SURFACE_SCALE
, SPOTDIFFUSE_PROP_SURFACE_SCALE
);
396 CONVERT_PROP(SPOT_DIFFUSE_KERNEL_UNIT_LENGTH
, SPOTDIFFUSE_PROP_KERNEL_UNIT_LENGTH
);
399 case FilterType::DISTANT_DIFFUSE
:
401 CONVERT_PROP(DISTANT_DIFFUSE_DIFFUSE_CONSTANT
, DISTANTDIFFUSE_PROP_DIFFUSE_CONSTANT
);
402 CONVERT_PROP(DISTANT_DIFFUSE_AZIMUTH
, DISTANTDIFFUSE_PROP_AZIMUTH
);
403 CONVERT_PROP(DISTANT_DIFFUSE_ELEVATION
, DISTANTDIFFUSE_PROP_ELEVATION
);
404 CONVERT_PROP(DISTANT_DIFFUSE_COLOR
, DISTANTDIFFUSE_PROP_COLOR
);
405 CONVERT_PROP(DISTANT_DIFFUSE_SURFACE_SCALE
, DISTANTDIFFUSE_PROP_SURFACE_SCALE
);
406 CONVERT_PROP(DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH
, DISTANTDIFFUSE_PROP_KERNEL_UNIT_LENGTH
);
409 case FilterType::POINT_SPECULAR
:
411 CONVERT_PROP(POINT_SPECULAR_SPECULAR_CONSTANT
, POINTSPECULAR_PROP_SPECULAR_CONSTANT
);
412 CONVERT_PROP(POINT_SPECULAR_SPECULAR_EXPONENT
, POINTSPECULAR_PROP_SPECULAR_EXPONENT
);
413 CONVERT_PROP(POINT_SPECULAR_POSITION
, POINTSPECULAR_PROP_LIGHT_POSITION
);
414 CONVERT_PROP(POINT_SPECULAR_COLOR
, POINTSPECULAR_PROP_COLOR
);
415 CONVERT_PROP(POINT_SPECULAR_SURFACE_SCALE
, POINTSPECULAR_PROP_SURFACE_SCALE
);
416 CONVERT_PROP(POINT_SPECULAR_KERNEL_UNIT_LENGTH
, POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH
);
419 case FilterType::SPOT_SPECULAR
:
421 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_CONSTANT
, SPOTSPECULAR_PROP_SPECULAR_CONSTANT
);
422 CONVERT_PROP(SPOT_SPECULAR_SPECULAR_EXPONENT
, SPOTSPECULAR_PROP_SPECULAR_EXPONENT
);
423 CONVERT_PROP(SPOT_SPECULAR_POINTS_AT
, SPOTSPECULAR_PROP_POINTS_AT
);
424 CONVERT_PROP(SPOT_SPECULAR_FOCUS
, SPOTSPECULAR_PROP_FOCUS
);
425 CONVERT_PROP(SPOT_SPECULAR_LIMITING_CONE_ANGLE
, SPOTSPECULAR_PROP_LIMITING_CONE_ANGLE
);
426 CONVERT_PROP(SPOT_SPECULAR_POSITION
, SPOTSPECULAR_PROP_LIGHT_POSITION
);
427 CONVERT_PROP(SPOT_SPECULAR_COLOR
, SPOTSPECULAR_PROP_COLOR
);
428 CONVERT_PROP(SPOT_SPECULAR_SURFACE_SCALE
, SPOTSPECULAR_PROP_SURFACE_SCALE
);
429 CONVERT_PROP(SPOT_SPECULAR_KERNEL_UNIT_LENGTH
, SPOTSPECULAR_PROP_KERNEL_UNIT_LENGTH
);
432 case FilterType::DISTANT_SPECULAR
:
434 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_CONSTANT
, DISTANTSPECULAR_PROP_SPECULAR_CONSTANT
);
435 CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_EXPONENT
, DISTANTSPECULAR_PROP_SPECULAR_EXPONENT
);
436 CONVERT_PROP(DISTANT_SPECULAR_AZIMUTH
, DISTANTSPECULAR_PROP_AZIMUTH
);
437 CONVERT_PROP(DISTANT_SPECULAR_ELEVATION
, DISTANTSPECULAR_PROP_ELEVATION
);
438 CONVERT_PROP(DISTANT_SPECULAR_COLOR
, DISTANTSPECULAR_PROP_COLOR
);
439 CONVERT_PROP(DISTANT_SPECULAR_SURFACE_SCALE
, DISTANTSPECULAR_PROP_SURFACE_SCALE
);
440 CONVERT_PROP(DISTANT_SPECULAR_KERNEL_UNIT_LENGTH
, DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH
);
443 case FilterType::CROP
:
445 CONVERT_PROP(CROP_RECT
, CROP_PROP_RECT
);
456 GetD2D1PropsForIntSize(FilterType aType
, uint32_t aIndex
, UINT32
*aPropWidth
, UINT32
*aPropHeight
)
459 case FilterType::MORPHOLOGY
:
460 if (aIndex
== ATT_MORPHOLOGY_RADII
) {
461 *aPropWidth
= D2D1_MORPHOLOGY_PROP_WIDTH
;
462 *aPropHeight
= D2D1_MORPHOLOGY_PROP_HEIGHT
;
472 static inline REFCLSID
GetCLDIDForFilterType(FilterType aType
)
475 case FilterType::COLOR_MATRIX
:
476 return CLSID_D2D1ColorMatrix
;
477 case FilterType::TRANSFORM
:
478 return CLSID_D2D12DAffineTransform
;
479 case FilterType::BLEND
:
480 return CLSID_D2D1Blend
;
481 case FilterType::MORPHOLOGY
:
482 return CLSID_D2D1Morphology
;
483 case FilterType::FLOOD
:
484 return CLSID_D2D1Flood
;
485 case FilterType::TILE
:
486 return CLSID_D2D1Tile
;
487 case FilterType::TABLE_TRANSFER
:
488 return CLSID_D2D1TableTransfer
;
489 case FilterType::LINEAR_TRANSFER
:
490 return CLSID_D2D1LinearTransfer
;
491 case FilterType::DISCRETE_TRANSFER
:
492 return CLSID_D2D1DiscreteTransfer
;
493 case FilterType::GAMMA_TRANSFER
:
494 return CLSID_D2D1GammaTransfer
;
495 case FilterType::DISPLACEMENT_MAP
:
496 return CLSID_D2D1DisplacementMap
;
497 case FilterType::TURBULENCE
:
498 return CLSID_D2D1Turbulence
;
499 case FilterType::ARITHMETIC_COMBINE
:
500 return CLSID_D2D1ArithmeticComposite
;
501 case FilterType::COMPOSITE
:
502 return CLSID_D2D1Composite
;
503 case FilterType::GAUSSIAN_BLUR
:
504 return CLSID_D2D1GaussianBlur
;
505 case FilterType::DIRECTIONAL_BLUR
:
506 return CLSID_D2D1DirectionalBlur
;
507 case FilterType::POINT_DIFFUSE
:
508 return CLSID_D2D1PointDiffuse
;
509 case FilterType::POINT_SPECULAR
:
510 return CLSID_D2D1PointSpecular
;
511 case FilterType::SPOT_DIFFUSE
:
512 return CLSID_D2D1SpotDiffuse
;
513 case FilterType::SPOT_SPECULAR
:
514 return CLSID_D2D1SpotSpecular
;
515 case FilterType::DISTANT_DIFFUSE
:
516 return CLSID_D2D1DistantDiffuse
;
517 case FilterType::DISTANT_SPECULAR
:
518 return CLSID_D2D1DistantSpecular
;
519 case FilterType::CROP
:
520 return CLSID_D2D1Crop
;
521 case FilterType::PREMULTIPLY
:
522 return CLSID_D2D1Premultiply
;
523 case FilterType::UNPREMULTIPLY
:
524 return CLSID_D2D1UnPremultiply
;
532 IsTransferFilterType(FilterType aType
)
535 case FilterType::LINEAR_TRANSFER
:
536 case FilterType::GAMMA_TRANSFER
:
537 case FilterType::TABLE_TRANSFER
:
538 case FilterType::DISCRETE_TRANSFER
:
546 HasUnboundedOutputRegion(FilterType aType
)
548 if (IsTransferFilterType(aType
)) {
553 case FilterType::COLOR_MATRIX
:
554 case FilterType::POINT_DIFFUSE
:
555 case FilterType::SPOT_DIFFUSE
:
556 case FilterType::DISTANT_DIFFUSE
:
557 case FilterType::POINT_SPECULAR
:
558 case FilterType::SPOT_SPECULAR
:
559 case FilterType::DISTANT_SPECULAR
:
567 already_AddRefed
<FilterNode
>
568 FilterNodeD2D1::Create(ID2D1DeviceContext
*aDC
, FilterType aType
)
570 if (aType
== FilterType::CONVOLVE_MATRIX
) {
571 return MakeAndAddRef
<FilterNodeConvolveD2D1
>(aDC
);
574 RefPtr
<ID2D1Effect
> effect
;
577 hr
= aDC
->CreateEffect(GetCLDIDForFilterType(aType
), getter_AddRefs(effect
));
579 if (FAILED(hr
) || !effect
) {
580 gfxCriticalErrorOnce() << "Failed to create effect for FilterType: " << hexa(hr
);
584 if (aType
== FilterType::ARITHMETIC_COMBINE
) {
585 effect
->SetValue(D2D1_ARITHMETICCOMPOSITE_PROP_CLAMP_OUTPUT
, TRUE
);
588 RefPtr
<FilterNodeD2D1
> filter
= new FilterNodeD2D1(effect
, aType
);
590 if (HasUnboundedOutputRegion(aType
)) {
591 // These filters can produce non-transparent output from transparent
592 // input pixels, and we want them to have an unbounded output region.
593 filter
= new FilterNodeExtendInputAdapterD2D1(aDC
, filter
, aType
);
596 if (IsTransferFilterType(aType
)) {
597 // Component transfer filters should appear to apply on unpremultiplied
598 // colors, but the D2D1 effects apply on premultiplied colors.
599 filter
= new FilterNodePremultiplyAdapterD2D1(aDC
, filter
, aType
);
602 return filter
.forget();
606 FilterNodeD2D1::InitUnmappedProperties()
609 case FilterType::TRANSFORM
:
610 mEffect
->SetValue(D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE
, D2D1_BORDER_MODE_HARD
);
618 FilterNodeD2D1::SetInput(uint32_t aIndex
, SourceSurface
*aSurface
)
620 UINT32 input
= GetD2D1InputForInput(mType
, aIndex
);
621 ID2D1Effect
* effect
= InputEffect();
622 MOZ_ASSERT(input
< effect
->GetInputCount());
624 if (mType
== FilterType::COMPOSITE
) {
625 UINT32 inputCount
= effect
->GetInputCount();
627 if (aIndex
== inputCount
- 1 && aSurface
== nullptr) {
628 effect
->SetInputCount(inputCount
- 1);
629 } else if (aIndex
>= inputCount
&& aSurface
) {
630 effect
->SetInputCount(aIndex
+ 1);
634 MOZ_ASSERT(input
< effect
->GetInputCount());
636 mInputSurfaces
.resize(effect
->GetInputCount());
637 mInputFilters
.resize(effect
->GetInputCount());
639 // In order to convert aSurface into an ID2D1Image, we need to know what
640 // DrawTarget we paint into. However, the same FilterNode object can be
641 // used on different DrawTargets, so we need to hold on to the SourceSurface
642 // objects and delay the conversion until we're actually painted and know
643 // our target DrawTarget.
644 // The conversion happens in WillDraw().
646 mInputSurfaces
[input
] = aSurface
;
647 mInputFilters
[input
] = nullptr;
649 // Clear the existing image from the effect.
650 effect
->SetInput(input
, nullptr);
654 FilterNodeD2D1::SetInput(uint32_t aIndex
, FilterNode
*aFilter
)
656 UINT32 input
= GetD2D1InputForInput(mType
, aIndex
);
657 ID2D1Effect
* effect
= InputEffect();
659 if (mType
== FilterType::COMPOSITE
) {
660 UINT32 inputCount
= effect
->GetInputCount();
662 if (aIndex
== inputCount
- 1 && aFilter
== nullptr) {
663 effect
->SetInputCount(inputCount
- 1);
664 } else if (aIndex
>= inputCount
&& aFilter
) {
665 effect
->SetInputCount(aIndex
+ 1);
669 MOZ_ASSERT(input
< effect
->GetInputCount());
671 if (aFilter
&& aFilter
->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1
) {
672 gfxWarning() << "Unknown input FilterNode set on effect.";
677 FilterNodeD2D1
* filter
= static_cast<FilterNodeD2D1
*>(aFilter
);
679 mInputSurfaces
.resize(effect
->GetInputCount());
680 mInputFilters
.resize(effect
->GetInputCount());
682 // We hold on to the FilterNode object so that we can call WillDraw() on it.
683 mInputSurfaces
[input
] = nullptr;
684 mInputFilters
[input
] = filter
;
687 effect
->SetInputEffect(input
, filter
->OutputEffect());
692 FilterNodeD2D1::WillDraw(DrawTarget
*aDT
)
694 // Convert input SourceSurfaces into ID2D1Images and set them on the effect.
695 for (size_t inputIndex
= 0; inputIndex
< mInputSurfaces
.size(); inputIndex
++) {
696 if (mInputSurfaces
[inputIndex
]) {
697 ID2D1Effect
* effect
= InputEffect();
698 RefPtr
<ID2D1Image
> image
= GetImageForSourceSurface(aDT
, mInputSurfaces
[inputIndex
]);
699 effect
->SetInput(inputIndex
, image
);
703 // Call WillDraw() on our input filters.
704 for (std::vector
<RefPtr
<FilterNodeD2D1
>>::iterator it
= mInputFilters
.begin();
705 it
!= mInputFilters
.end(); it
++) {
707 (*it
)->WillDraw(aDT
);
713 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, uint32_t aValue
)
715 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
716 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
718 if (mType
== FilterType::TURBULENCE
&& aIndex
== ATT_TURBULENCE_BASE_FREQUENCY
) {
719 mEffect
->SetValue(input
, D2D1::Vector2F(FLOAT(aValue
), FLOAT(aValue
)));
721 } else if (mType
== FilterType::DIRECTIONAL_BLUR
&& aIndex
== ATT_DIRECTIONAL_BLUR_DIRECTION
) {
722 mEffect
->SetValue(input
, aValue
== BLUR_DIRECTION_X
? 0 : 90.0f
);
726 mEffect
->SetValue(input
, ConvertValue(mType
, aIndex
, aValue
));
730 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, Float aValue
)
732 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
733 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
735 mEffect
->SetValue(input
, aValue
);
739 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Point
&aValue
)
741 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
742 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
744 mEffect
->SetValue(input
, D2DPoint(aValue
));
748 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Matrix5x4
&aValue
)
750 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
751 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
753 mEffect
->SetValue(input
, D2DMatrix5x4(aValue
));
757 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Point3D
&aValue
)
759 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
760 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
762 mEffect
->SetValue(input
, D2DVector3D(aValue
));
766 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Size
&aValue
)
768 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
769 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
771 mEffect
->SetValue(input
, D2D1::Vector2F(aValue
.width
, aValue
.height
));
775 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const IntSize
&aValue
)
777 UINT32 widthProp
, heightProp
;
779 if (!GetD2D1PropsForIntSize(mType
, aIndex
, &widthProp
, &heightProp
)) {
783 IntSize value
= aValue
;
784 ConvertValue(mType
, aIndex
, value
);
786 mEffect
->SetValue(widthProp
, (UINT
)value
.width
);
787 mEffect
->SetValue(heightProp
, (UINT
)value
.height
);
791 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Color
&aValue
)
793 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
794 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
797 case FilterType::POINT_DIFFUSE
:
798 case FilterType::SPOT_DIFFUSE
:
799 case FilterType::DISTANT_DIFFUSE
:
800 case FilterType::POINT_SPECULAR
:
801 case FilterType::SPOT_SPECULAR
:
802 case FilterType::DISTANT_SPECULAR
:
803 mEffect
->SetValue(input
, D2D1::Vector3F(aValue
.r
, aValue
.g
, aValue
.b
));
806 mEffect
->SetValue(input
, D2D1::Vector4F(aValue
.r
* aValue
.a
, aValue
.g
* aValue
.a
, aValue
.b
* aValue
.a
, aValue
.a
));
811 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Rect
&aValue
)
813 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
814 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
816 mEffect
->SetValue(input
, D2DRect(aValue
));
820 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const IntRect
&aValue
)
822 if (mType
== FilterType::TURBULENCE
) {
823 MOZ_ASSERT(aIndex
== ATT_TURBULENCE_RECT
);
825 mEffect
->SetValue(D2D1_TURBULENCE_PROP_OFFSET
, D2D1::Vector2F(Float(aValue
.X()), Float(aValue
.Y())));
826 mEffect
->SetValue(D2D1_TURBULENCE_PROP_SIZE
, D2D1::Vector2F(Float(aValue
.Width()), Float(aValue
.Height())));
830 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
831 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
833 mEffect
->SetValue(input
, D2D1::RectF(Float(aValue
.X()), Float(aValue
.Y()),
834 Float(aValue
.XMost()), Float(aValue
.YMost())));
838 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, bool aValue
)
840 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
841 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
843 mEffect
->SetValue(input
, (BOOL
)aValue
);
847 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Float
*aValues
, uint32_t aSize
)
849 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
850 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
852 mEffect
->SetValue(input
, (BYTE
*)aValues
, sizeof(Float
) * aSize
);
856 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const IntPoint
&aValue
)
858 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
859 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
861 mEffect
->SetValue(input
, D2DPoint(aValue
));
865 FilterNodeD2D1::SetAttribute(uint32_t aIndex
, const Matrix
&aMatrix
)
867 UINT32 input
= GetD2D1PropForAttribute(mType
, aIndex
);
868 MOZ_ASSERT(input
< mEffect
->GetPropertyCount());
870 mEffect
->SetValue(input
, D2DMatrix(aMatrix
));
873 FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(ID2D1DeviceContext
*aDC
)
874 : FilterNodeD2D1(nullptr, FilterType::CONVOLVE_MATRIX
)
875 , mEdgeMode(EDGE_MODE_DUPLICATE
)
877 // Correctly handling the interaction of edge mode and source rect is a bit
878 // tricky with D2D1 effects. We want the edge mode to only apply outside of
879 // the source rect (as specified by the ATT_CONVOLVE_MATRIX_SOURCE_RECT
880 // attribute). So if our input surface or filter is smaller than the source
881 // rect, we need to add transparency around it until we reach the edges of
882 // the source rect, and only then do any repeating or edge duplicating.
883 // Unfortunately, the border effect does not have a source rect attribute -
884 // it only looks at the output rect of its input filter or surface. So we use
885 // our custom ExtendInput effect to adjust the output rect of our input.
886 // All of this is only necessary when our edge mode is not EDGE_MODE_NONE, so
887 // we update the filter chain dynamically in UpdateChain().
891 hr
= aDC
->CreateEffect(CLSID_D2D1ConvolveMatrix
, getter_AddRefs(mEffect
));
893 if (FAILED(hr
) || !mEffect
) {
894 gfxWarning() << "Failed to create ConvolveMatrix filter!";
898 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE
, D2D1_BORDER_MODE_SOFT
);
900 hr
= aDC
->CreateEffect(CLSID_ExtendInputEffect
, getter_AddRefs(mExtendInputEffect
));
902 if (FAILED(hr
) || !mExtendInputEffect
) {
903 gfxWarning() << "Failed to create ConvolveMatrix filter!";
907 hr
= aDC
->CreateEffect(CLSID_D2D1Border
, getter_AddRefs(mBorderEffect
));
909 if (FAILED(hr
) || !mBorderEffect
) {
910 gfxWarning() << "Failed to create ConvolveMatrix filter!";
914 mBorderEffect
->SetInputEffect(0, mExtendInputEffect
.get());
921 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex
, FilterNode
*aFilter
)
923 FilterNodeD2D1::SetInput(aIndex
, aFilter
);
929 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, uint32_t aValue
)
931 if (aIndex
!= ATT_CONVOLVE_MATRIX_EDGE_MODE
) {
932 return FilterNodeD2D1::SetAttribute(aIndex
, aValue
);
935 mEdgeMode
= (ConvolveMatrixEdgeMode
)aValue
;
941 FilterNodeConvolveD2D1::InputEffect()
943 return mEdgeMode
== EDGE_MODE_NONE
? mEffect
.get() : mExtendInputEffect
.get();
947 FilterNodeConvolveD2D1::UpdateChain()
949 // The shape of the filter graph:
952 // input --> convolvematrix
954 // EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP:
955 // input --> extendinput --> border --> convolvematrix
957 // mEffect is convolvematrix.
959 if (mEdgeMode
!= EDGE_MODE_NONE
) {
960 mEffect
->SetInputEffect(0, mBorderEffect
.get());
963 RefPtr
<ID2D1Effect
> inputEffect
;
964 if (mInputFilters
.size() > 0 && mInputFilters
[0]) {
965 inputEffect
= mInputFilters
[0]->OutputEffect();
967 InputEffect()->SetInputEffect(0, inputEffect
);
969 if (mEdgeMode
== EDGE_MODE_DUPLICATE
) {
970 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X
, D2D1_BORDER_EDGE_MODE_CLAMP
);
971 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y
, D2D1_BORDER_EDGE_MODE_CLAMP
);
972 } else if (mEdgeMode
== EDGE_MODE_WRAP
) {
973 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X
, D2D1_BORDER_EDGE_MODE_WRAP
);
974 mBorderEffect
->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y
, D2D1_BORDER_EDGE_MODE_WRAP
);
979 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, const IntSize
&aValue
)
981 if (aIndex
!= ATT_CONVOLVE_MATRIX_KERNEL_SIZE
) {
986 mKernelSize
= aValue
;
988 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X
, aValue
.width
);
989 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y
, aValue
.height
);
995 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, const IntPoint
&aValue
)
997 if (aIndex
!= ATT_CONVOLVE_MATRIX_TARGET
) {
1008 FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex
, const IntRect
&aValue
)
1010 if (aIndex
!= ATT_CONVOLVE_MATRIX_SOURCE_RECT
) {
1015 mSourceRect
= aValue
;
1021 FilterNodeConvolveD2D1::UpdateOffset()
1023 D2D1_VECTOR_2F vector
=
1024 D2D1::Vector2F((Float(mKernelSize
.width
) - 1.0f
) / 2.0f
- Float(mTarget
.x
),
1025 (Float(mKernelSize
.height
) - 1.0f
) / 2.0f
- Float(mTarget
.y
));
1027 mEffect
->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET
, vector
);
1031 FilterNodeConvolveD2D1::UpdateSourceRect()
1033 mExtendInputEffect
->SetValue(EXTENDINPUT_PROP_OUTPUT_RECT
,
1034 D2D1::Vector4F(Float(mSourceRect
.X()), Float(mSourceRect
.Y()),
1035 Float(mSourceRect
.XMost()), Float(mSourceRect
.YMost())));
1038 FilterNodeExtendInputAdapterD2D1::FilterNodeExtendInputAdapterD2D1(ID2D1DeviceContext
*aDC
,
1039 FilterNodeD2D1
*aFilterNode
, FilterType aType
)
1040 : FilterNodeD2D1(aFilterNode
->MainEffect(), aType
)
1041 , mWrappedFilterNode(aFilterNode
)
1043 // We have an mEffect that looks at the bounds of the input effect, and we
1044 // want mEffect to regard its input as unbounded. So we take the input,
1045 // pipe it through an ExtendInput effect (which has an infinite output rect
1046 // by default), and feed the resulting unbounded composition into mEffect.
1050 hr
= aDC
->CreateEffect(CLSID_ExtendInputEffect
, getter_AddRefs(mExtendInputEffect
));
1052 if (FAILED(hr
) || !mExtendInputEffect
) {
1053 gfxWarning() << "Failed to create extend input effect for filter: " << hexa(hr
);
1057 aFilterNode
->InputEffect()->SetInputEffect(0, mExtendInputEffect
.get());
1060 FilterNodePremultiplyAdapterD2D1::FilterNodePremultiplyAdapterD2D1(ID2D1DeviceContext
*aDC
,
1061 FilterNodeD2D1
*aFilterNode
, FilterType aType
)
1062 : FilterNodeD2D1(aFilterNode
->MainEffect(), aType
)
1064 // D2D1 component transfer effects do strange things when it comes to
1065 // premultiplication.
1066 // For our purposes we only need the transfer filters to apply straight to
1067 // unpremultiplied source channels and output unpremultiplied results.
1068 // However, the D2D1 effects are designed differently: They can apply to both
1069 // premultiplied and unpremultiplied inputs, and they always premultiply
1070 // their result - at least in those color channels that have not been
1072 // In order to determine whether the input needs to be unpremultiplied as
1073 // part of the transfer, the effect consults the alpha mode metadata of the
1074 // input surface or the input effect. We don't have such a concept in Moz2D,
1075 // and giving Moz2D users different results based on something that cannot be
1076 // influenced through Moz2D APIs seems like a bad idea.
1077 // We solve this by applying a premultiply effect to the input before feeding
1078 // it into the transfer effect. The premultiply effect always premultiplies
1079 // regardless of any alpha mode metadata on inputs, and it always marks its
1080 // output as premultiplied so that the transfer effect will unpremultiply
1081 // consistently. Feeding always-premultiplied input into the transfer effect
1082 // also avoids another problem that would appear when individual color
1083 // channels disable the transfer: In that case, the disabled channels would
1084 // pass through unchanged in their unpremultiplied form and the other
1085 // channels would be premultiplied, giving a mixed result.
1086 // But since we now ensure that the input is premultiplied, disabled channels
1087 // will pass premultiplied values through to the result, which is consistent
1088 // with the enabled channels.
1089 // We also add an unpremultiply effect that postprocesses the result of the
1090 // transfer effect because getting unpremultiplied results from the transfer
1091 // filters is part of the FilterNode API.
1094 hr
= aDC
->CreateEffect(CLSID_D2D1Premultiply
, getter_AddRefs(mPrePremultiplyEffect
));
1096 if (FAILED(hr
) || !mPrePremultiplyEffect
) {
1097 gfxWarning() << "Failed to create ComponentTransfer filter!";
1101 hr
= aDC
->CreateEffect(CLSID_D2D1UnPremultiply
, getter_AddRefs(mPostUnpremultiplyEffect
));
1103 if (FAILED(hr
) || !mPostUnpremultiplyEffect
) {
1104 gfxWarning() << "Failed to create ComponentTransfer filter!";
1108 aFilterNode
->InputEffect()->SetInputEffect(0, mPrePremultiplyEffect
.get());
1109 mPostUnpremultiplyEffect
->SetInputEffect(0, aFilterNode
->OutputEffect());