gfx/2d/FilterNodeD2D1.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial