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