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.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "FilterNodeD2D1.h"
     8 #include "Logging.h"
    10 #include "SourceSurfaceD2D1.h"
    11 #include "SourceSurfaceD2D.h"
    12 #include "SourceSurfaceD2DTarget.h"
    13 #include "DrawTargetD2D.h"
    14 #include "DrawTargetD2D1.h"
    16 namespace mozilla {
    17 namespace gfx {
    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   }
    30   return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED;
    31 }
    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   }
    46   return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR;
    47 }
    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   }
    64   return D2D1_BLEND_MODE_DARKEN;
    65 }
    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   }
    76   MOZ_CRASH("Unknown enum value!");
    77   return D2D1_MORPHOLOGY_MODE_DILATE;
    78 }
    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   }
    89   MOZ_CRASH("Unknown enum value!");
    90   return D2D1_TURBULENCE_NOISE_TURBULENCE;
    91 }
    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   }
   108   MOZ_CRASH("Unknown enum value!");
   109   return D2D1_COMPOSITE_MODE_SOURCE_OVER;
   110 }
   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   }
   125   MOZ_CRASH("Unknown enum value!");
   126   return D2D1_CHANNEL_SELECTOR_R;
   127 }
   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 }
   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   }
   183   return aValue;
   184 }
   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 }
   200 UINT32
   201 GetD2D1InputForInput(FilterType aType, uint32_t aIndex)
   202 {
   203   return aIndex;
   204 }
   206 #define CONVERT_PROP(moz2dname, d2dname) \
   207   case ATT_##moz2dname: \
   208   return D2D1_##d2dname
   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   }
   422   return UINT32_MAX;
   423 }
   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 }
   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 }
   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   }
   505   RefPtr<ID2D1Effect> effect;
   506   HRESULT hr;
   508   hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), byRef(effect));
   510   if (FAILED(hr)) {
   511     gfxWarning() << "Failed to create effect for FilterType: " << hr;
   512     return nullptr;
   513   }
   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 }
   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 }
   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());
   545   if (mType == FilterType::COMPOSITE) {
   546     UINT32 inputCount = effect->GetInputCount();
   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   }
   555   RefPtr<ID2D1Image> image = GetImageForSourceSurface(mDT, aSurface);
   556   effect->SetInput(input, image);
   557 }
   559 void
   560 FilterNodeD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
   561 {
   562   UINT32 input = GetD2D1InputForInput(mType, aIndex);
   563   ID2D1Effect* effect = InputEffect();
   565   if (mType == FilterType::COMPOSITE) {
   566     UINT32 inputCount = effect->GetInputCount();
   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   }
   575    MOZ_ASSERT(input < effect->GetInputCount());
   577   if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
   578     gfxWarning() << "Unknown input SourceSurface set on effect.";
   579     MOZ_ASSERT(0);
   580     return;
   581   }
   583   effect->SetInputEffect(input, static_cast<FilterNodeD2D1*>(aFilter)->OutputEffect());
   584 }
   586 void
   587 FilterNodeD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue)
   588 {
   589   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   590   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   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   }
   600   mEffect->SetValue(input, ConvertValue(mType, aIndex, aValue));
   601 }
   603 void
   604 FilterNodeD2D1::SetAttribute(uint32_t aIndex, Float aValue)
   605 {
   606   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   607   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   609   mEffect->SetValue(input, aValue);
   610 }
   612 void
   613 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point &aValue)
   614 {
   615   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   616   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   618   mEffect->SetValue(input, D2DPoint(aValue));
   619 }
   621 void
   622 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix5x4 &aValue)
   623 {
   624   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   625   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   627   mEffect->SetValue(input, D2DMatrix5x4(aValue));
   628 }
   630 void
   631 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point3D &aValue)
   632 {
   633   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   634   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   636   mEffect->SetValue(input, D2DVector3D(aValue));
   637 }
   639 void
   640 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Size &aValue)
   641 {
   642   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   643   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   645   mEffect->SetValue(input, D2D1::Vector2F(aValue.width, aValue.height));
   646 }
   648 void
   649 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue)
   650 {
   651   UINT32 widthProp, heightProp;
   653   if (!GetD2D1PropsForIntSize(mType, aIndex, &widthProp, &heightProp)) {
   654     return;
   655   }
   657   IntSize value = aValue;
   658   ConvertValue(mType, aIndex, value);
   660   mEffect->SetValue(widthProp, (UINT)value.width);
   661   mEffect->SetValue(heightProp, (UINT)value.height);
   662 }
   664 void
   665 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Color &aValue)
   666 {
   667   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   668   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   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 }
   684 void
   685 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Rect &aValue)
   686 {
   687   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   688   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   690   mEffect->SetValue(input, D2DRect(aValue));
   691 }
   693 void
   694 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue)
   695 {
   696   if (mType == FilterType::TURBULENCE) {
   697     MOZ_ASSERT(aIndex == ATT_TURBULENCE_RECT);
   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   }
   704   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   705   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   707   mEffect->SetValue(input, D2D1::RectF(Float(aValue.x), Float(aValue.y),
   708                                        Float(aValue.XMost()), Float(aValue.YMost())));
   709 }
   711 void
   712 FilterNodeD2D1::SetAttribute(uint32_t aIndex, bool aValue)
   713 {
   714   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   715   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   717   mEffect->SetValue(input, (BOOL)aValue);
   718 }
   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());
   726   mEffect->SetValue(input, (BYTE*)aValues, sizeof(Float) * aSize);
   727 }
   729 void
   730 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue)
   731 {
   732   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   733   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   735   mEffect->SetValue(input, D2DPoint(aValue));
   736 }
   738 void
   739 FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix)
   740 {
   741   UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
   742   MOZ_ASSERT(input < mEffect->GetPropertyCount());
   744   mEffect->SetValue(input, D2DMatrix(aMatrix));
   745 }
   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().
   770   HRESULT hr;
   772   hr = aDC->CreateEffect(CLSID_D2D1ConvolveMatrix, byRef(mEffect));
   774   if (FAILED(hr)) {
   775     gfxWarning() << "Failed to create ConvolveMatrix filter!";
   776     return;
   777   }
   779   mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE, D2D1_BORDER_MODE_SOFT);
   781   hr = aDC->CreateEffect(CLSID_D2D1Flood, byRef(mFloodEffect));
   783   if (FAILED(hr)) {
   784     gfxWarning() << "Failed to create ConvolveMatrix filter!";
   785     return;
   786   }
   788   mFloodEffect->SetValue(D2D1_FLOOD_PROP_COLOR, D2D1::Vector4F(0.0f, 0.0f, 0.0f, 0.0f));
   790   hr = aDC->CreateEffect(CLSID_D2D1Composite, byRef(mCompositeEffect));
   792   if (FAILED(hr)) {
   793     gfxWarning() << "Failed to create ConvolveMatrix filter!";
   794     return;
   795   }
   797   mCompositeEffect->SetInputEffect(1, mFloodEffect.get());
   799   hr = aDC->CreateEffect(CLSID_D2D1Crop, byRef(mCropEffect));
   801   if (FAILED(hr)) {
   802     gfxWarning() << "Failed to create ConvolveMatrix filter!";
   803     return;
   804   }
   806   mCropEffect->SetInputEffect(0, mCompositeEffect.get());
   808   hr = aDC->CreateEffect(CLSID_D2D1Border, byRef(mBorderEffect));
   810   if (FAILED(hr)) {
   811     gfxWarning() << "Failed to create ConvolveMatrix filter!";
   812     return;
   813   }
   815   mBorderEffect->SetInputEffect(0, mCropEffect.get());
   817   UpdateChain();
   818   UpdateSourceRect();
   819 }
   821 void
   822 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface)
   823 {
   824   MOZ_ASSERT(aIndex == 0);
   826   mInput = GetImageForSourceSurface(mDT, aSurface);
   828   mInputEffect = nullptr;
   830   UpdateChain();
   831 }
   833 void
   834 FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter)
   835 {
   836   MOZ_ASSERT(aIndex == 0);
   838   if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
   839     gfxWarning() << "Unknown input SourceSurface set on effect.";
   840     MOZ_ASSERT(0);
   841     return;
   842   }
   844   mInput = nullptr;
   845   mInputEffect = static_cast<FilterNodeD2D1*>(aFilter)->mEffect;
   847   UpdateChain();
   848 }
   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   }
   857   mEdgeMode = (ConvolveMatrixEdgeMode)aValue;
   859   UpdateChain();
   860 }
   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
   874   ID2D1Effect *firstEffect = mCompositeEffect;
   875   if (mEdgeMode == EDGE_MODE_NONE) {
   876     firstEffect = mEffect;
   877   } else {
   878     mEffect->SetInputEffect(0, mBorderEffect.get());
   879   }
   881   if (mInputEffect) {
   882     firstEffect->SetInputEffect(0, mInputEffect);
   883   } else {
   884     firstEffect->SetInput(0, mInput);
   885   }
   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 }
   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   }
   904   mKernelSize = aValue;
   906   mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X, aValue.width);
   907   mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y, aValue.height);
   909   UpdateOffset();
   910 }
   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   }
   920   mTarget = aValue;
   922   UpdateOffset();
   923 }
   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   }
   933   mSourceRect = aValue;
   935   UpdateSourceRect();
   936 }
   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));
   945   mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET, vector);
   946 }
   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 }
   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;
   990   hr = aDC->CreateEffect(CLSID_D2D1Premultiply, byRef(mPrePremultiplyEffect));
   992   if (FAILED(hr)) {
   993     gfxWarning() << "Failed to create ComponentTransfer filter!";
   994     return;
   995   }
   997   hr = aDC->CreateEffect(CLSID_D2D1UnPremultiply, byRef(mPostUnpremultiplyEffect));
   999   if (FAILED(hr)) {
  1000     gfxWarning() << "Failed to create ComponentTransfer filter!";
  1001     return;
  1004   mEffect->SetInputEffect(0, mPrePremultiplyEffect.get());
  1005   mPostUnpremultiplyEffect->SetInputEffect(0, mEffect.get());

mercurial