1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/2d/FilterNodeD2D1.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1009 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "FilterNodeD2D1.h" 1.10 + 1.11 +#include "Logging.h" 1.12 + 1.13 +#include "SourceSurfaceD2D1.h" 1.14 +#include "SourceSurfaceD2D.h" 1.15 +#include "SourceSurfaceD2DTarget.h" 1.16 +#include "DrawTargetD2D.h" 1.17 +#include "DrawTargetD2D1.h" 1.18 + 1.19 +namespace mozilla { 1.20 +namespace gfx { 1.21 + 1.22 +D2D1_COLORMATRIX_ALPHA_MODE D2DAlphaMode(uint32_t aMode) 1.23 +{ 1.24 + switch (aMode) { 1.25 + case ALPHA_MODE_PREMULTIPLIED: 1.26 + return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED; 1.27 + case ALPHA_MODE_STRAIGHT: 1.28 + return D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT; 1.29 + default: 1.30 + MOZ_CRASH("Unknown enum value!"); 1.31 + } 1.32 + 1.33 + return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED; 1.34 +} 1.35 + 1.36 +D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE D2DAffineTransformInterpolationMode(Filter aFilter) 1.37 +{ 1.38 + switch (aFilter) { 1.39 + case Filter::GOOD: 1.40 + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR; 1.41 + case Filter::LINEAR: 1.42 + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR; 1.43 + case Filter::POINT: 1.44 + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR; 1.45 + default: 1.46 + MOZ_CRASH("Unknown enum value!"); 1.47 + } 1.48 + 1.49 + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR; 1.50 +} 1.51 + 1.52 +D2D1_BLEND_MODE D2DBlendMode(uint32_t aMode) 1.53 +{ 1.54 + switch (aMode) { 1.55 + case BLEND_MODE_DARKEN: 1.56 + return D2D1_BLEND_MODE_DARKEN; 1.57 + case BLEND_MODE_LIGHTEN: 1.58 + return D2D1_BLEND_MODE_LIGHTEN; 1.59 + case BLEND_MODE_MULTIPLY: 1.60 + return D2D1_BLEND_MODE_MULTIPLY; 1.61 + case BLEND_MODE_SCREEN: 1.62 + return D2D1_BLEND_MODE_SCREEN; 1.63 + default: 1.64 + MOZ_CRASH("Unknown enum value!"); 1.65 + } 1.66 + 1.67 + return D2D1_BLEND_MODE_DARKEN; 1.68 +} 1.69 + 1.70 +D2D1_MORPHOLOGY_MODE D2DMorphologyMode(uint32_t aMode) 1.71 +{ 1.72 + switch (aMode) { 1.73 + case MORPHOLOGY_OPERATOR_DILATE: 1.74 + return D2D1_MORPHOLOGY_MODE_DILATE; 1.75 + case MORPHOLOGY_OPERATOR_ERODE: 1.76 + return D2D1_MORPHOLOGY_MODE_ERODE; 1.77 + } 1.78 + 1.79 + MOZ_CRASH("Unknown enum value!"); 1.80 + return D2D1_MORPHOLOGY_MODE_DILATE; 1.81 +} 1.82 + 1.83 +D2D1_TURBULENCE_NOISE D2DTurbulenceNoise(uint32_t aMode) 1.84 +{ 1.85 + switch (aMode) { 1.86 + case TURBULENCE_TYPE_FRACTAL_NOISE: 1.87 + return D2D1_TURBULENCE_NOISE_FRACTAL_SUM; 1.88 + case TURBULENCE_TYPE_TURBULENCE: 1.89 + return D2D1_TURBULENCE_NOISE_TURBULENCE; 1.90 + } 1.91 + 1.92 + MOZ_CRASH("Unknown enum value!"); 1.93 + return D2D1_TURBULENCE_NOISE_TURBULENCE; 1.94 +} 1.95 + 1.96 +D2D1_COMPOSITE_MODE D2DFilterCompositionMode(uint32_t aMode) 1.97 +{ 1.98 + switch (aMode) { 1.99 + case COMPOSITE_OPERATOR_OVER: 1.100 + return D2D1_COMPOSITE_MODE_SOURCE_OVER; 1.101 + case COMPOSITE_OPERATOR_IN: 1.102 + return D2D1_COMPOSITE_MODE_SOURCE_IN; 1.103 + case COMPOSITE_OPERATOR_OUT: 1.104 + return D2D1_COMPOSITE_MODE_SOURCE_OUT; 1.105 + case COMPOSITE_OPERATOR_ATOP: 1.106 + return D2D1_COMPOSITE_MODE_SOURCE_ATOP; 1.107 + case COMPOSITE_OPERATOR_XOR: 1.108 + return D2D1_COMPOSITE_MODE_XOR; 1.109 + } 1.110 + 1.111 + MOZ_CRASH("Unknown enum value!"); 1.112 + return D2D1_COMPOSITE_MODE_SOURCE_OVER; 1.113 +} 1.114 + 1.115 +D2D1_CHANNEL_SELECTOR D2DChannelSelector(uint32_t aMode) 1.116 +{ 1.117 + switch (aMode) { 1.118 + case COLOR_CHANNEL_R: 1.119 + return D2D1_CHANNEL_SELECTOR_R; 1.120 + case COLOR_CHANNEL_G: 1.121 + return D2D1_CHANNEL_SELECTOR_G; 1.122 + case COLOR_CHANNEL_B: 1.123 + return D2D1_CHANNEL_SELECTOR_B; 1.124 + case COLOR_CHANNEL_A: 1.125 + return D2D1_CHANNEL_SELECTOR_A; 1.126 + } 1.127 + 1.128 + MOZ_CRASH("Unknown enum value!"); 1.129 + return D2D1_CHANNEL_SELECTOR_R; 1.130 +} 1.131 + 1.132 +TemporaryRef<ID2D1Image> GetImageForSourceSurface(DrawTarget *aDT, SourceSurface *aSurface) 1.133 +{ 1.134 + switch (aDT->GetType()) { 1.135 + case BackendType::DIRECT2D1_1: 1.136 + return static_cast<DrawTargetD2D1*>(aDT)->GetImageForSurface(aSurface, ExtendMode::CLAMP); 1.137 + case BackendType::DIRECT2D: 1.138 + return static_cast<DrawTargetD2D*>(aDT)->GetImageForSurface(aSurface); 1.139 + default: 1.140 + MOZ_CRASH("Unknown draw target type!"); 1.141 + return nullptr; 1.142 + } 1.143 +} 1.144 + 1.145 +uint32_t ConvertValue(FilterType aType, uint32_t aAttribute, uint32_t aValue) 1.146 +{ 1.147 + switch (aType) { 1.148 + case FilterType::COLOR_MATRIX: 1.149 + if (aAttribute == ATT_COLOR_MATRIX_ALPHA_MODE) { 1.150 + aValue = D2DAlphaMode(aValue); 1.151 + } 1.152 + break; 1.153 + case FilterType::TRANSFORM: 1.154 + if (aAttribute == ATT_TRANSFORM_FILTER) { 1.155 + aValue = D2DAffineTransformInterpolationMode(Filter(aValue)); 1.156 + } 1.157 + break; 1.158 + case FilterType::BLEND: 1.159 + if (aAttribute == ATT_BLEND_BLENDMODE) { 1.160 + aValue = D2DBlendMode(aValue); 1.161 + } 1.162 + break; 1.163 + case FilterType::MORPHOLOGY: 1.164 + if (aAttribute == ATT_MORPHOLOGY_OPERATOR) { 1.165 + aValue = D2DMorphologyMode(aValue); 1.166 + } 1.167 + break; 1.168 + case FilterType::DISPLACEMENT_MAP: 1.169 + if (aAttribute == ATT_DISPLACEMENT_MAP_X_CHANNEL || 1.170 + aAttribute == ATT_DISPLACEMENT_MAP_Y_CHANNEL) { 1.171 + aValue = D2DChannelSelector(aValue); 1.172 + } 1.173 + break; 1.174 + case FilterType::TURBULENCE: 1.175 + if (aAttribute == ATT_TURBULENCE_TYPE) { 1.176 + aValue = D2DTurbulenceNoise(aValue); 1.177 + } 1.178 + break; 1.179 + case FilterType::COMPOSITE: 1.180 + if (aAttribute == ATT_COMPOSITE_OPERATOR) { 1.181 + aValue = D2DFilterCompositionMode(aValue); 1.182 + } 1.183 + break; 1.184 + } 1.185 + 1.186 + return aValue; 1.187 +} 1.188 + 1.189 +void ConvertValue(FilterType aType, uint32_t aAttribute, IntSize &aValue) 1.190 +{ 1.191 + switch (aType) { 1.192 + case FilterType::MORPHOLOGY: 1.193 + if (aAttribute == ATT_MORPHOLOGY_RADII) { 1.194 + aValue.width *= 2; 1.195 + aValue.width += 1; 1.196 + aValue.height *= 2; 1.197 + aValue.height += 1; 1.198 + } 1.199 + break; 1.200 + } 1.201 +} 1.202 + 1.203 +UINT32 1.204 +GetD2D1InputForInput(FilterType aType, uint32_t aIndex) 1.205 +{ 1.206 + return aIndex; 1.207 +} 1.208 + 1.209 +#define CONVERT_PROP(moz2dname, d2dname) \ 1.210 + case ATT_##moz2dname: \ 1.211 + return D2D1_##d2dname 1.212 + 1.213 +UINT32 1.214 +GetD2D1PropForAttribute(FilterType aType, uint32_t aIndex) 1.215 +{ 1.216 + switch (aType) { 1.217 + case FilterType::COLOR_MATRIX: 1.218 + switch (aIndex) { 1.219 + CONVERT_PROP(COLOR_MATRIX_MATRIX, COLORMATRIX_PROP_COLOR_MATRIX); 1.220 + CONVERT_PROP(COLOR_MATRIX_ALPHA_MODE, COLORMATRIX_PROP_ALPHA_MODE); 1.221 + } 1.222 + break; 1.223 + case FilterType::TRANSFORM: 1.224 + switch (aIndex) { 1.225 + CONVERT_PROP(TRANSFORM_MATRIX, 2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX); 1.226 + CONVERT_PROP(TRANSFORM_FILTER, 2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE); 1.227 + } 1.228 + case FilterType::BLEND: 1.229 + switch (aIndex) { 1.230 + CONVERT_PROP(BLEND_BLENDMODE, BLEND_PROP_MODE); 1.231 + } 1.232 + break; 1.233 + case FilterType::MORPHOLOGY: 1.234 + switch (aIndex) { 1.235 + CONVERT_PROP(MORPHOLOGY_OPERATOR, MORPHOLOGY_PROP_MODE); 1.236 + } 1.237 + break; 1.238 + case FilterType::FLOOD: 1.239 + switch (aIndex) { 1.240 + CONVERT_PROP(FLOOD_COLOR, FLOOD_PROP_COLOR); 1.241 + } 1.242 + break; 1.243 + case FilterType::TILE: 1.244 + switch (aIndex) { 1.245 + CONVERT_PROP(TILE_SOURCE_RECT, TILE_PROP_RECT); 1.246 + } 1.247 + break; 1.248 + case FilterType::TABLE_TRANSFER: 1.249 + switch (aIndex) { 1.250 + CONVERT_PROP(TABLE_TRANSFER_DISABLE_R, TABLETRANSFER_PROP_RED_DISABLE); 1.251 + CONVERT_PROP(TABLE_TRANSFER_DISABLE_G, TABLETRANSFER_PROP_GREEN_DISABLE); 1.252 + CONVERT_PROP(TABLE_TRANSFER_DISABLE_B, TABLETRANSFER_PROP_BLUE_DISABLE); 1.253 + CONVERT_PROP(TABLE_TRANSFER_DISABLE_A, TABLETRANSFER_PROP_ALPHA_DISABLE); 1.254 + CONVERT_PROP(TABLE_TRANSFER_TABLE_R, TABLETRANSFER_PROP_RED_TABLE); 1.255 + CONVERT_PROP(TABLE_TRANSFER_TABLE_G, TABLETRANSFER_PROP_GREEN_TABLE); 1.256 + CONVERT_PROP(TABLE_TRANSFER_TABLE_B, TABLETRANSFER_PROP_BLUE_TABLE); 1.257 + CONVERT_PROP(TABLE_TRANSFER_TABLE_A, TABLETRANSFER_PROP_ALPHA_TABLE); 1.258 + } 1.259 + break; 1.260 + case FilterType::DISCRETE_TRANSFER: 1.261 + switch (aIndex) { 1.262 + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_R, DISCRETETRANSFER_PROP_RED_DISABLE); 1.263 + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_G, DISCRETETRANSFER_PROP_GREEN_DISABLE); 1.264 + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_B, DISCRETETRANSFER_PROP_BLUE_DISABLE); 1.265 + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_A, DISCRETETRANSFER_PROP_ALPHA_DISABLE); 1.266 + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_R, DISCRETETRANSFER_PROP_RED_TABLE); 1.267 + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_G, DISCRETETRANSFER_PROP_GREEN_TABLE); 1.268 + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_B, DISCRETETRANSFER_PROP_BLUE_TABLE); 1.269 + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_A, DISCRETETRANSFER_PROP_ALPHA_TABLE); 1.270 + } 1.271 + break; 1.272 + case FilterType::LINEAR_TRANSFER: 1.273 + switch (aIndex) { 1.274 + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_R, LINEARTRANSFER_PROP_RED_DISABLE); 1.275 + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_G, LINEARTRANSFER_PROP_GREEN_DISABLE); 1.276 + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_B, LINEARTRANSFER_PROP_BLUE_DISABLE); 1.277 + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_A, LINEARTRANSFER_PROP_ALPHA_DISABLE); 1.278 + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_R, LINEARTRANSFER_PROP_RED_Y_INTERCEPT); 1.279 + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_G, LINEARTRANSFER_PROP_GREEN_Y_INTERCEPT); 1.280 + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_B, LINEARTRANSFER_PROP_BLUE_Y_INTERCEPT); 1.281 + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_A, LINEARTRANSFER_PROP_ALPHA_Y_INTERCEPT); 1.282 + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_R, LINEARTRANSFER_PROP_RED_SLOPE); 1.283 + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_G, LINEARTRANSFER_PROP_GREEN_SLOPE); 1.284 + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_B, LINEARTRANSFER_PROP_BLUE_SLOPE); 1.285 + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_A, LINEARTRANSFER_PROP_ALPHA_SLOPE); 1.286 + } 1.287 + break; 1.288 + case FilterType::GAMMA_TRANSFER: 1.289 + switch (aIndex) { 1.290 + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_R, GAMMATRANSFER_PROP_RED_DISABLE); 1.291 + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_G, GAMMATRANSFER_PROP_GREEN_DISABLE); 1.292 + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_B, GAMMATRANSFER_PROP_BLUE_DISABLE); 1.293 + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_A, GAMMATRANSFER_PROP_ALPHA_DISABLE); 1.294 + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_R, GAMMATRANSFER_PROP_RED_AMPLITUDE); 1.295 + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_G, GAMMATRANSFER_PROP_GREEN_AMPLITUDE); 1.296 + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_B, GAMMATRANSFER_PROP_BLUE_AMPLITUDE); 1.297 + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_A, GAMMATRANSFER_PROP_ALPHA_AMPLITUDE); 1.298 + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_R, GAMMATRANSFER_PROP_RED_EXPONENT); 1.299 + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_G, GAMMATRANSFER_PROP_GREEN_EXPONENT); 1.300 + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_B, GAMMATRANSFER_PROP_BLUE_EXPONENT); 1.301 + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_A, GAMMATRANSFER_PROP_ALPHA_EXPONENT); 1.302 + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_R, GAMMATRANSFER_PROP_RED_OFFSET); 1.303 + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_G, GAMMATRANSFER_PROP_GREEN_OFFSET); 1.304 + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_B, GAMMATRANSFER_PROP_BLUE_OFFSET); 1.305 + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_A, GAMMATRANSFER_PROP_ALPHA_OFFSET); 1.306 + } 1.307 + break; 1.308 + case FilterType::CONVOLVE_MATRIX: 1.309 + switch (aIndex) { 1.310 + CONVERT_PROP(CONVOLVE_MATRIX_BIAS, CONVOLVEMATRIX_PROP_BIAS); 1.311 + CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_MATRIX, CONVOLVEMATRIX_PROP_KERNEL_MATRIX); 1.312 + CONVERT_PROP(CONVOLVE_MATRIX_DIVISOR, CONVOLVEMATRIX_PROP_DIVISOR); 1.313 + CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, CONVOLVEMATRIX_PROP_KERNEL_UNIT_LENGTH); 1.314 + CONVERT_PROP(CONVOLVE_MATRIX_PRESERVE_ALPHA, CONVOLVEMATRIX_PROP_PRESERVE_ALPHA); 1.315 + } 1.316 + case FilterType::DISPLACEMENT_MAP: 1.317 + switch (aIndex) { 1.318 + CONVERT_PROP(DISPLACEMENT_MAP_SCALE, DISPLACEMENTMAP_PROP_SCALE); 1.319 + CONVERT_PROP(DISPLACEMENT_MAP_X_CHANNEL, DISPLACEMENTMAP_PROP_X_CHANNEL_SELECT); 1.320 + CONVERT_PROP(DISPLACEMENT_MAP_Y_CHANNEL, DISPLACEMENTMAP_PROP_Y_CHANNEL_SELECT); 1.321 + } 1.322 + break; 1.323 + case FilterType::TURBULENCE: 1.324 + switch (aIndex) { 1.325 + CONVERT_PROP(TURBULENCE_BASE_FREQUENCY, TURBULENCE_PROP_BASE_FREQUENCY); 1.326 + CONVERT_PROP(TURBULENCE_NUM_OCTAVES, TURBULENCE_PROP_NUM_OCTAVES); 1.327 + CONVERT_PROP(TURBULENCE_SEED, TURBULENCE_PROP_SEED); 1.328 + CONVERT_PROP(TURBULENCE_STITCHABLE, TURBULENCE_PROP_STITCHABLE); 1.329 + CONVERT_PROP(TURBULENCE_TYPE, TURBULENCE_PROP_NOISE); 1.330 + } 1.331 + break; 1.332 + case FilterType::ARITHMETIC_COMBINE: 1.333 + switch (aIndex) { 1.334 + CONVERT_PROP(ARITHMETIC_COMBINE_COEFFICIENTS, ARITHMETICCOMPOSITE_PROP_COEFFICIENTS); 1.335 + } 1.336 + break; 1.337 + case FilterType::COMPOSITE: 1.338 + switch (aIndex) { 1.339 + CONVERT_PROP(COMPOSITE_OPERATOR, COMPOSITE_PROP_MODE); 1.340 + } 1.341 + break; 1.342 + case FilterType::GAUSSIAN_BLUR: 1.343 + switch (aIndex) { 1.344 + CONVERT_PROP(GAUSSIAN_BLUR_STD_DEVIATION, GAUSSIANBLUR_PROP_STANDARD_DEVIATION); 1.345 + } 1.346 + break; 1.347 + case FilterType::DIRECTIONAL_BLUR: 1.348 + switch (aIndex) { 1.349 + CONVERT_PROP(DIRECTIONAL_BLUR_STD_DEVIATION, DIRECTIONALBLUR_PROP_STANDARD_DEVIATION); 1.350 + CONVERT_PROP(DIRECTIONAL_BLUR_DIRECTION, DIRECTIONALBLUR_PROP_ANGLE); 1.351 + } 1.352 + break; 1.353 + case FilterType::POINT_DIFFUSE: 1.354 + switch (aIndex) { 1.355 + CONVERT_PROP(POINT_DIFFUSE_DIFFUSE_CONSTANT, POINTDIFFUSE_PROP_DIFFUSE_CONSTANT); 1.356 + CONVERT_PROP(POINT_DIFFUSE_POSITION, POINTDIFFUSE_PROP_LIGHT_POSITION); 1.357 + CONVERT_PROP(POINT_DIFFUSE_COLOR, POINTDIFFUSE_PROP_COLOR); 1.358 + CONVERT_PROP(POINT_DIFFUSE_SURFACE_SCALE, POINTDIFFUSE_PROP_SURFACE_SCALE); 1.359 + CONVERT_PROP(POINT_DIFFUSE_KERNEL_UNIT_LENGTH, POINTDIFFUSE_PROP_KERNEL_UNIT_LENGTH); 1.360 + } 1.361 + break; 1.362 + case FilterType::SPOT_DIFFUSE: 1.363 + switch (aIndex) { 1.364 + CONVERT_PROP(SPOT_DIFFUSE_DIFFUSE_CONSTANT, SPOTDIFFUSE_PROP_DIFFUSE_CONSTANT); 1.365 + CONVERT_PROP(SPOT_DIFFUSE_POINTS_AT, SPOTDIFFUSE_PROP_POINTS_AT); 1.366 + CONVERT_PROP(SPOT_DIFFUSE_FOCUS, SPOTDIFFUSE_PROP_FOCUS); 1.367 + CONVERT_PROP(SPOT_DIFFUSE_LIMITING_CONE_ANGLE, SPOTDIFFUSE_PROP_LIMITING_CONE_ANGLE); 1.368 + CONVERT_PROP(SPOT_DIFFUSE_POSITION, SPOTDIFFUSE_PROP_LIGHT_POSITION); 1.369 + CONVERT_PROP(SPOT_DIFFUSE_COLOR, SPOTDIFFUSE_PROP_COLOR); 1.370 + CONVERT_PROP(SPOT_DIFFUSE_SURFACE_SCALE, SPOTDIFFUSE_PROP_SURFACE_SCALE); 1.371 + CONVERT_PROP(SPOT_DIFFUSE_KERNEL_UNIT_LENGTH, SPOTDIFFUSE_PROP_KERNEL_UNIT_LENGTH); 1.372 + } 1.373 + break; 1.374 + case FilterType::DISTANT_DIFFUSE: 1.375 + switch (aIndex) { 1.376 + CONVERT_PROP(DISTANT_DIFFUSE_DIFFUSE_CONSTANT, DISTANTDIFFUSE_PROP_DIFFUSE_CONSTANT); 1.377 + CONVERT_PROP(DISTANT_DIFFUSE_AZIMUTH, DISTANTDIFFUSE_PROP_AZIMUTH); 1.378 + CONVERT_PROP(DISTANT_DIFFUSE_ELEVATION, DISTANTDIFFUSE_PROP_ELEVATION); 1.379 + CONVERT_PROP(DISTANT_DIFFUSE_COLOR, DISTANTDIFFUSE_PROP_COLOR); 1.380 + CONVERT_PROP(DISTANT_DIFFUSE_SURFACE_SCALE, DISTANTDIFFUSE_PROP_SURFACE_SCALE); 1.381 + CONVERT_PROP(DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH, DISTANTDIFFUSE_PROP_KERNEL_UNIT_LENGTH); 1.382 + } 1.383 + break; 1.384 + case FilterType::POINT_SPECULAR: 1.385 + switch (aIndex) { 1.386 + CONVERT_PROP(POINT_SPECULAR_SPECULAR_CONSTANT, POINTSPECULAR_PROP_SPECULAR_CONSTANT); 1.387 + CONVERT_PROP(POINT_SPECULAR_SPECULAR_EXPONENT, POINTSPECULAR_PROP_SPECULAR_EXPONENT); 1.388 + CONVERT_PROP(POINT_SPECULAR_POSITION, POINTSPECULAR_PROP_LIGHT_POSITION); 1.389 + CONVERT_PROP(POINT_SPECULAR_COLOR, POINTSPECULAR_PROP_COLOR); 1.390 + CONVERT_PROP(POINT_SPECULAR_SURFACE_SCALE, POINTSPECULAR_PROP_SURFACE_SCALE); 1.391 + CONVERT_PROP(POINT_SPECULAR_KERNEL_UNIT_LENGTH, POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH); 1.392 + } 1.393 + break; 1.394 + case FilterType::SPOT_SPECULAR: 1.395 + switch (aIndex) { 1.396 + CONVERT_PROP(SPOT_SPECULAR_SPECULAR_CONSTANT, SPOTSPECULAR_PROP_SPECULAR_CONSTANT); 1.397 + CONVERT_PROP(SPOT_SPECULAR_SPECULAR_EXPONENT, SPOTSPECULAR_PROP_SPECULAR_EXPONENT); 1.398 + CONVERT_PROP(SPOT_SPECULAR_POINTS_AT, SPOTSPECULAR_PROP_POINTS_AT); 1.399 + CONVERT_PROP(SPOT_SPECULAR_FOCUS, SPOTSPECULAR_PROP_FOCUS); 1.400 + CONVERT_PROP(SPOT_SPECULAR_LIMITING_CONE_ANGLE, SPOTSPECULAR_PROP_LIMITING_CONE_ANGLE); 1.401 + CONVERT_PROP(SPOT_SPECULAR_POSITION, SPOTSPECULAR_PROP_LIGHT_POSITION); 1.402 + CONVERT_PROP(SPOT_SPECULAR_COLOR, SPOTSPECULAR_PROP_COLOR); 1.403 + CONVERT_PROP(SPOT_SPECULAR_SURFACE_SCALE, SPOTSPECULAR_PROP_SURFACE_SCALE); 1.404 + CONVERT_PROP(SPOT_SPECULAR_KERNEL_UNIT_LENGTH, SPOTSPECULAR_PROP_KERNEL_UNIT_LENGTH); 1.405 + } 1.406 + break; 1.407 + case FilterType::DISTANT_SPECULAR: 1.408 + switch (aIndex) { 1.409 + CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_CONSTANT, DISTANTSPECULAR_PROP_SPECULAR_CONSTANT); 1.410 + CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_EXPONENT, DISTANTSPECULAR_PROP_SPECULAR_EXPONENT); 1.411 + CONVERT_PROP(DISTANT_SPECULAR_AZIMUTH, DISTANTSPECULAR_PROP_AZIMUTH); 1.412 + CONVERT_PROP(DISTANT_SPECULAR_ELEVATION, DISTANTSPECULAR_PROP_ELEVATION); 1.413 + CONVERT_PROP(DISTANT_SPECULAR_COLOR, DISTANTSPECULAR_PROP_COLOR); 1.414 + CONVERT_PROP(DISTANT_SPECULAR_SURFACE_SCALE, DISTANTSPECULAR_PROP_SURFACE_SCALE); 1.415 + CONVERT_PROP(DISTANT_SPECULAR_KERNEL_UNIT_LENGTH, DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH); 1.416 + } 1.417 + break; 1.418 + case FilterType::CROP: 1.419 + switch (aIndex) { 1.420 + CONVERT_PROP(CROP_RECT, CROP_PROP_RECT); 1.421 + } 1.422 + break; 1.423 + } 1.424 + 1.425 + return UINT32_MAX; 1.426 +} 1.427 + 1.428 +bool 1.429 +GetD2D1PropsForIntSize(FilterType aType, uint32_t aIndex, UINT32 *aPropWidth, UINT32 *aPropHeight) 1.430 +{ 1.431 + switch (aType) { 1.432 + case FilterType::MORPHOLOGY: 1.433 + if (aIndex == ATT_MORPHOLOGY_RADII) { 1.434 + *aPropWidth = D2D1_MORPHOLOGY_PROP_WIDTH; 1.435 + *aPropHeight = D2D1_MORPHOLOGY_PROP_HEIGHT; 1.436 + return true; 1.437 + } 1.438 + break; 1.439 + } 1.440 + return false; 1.441 +} 1.442 + 1.443 +static inline REFCLSID GetCLDIDForFilterType(FilterType aType) 1.444 +{ 1.445 + switch (aType) { 1.446 + case FilterType::COLOR_MATRIX: 1.447 + return CLSID_D2D1ColorMatrix; 1.448 + case FilterType::TRANSFORM: 1.449 + return CLSID_D2D12DAffineTransform; 1.450 + case FilterType::BLEND: 1.451 + return CLSID_D2D1Blend; 1.452 + case FilterType::MORPHOLOGY: 1.453 + return CLSID_D2D1Morphology; 1.454 + case FilterType::FLOOD: 1.455 + return CLSID_D2D1Flood; 1.456 + case FilterType::TILE: 1.457 + return CLSID_D2D1Tile; 1.458 + case FilterType::TABLE_TRANSFER: 1.459 + return CLSID_D2D1TableTransfer; 1.460 + case FilterType::LINEAR_TRANSFER: 1.461 + return CLSID_D2D1LinearTransfer; 1.462 + case FilterType::DISCRETE_TRANSFER: 1.463 + return CLSID_D2D1DiscreteTransfer; 1.464 + case FilterType::GAMMA_TRANSFER: 1.465 + return CLSID_D2D1GammaTransfer; 1.466 + case FilterType::DISPLACEMENT_MAP: 1.467 + return CLSID_D2D1DisplacementMap; 1.468 + case FilterType::TURBULENCE: 1.469 + return CLSID_D2D1Turbulence; 1.470 + case FilterType::ARITHMETIC_COMBINE: 1.471 + return CLSID_D2D1ArithmeticComposite; 1.472 + case FilterType::COMPOSITE: 1.473 + return CLSID_D2D1Composite; 1.474 + case FilterType::GAUSSIAN_BLUR: 1.475 + return CLSID_D2D1GaussianBlur; 1.476 + case FilterType::DIRECTIONAL_BLUR: 1.477 + return CLSID_D2D1DirectionalBlur; 1.478 + case FilterType::POINT_DIFFUSE: 1.479 + return CLSID_D2D1PointDiffuse; 1.480 + case FilterType::POINT_SPECULAR: 1.481 + return CLSID_D2D1PointSpecular; 1.482 + case FilterType::SPOT_DIFFUSE: 1.483 + return CLSID_D2D1SpotDiffuse; 1.484 + case FilterType::SPOT_SPECULAR: 1.485 + return CLSID_D2D1SpotSpecular; 1.486 + case FilterType::DISTANT_DIFFUSE: 1.487 + return CLSID_D2D1DistantDiffuse; 1.488 + case FilterType::DISTANT_SPECULAR: 1.489 + return CLSID_D2D1DistantSpecular; 1.490 + case FilterType::CROP: 1.491 + return CLSID_D2D1Crop; 1.492 + case FilterType::PREMULTIPLY: 1.493 + return CLSID_D2D1Premultiply; 1.494 + case FilterType::UNPREMULTIPLY: 1.495 + return CLSID_D2D1UnPremultiply; 1.496 + } 1.497 + return GUID_NULL; 1.498 +} 1.499 + 1.500 +/* static */ 1.501 +TemporaryRef<FilterNode> 1.502 +FilterNodeD2D1::Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aType) 1.503 +{ 1.504 + if (aType == FilterType::CONVOLVE_MATRIX) { 1.505 + return new FilterNodeConvolveD2D1(aDT, aDC); 1.506 + } 1.507 + 1.508 + RefPtr<ID2D1Effect> effect; 1.509 + HRESULT hr; 1.510 + 1.511 + hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), byRef(effect)); 1.512 + 1.513 + if (FAILED(hr)) { 1.514 + gfxWarning() << "Failed to create effect for FilterType: " << hr; 1.515 + return nullptr; 1.516 + } 1.517 + 1.518 + switch (aType) { 1.519 + case FilterType::LINEAR_TRANSFER: 1.520 + case FilterType::GAMMA_TRANSFER: 1.521 + case FilterType::TABLE_TRANSFER: 1.522 + case FilterType::DISCRETE_TRANSFER: 1.523 + return new FilterNodeComponentTransferD2D1(aDT, aDC, effect, aType); 1.524 + default: 1.525 + return new FilterNodeD2D1(aDT, effect, aType); 1.526 + } 1.527 +} 1.528 + 1.529 +void 1.530 +FilterNodeD2D1::InitUnmappedProperties() 1.531 +{ 1.532 + switch (mType) { 1.533 + case FilterType::TRANSFORM: 1.534 + mEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE, D2D1_BORDER_MODE_HARD); 1.535 + break; 1.536 + default: 1.537 + break; 1.538 + } 1.539 +} 1.540 + 1.541 +void 1.542 +FilterNodeD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface) 1.543 +{ 1.544 + UINT32 input = GetD2D1InputForInput(mType, aIndex); 1.545 + ID2D1Effect* effect = InputEffect(); 1.546 + MOZ_ASSERT(input < effect->GetInputCount()); 1.547 + 1.548 + if (mType == FilterType::COMPOSITE) { 1.549 + UINT32 inputCount = effect->GetInputCount(); 1.550 + 1.551 + if (aIndex == inputCount - 1 && aSurface == nullptr) { 1.552 + effect->SetInputCount(inputCount - 1); 1.553 + } else if (aIndex >= inputCount && aSurface) { 1.554 + effect->SetInputCount(aIndex + 1); 1.555 + } 1.556 + } 1.557 + 1.558 + RefPtr<ID2D1Image> image = GetImageForSourceSurface(mDT, aSurface); 1.559 + effect->SetInput(input, image); 1.560 +} 1.561 + 1.562 +void 1.563 +FilterNodeD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter) 1.564 +{ 1.565 + UINT32 input = GetD2D1InputForInput(mType, aIndex); 1.566 + ID2D1Effect* effect = InputEffect(); 1.567 + 1.568 + if (mType == FilterType::COMPOSITE) { 1.569 + UINT32 inputCount = effect->GetInputCount(); 1.570 + 1.571 + if (aIndex == inputCount - 1 && aFilter == nullptr) { 1.572 + effect->SetInputCount(inputCount - 1); 1.573 + } else if (aIndex >= inputCount && aFilter) { 1.574 + effect->SetInputCount(aIndex + 1); 1.575 + } 1.576 + } 1.577 + 1.578 + MOZ_ASSERT(input < effect->GetInputCount()); 1.579 + 1.580 + if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) { 1.581 + gfxWarning() << "Unknown input SourceSurface set on effect."; 1.582 + MOZ_ASSERT(0); 1.583 + return; 1.584 + } 1.585 + 1.586 + effect->SetInputEffect(input, static_cast<FilterNodeD2D1*>(aFilter)->OutputEffect()); 1.587 +} 1.588 + 1.589 +void 1.590 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue) 1.591 +{ 1.592 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.593 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.594 + 1.595 + if (mType == FilterType::TURBULENCE && aIndex == ATT_TURBULENCE_BASE_FREQUENCY) { 1.596 + mEffect->SetValue(input, D2D1::Vector2F(FLOAT(aValue), FLOAT(aValue))); 1.597 + return; 1.598 + } else if (mType == FilterType::DIRECTIONAL_BLUR && aIndex == ATT_DIRECTIONAL_BLUR_DIRECTION) { 1.599 + mEffect->SetValue(input, aValue == BLUR_DIRECTION_X ? 0 : 90.0f); 1.600 + return; 1.601 + } 1.602 + 1.603 + mEffect->SetValue(input, ConvertValue(mType, aIndex, aValue)); 1.604 +} 1.605 + 1.606 +void 1.607 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, Float aValue) 1.608 +{ 1.609 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.610 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.611 + 1.612 + mEffect->SetValue(input, aValue); 1.613 +} 1.614 + 1.615 +void 1.616 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point &aValue) 1.617 +{ 1.618 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.619 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.620 + 1.621 + mEffect->SetValue(input, D2DPoint(aValue)); 1.622 +} 1.623 + 1.624 +void 1.625 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix5x4 &aValue) 1.626 +{ 1.627 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.628 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.629 + 1.630 + mEffect->SetValue(input, D2DMatrix5x4(aValue)); 1.631 +} 1.632 + 1.633 +void 1.634 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point3D &aValue) 1.635 +{ 1.636 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.637 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.638 + 1.639 + mEffect->SetValue(input, D2DVector3D(aValue)); 1.640 +} 1.641 + 1.642 +void 1.643 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Size &aValue) 1.644 +{ 1.645 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.646 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.647 + 1.648 + mEffect->SetValue(input, D2D1::Vector2F(aValue.width, aValue.height)); 1.649 +} 1.650 + 1.651 +void 1.652 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue) 1.653 +{ 1.654 + UINT32 widthProp, heightProp; 1.655 + 1.656 + if (!GetD2D1PropsForIntSize(mType, aIndex, &widthProp, &heightProp)) { 1.657 + return; 1.658 + } 1.659 + 1.660 + IntSize value = aValue; 1.661 + ConvertValue(mType, aIndex, value); 1.662 + 1.663 + mEffect->SetValue(widthProp, (UINT)value.width); 1.664 + mEffect->SetValue(heightProp, (UINT)value.height); 1.665 +} 1.666 + 1.667 +void 1.668 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Color &aValue) 1.669 +{ 1.670 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.671 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.672 + 1.673 + switch (mType) { 1.674 + case FilterType::POINT_DIFFUSE: 1.675 + case FilterType::SPOT_DIFFUSE: 1.676 + case FilterType::DISTANT_DIFFUSE: 1.677 + case FilterType::POINT_SPECULAR: 1.678 + case FilterType::SPOT_SPECULAR: 1.679 + case FilterType::DISTANT_SPECULAR: 1.680 + mEffect->SetValue(input, D2D1::Vector3F(aValue.r, aValue.g, aValue.b)); 1.681 + break; 1.682 + default: 1.683 + mEffect->SetValue(input, D2D1::Vector4F(aValue.r * aValue.a, aValue.g * aValue.a, aValue.b * aValue.a, aValue.a)); 1.684 + } 1.685 +} 1.686 + 1.687 +void 1.688 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Rect &aValue) 1.689 +{ 1.690 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.691 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.692 + 1.693 + mEffect->SetValue(input, D2DRect(aValue)); 1.694 +} 1.695 + 1.696 +void 1.697 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue) 1.698 +{ 1.699 + if (mType == FilterType::TURBULENCE) { 1.700 + MOZ_ASSERT(aIndex == ATT_TURBULENCE_RECT); 1.701 + 1.702 + mEffect->SetValue(D2D1_TURBULENCE_PROP_OFFSET, D2D1::Vector2F(Float(aValue.x), Float(aValue.y))); 1.703 + mEffect->SetValue(D2D1_TURBULENCE_PROP_SIZE, D2D1::Vector2F(Float(aValue.width), Float(aValue.height))); 1.704 + return; 1.705 + } 1.706 + 1.707 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.708 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.709 + 1.710 + mEffect->SetValue(input, D2D1::RectF(Float(aValue.x), Float(aValue.y), 1.711 + Float(aValue.XMost()), Float(aValue.YMost()))); 1.712 +} 1.713 + 1.714 +void 1.715 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, bool aValue) 1.716 +{ 1.717 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.718 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.719 + 1.720 + mEffect->SetValue(input, (BOOL)aValue); 1.721 +} 1.722 + 1.723 +void 1.724 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Float *aValues, uint32_t aSize) 1.725 +{ 1.726 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.727 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.728 + 1.729 + mEffect->SetValue(input, (BYTE*)aValues, sizeof(Float) * aSize); 1.730 +} 1.731 + 1.732 +void 1.733 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue) 1.734 +{ 1.735 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.736 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.737 + 1.738 + mEffect->SetValue(input, D2DPoint(aValue)); 1.739 +} 1.740 + 1.741 +void 1.742 +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix) 1.743 +{ 1.744 + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); 1.745 + MOZ_ASSERT(input < mEffect->GetPropertyCount()); 1.746 + 1.747 + mEffect->SetValue(input, D2DMatrix(aMatrix)); 1.748 +} 1.749 + 1.750 +FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC) 1.751 + : FilterNodeD2D1(aDT, nullptr, FilterType::CONVOLVE_MATRIX) 1.752 + , mEdgeMode(EDGE_MODE_DUPLICATE) 1.753 +{ 1.754 + // Correctly handling the interaction of edge mode and source rect is a bit 1.755 + // tricky with D2D1 effects. We want the edge mode to only apply outside of 1.756 + // the source rect (as specified by the ATT_CONVOLVE_MATRIX_SOURCE_RECT 1.757 + // attribute). So if our input surface or filter is smaller than the source 1.758 + // rect, we need to add transparency around it until we reach the edges of 1.759 + // the source rect, and only then do any repeating or edge duplicating. 1.760 + // Unfortunately, D2D1 does not have any "extend with transparency" effect. 1.761 + // (The crop effect can only cut off parts, it can't make the output rect 1.762 + // bigger.) And the border effect does not have a source rect attribute - 1.763 + // it only looks at the output rect of its input filter or surface. 1.764 + // So we use the following trick to extend the input size to the source rect: 1.765 + // Instead of feeding the input directly into the border effect, we first 1.766 + // composite it with a transparent flood effect (which is infinite-sized) and 1.767 + // use a crop effect on the result in order to get the right size. Then we 1.768 + // feed the cropped composition into the border effect, which then finally 1.769 + // feeds into the convolve matrix effect. 1.770 + // All of this is only necessary when our edge mode is not EDGE_MODE_NONE, so 1.771 + // we update the filter chain dynamically in UpdateChain(). 1.772 + 1.773 + HRESULT hr; 1.774 + 1.775 + hr = aDC->CreateEffect(CLSID_D2D1ConvolveMatrix, byRef(mEffect)); 1.776 + 1.777 + if (FAILED(hr)) { 1.778 + gfxWarning() << "Failed to create ConvolveMatrix filter!"; 1.779 + return; 1.780 + } 1.781 + 1.782 + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE, D2D1_BORDER_MODE_SOFT); 1.783 + 1.784 + hr = aDC->CreateEffect(CLSID_D2D1Flood, byRef(mFloodEffect)); 1.785 + 1.786 + if (FAILED(hr)) { 1.787 + gfxWarning() << "Failed to create ConvolveMatrix filter!"; 1.788 + return; 1.789 + } 1.790 + 1.791 + mFloodEffect->SetValue(D2D1_FLOOD_PROP_COLOR, D2D1::Vector4F(0.0f, 0.0f, 0.0f, 0.0f)); 1.792 + 1.793 + hr = aDC->CreateEffect(CLSID_D2D1Composite, byRef(mCompositeEffect)); 1.794 + 1.795 + if (FAILED(hr)) { 1.796 + gfxWarning() << "Failed to create ConvolveMatrix filter!"; 1.797 + return; 1.798 + } 1.799 + 1.800 + mCompositeEffect->SetInputEffect(1, mFloodEffect.get()); 1.801 + 1.802 + hr = aDC->CreateEffect(CLSID_D2D1Crop, byRef(mCropEffect)); 1.803 + 1.804 + if (FAILED(hr)) { 1.805 + gfxWarning() << "Failed to create ConvolveMatrix filter!"; 1.806 + return; 1.807 + } 1.808 + 1.809 + mCropEffect->SetInputEffect(0, mCompositeEffect.get()); 1.810 + 1.811 + hr = aDC->CreateEffect(CLSID_D2D1Border, byRef(mBorderEffect)); 1.812 + 1.813 + if (FAILED(hr)) { 1.814 + gfxWarning() << "Failed to create ConvolveMatrix filter!"; 1.815 + return; 1.816 + } 1.817 + 1.818 + mBorderEffect->SetInputEffect(0, mCropEffect.get()); 1.819 + 1.820 + UpdateChain(); 1.821 + UpdateSourceRect(); 1.822 +} 1.823 + 1.824 +void 1.825 +FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface) 1.826 +{ 1.827 + MOZ_ASSERT(aIndex == 0); 1.828 + 1.829 + mInput = GetImageForSourceSurface(mDT, aSurface); 1.830 + 1.831 + mInputEffect = nullptr; 1.832 + 1.833 + UpdateChain(); 1.834 +} 1.835 + 1.836 +void 1.837 +FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter) 1.838 +{ 1.839 + MOZ_ASSERT(aIndex == 0); 1.840 + 1.841 + if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) { 1.842 + gfxWarning() << "Unknown input SourceSurface set on effect."; 1.843 + MOZ_ASSERT(0); 1.844 + return; 1.845 + } 1.846 + 1.847 + mInput = nullptr; 1.848 + mInputEffect = static_cast<FilterNodeD2D1*>(aFilter)->mEffect; 1.849 + 1.850 + UpdateChain(); 1.851 +} 1.852 + 1.853 +void 1.854 +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue) 1.855 +{ 1.856 + if (aIndex != ATT_CONVOLVE_MATRIX_EDGE_MODE) { 1.857 + return FilterNodeD2D1::SetAttribute(aIndex, aValue); 1.858 + } 1.859 + 1.860 + mEdgeMode = (ConvolveMatrixEdgeMode)aValue; 1.861 + 1.862 + UpdateChain(); 1.863 +} 1.864 + 1.865 +void 1.866 +FilterNodeConvolveD2D1::UpdateChain() 1.867 +{ 1.868 + // The shape of the filter graph: 1.869 + // 1.870 + // EDGE_MODE_NONE: 1.871 + // input --> convolvematrix 1.872 + // 1.873 + // EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP: 1.874 + // input -------v 1.875 + // flood --> composite --> crop --> border --> convolvematrix 1.876 + 1.877 + ID2D1Effect *firstEffect = mCompositeEffect; 1.878 + if (mEdgeMode == EDGE_MODE_NONE) { 1.879 + firstEffect = mEffect; 1.880 + } else { 1.881 + mEffect->SetInputEffect(0, mBorderEffect.get()); 1.882 + } 1.883 + 1.884 + if (mInputEffect) { 1.885 + firstEffect->SetInputEffect(0, mInputEffect); 1.886 + } else { 1.887 + firstEffect->SetInput(0, mInput); 1.888 + } 1.889 + 1.890 + if (mEdgeMode == EDGE_MODE_DUPLICATE) { 1.891 + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_CLAMP); 1.892 + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_CLAMP); 1.893 + } else if (mEdgeMode == EDGE_MODE_WRAP) { 1.894 + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_WRAP); 1.895 + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_WRAP); 1.896 + } 1.897 +} 1.898 + 1.899 +void 1.900 +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue) 1.901 +{ 1.902 + if (aIndex != ATT_CONVOLVE_MATRIX_KERNEL_SIZE) { 1.903 + MOZ_ASSERT(false); 1.904 + return; 1.905 + } 1.906 + 1.907 + mKernelSize = aValue; 1.908 + 1.909 + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X, aValue.width); 1.910 + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y, aValue.height); 1.911 + 1.912 + UpdateOffset(); 1.913 +} 1.914 + 1.915 +void 1.916 +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue) 1.917 +{ 1.918 + if (aIndex != ATT_CONVOLVE_MATRIX_TARGET) { 1.919 + MOZ_ASSERT(false); 1.920 + return; 1.921 + } 1.922 + 1.923 + mTarget = aValue; 1.924 + 1.925 + UpdateOffset(); 1.926 +} 1.927 + 1.928 +void 1.929 +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue) 1.930 +{ 1.931 + if (aIndex != ATT_CONVOLVE_MATRIX_SOURCE_RECT) { 1.932 + MOZ_ASSERT(false); 1.933 + return; 1.934 + } 1.935 + 1.936 + mSourceRect = aValue; 1.937 + 1.938 + UpdateSourceRect(); 1.939 +} 1.940 + 1.941 +void 1.942 +FilterNodeConvolveD2D1::UpdateOffset() 1.943 +{ 1.944 + D2D1_VECTOR_2F vector = 1.945 + D2D1::Vector2F((Float(mKernelSize.width) - 1.0f) / 2.0f - Float(mTarget.x), 1.946 + (Float(mKernelSize.height) - 1.0f) / 2.0f - Float(mTarget.y)); 1.947 + 1.948 + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET, vector); 1.949 +} 1.950 + 1.951 +void 1.952 +FilterNodeConvolveD2D1::UpdateSourceRect() 1.953 +{ 1.954 + mCropEffect->SetValue(D2D1_CROP_PROP_RECT, 1.955 + D2D1::RectF(Float(mSourceRect.x), Float(mSourceRect.y), 1.956 + Float(mSourceRect.XMost()), Float(mSourceRect.YMost()))); 1.957 +} 1.958 + 1.959 +FilterNodeComponentTransferD2D1::FilterNodeComponentTransferD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC, 1.960 + ID2D1Effect *aEffect, FilterType aType) 1.961 + : FilterNodeD2D1(aDT, aEffect, aType) 1.962 +{ 1.963 + // D2D1 component transfer effects do strange things when it comes to 1.964 + // premultiplication. 1.965 + // For our purposes we only need the transfer filters to apply straight to 1.966 + // unpremultiplied source channels and output unpremultiplied results. 1.967 + // However, the D2D1 effects are designed differently: They can apply to both 1.968 + // premultiplied and unpremultiplied inputs, and they always premultiply 1.969 + // their result - at least in those color channels that have not been 1.970 + // disabled. 1.971 + // In order to determine whether the input needs to be unpremultiplied as 1.972 + // part of the transfer, the effect consults the alpha mode metadata of the 1.973 + // input surface or the input effect. We don't have such a concept in Moz2D, 1.974 + // and giving Moz2D users different results based on something that cannot be 1.975 + // influenced through Moz2D APIs seems like a bad idea. 1.976 + // We solve this by applying a premultiply effect to the input before feeding 1.977 + // it into the transfer effect. The premultiply effect always premultiplies 1.978 + // regardless of any alpha mode metadata on inputs, and it always marks its 1.979 + // output as premultiplied so that the transfer effect will unpremultiply 1.980 + // consistently. Feeding always-premultiplied input into the transfer effect 1.981 + // also avoids another problem that would appear when individual color 1.982 + // channels disable the transfer: In that case, the disabled channels would 1.983 + // pass through unchanged in their unpremultiplied form and the other 1.984 + // channels would be premultiplied, giving a mixed result. 1.985 + // But since we now ensure that the input is premultiplied, disabled channels 1.986 + // will pass premultiplied values through to the result, which is consistent 1.987 + // with the enabled channels. 1.988 + // We also add an unpremultiply effect that postprocesses the result of the 1.989 + // transfer effect because getting unpremultiplied results from the transfer 1.990 + // filters is part of the FilterNode API. 1.991 + HRESULT hr; 1.992 + 1.993 + hr = aDC->CreateEffect(CLSID_D2D1Premultiply, byRef(mPrePremultiplyEffect)); 1.994 + 1.995 + if (FAILED(hr)) { 1.996 + gfxWarning() << "Failed to create ComponentTransfer filter!"; 1.997 + return; 1.998 + } 1.999 + 1.1000 + hr = aDC->CreateEffect(CLSID_D2D1UnPremultiply, byRef(mPostUnpremultiplyEffect)); 1.1001 + 1.1002 + if (FAILED(hr)) { 1.1003 + gfxWarning() << "Failed to create ComponentTransfer filter!"; 1.1004 + return; 1.1005 + } 1.1006 + 1.1007 + mEffect->SetInputEffect(0, mPrePremultiplyEffect.get()); 1.1008 + mPostUnpremultiplyEffect->SetInputEffect(0, mEffect.get()); 1.1009 +} 1.1010 + 1.1011 +} 1.1012 +}