LCOV - code coverage report
Current view: top level - gfx/src - FilterSupport.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 938 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 106 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "FilterSupport.h"
       7             : 
       8             : #include "mozilla/gfx/2D.h"
       9             : #include "mozilla/gfx/Filters.h"
      10             : #include "mozilla/gfx/Logging.h"
      11             : #include "mozilla/PodOperations.h"
      12             : 
      13             : #include "gfxContext.h"
      14             : #include "gfxPattern.h"
      15             : #include "gfxPlatform.h"
      16             : #include "gfx2DGlue.h"
      17             : 
      18             : #include "nsMargin.h"
      19             : 
      20             : // c = n / 255
      21             : // c <= 0.0031308f ? c * 12.92f : 1.055f * powf(c, 1 / 2.4f) - 0.055f
      22             : static const float glinearRGBTosRGBMap[256] = {
      23             :   0.000f, 0.050f, 0.085f, 0.111f, 0.132f, 0.150f, 0.166f, 0.181f,
      24             :   0.194f, 0.207f, 0.219f, 0.230f, 0.240f, 0.250f, 0.260f, 0.269f,
      25             :   0.278f, 0.286f, 0.295f, 0.303f, 0.310f, 0.318f, 0.325f, 0.332f,
      26             :   0.339f, 0.346f, 0.352f, 0.359f, 0.365f, 0.371f, 0.378f, 0.383f,
      27             :   0.389f, 0.395f, 0.401f, 0.406f, 0.412f, 0.417f, 0.422f, 0.427f,
      28             :   0.433f, 0.438f, 0.443f, 0.448f, 0.452f, 0.457f, 0.462f, 0.466f,
      29             :   0.471f, 0.476f, 0.480f, 0.485f, 0.489f, 0.493f, 0.498f, 0.502f,
      30             :   0.506f, 0.510f, 0.514f, 0.518f, 0.522f, 0.526f, 0.530f, 0.534f,
      31             :   0.538f, 0.542f, 0.546f, 0.549f, 0.553f, 0.557f, 0.561f, 0.564f,
      32             :   0.568f, 0.571f, 0.575f, 0.579f, 0.582f, 0.586f, 0.589f, 0.592f,
      33             :   0.596f, 0.599f, 0.603f, 0.606f, 0.609f, 0.613f, 0.616f, 0.619f,
      34             :   0.622f, 0.625f, 0.629f, 0.632f, 0.635f, 0.638f, 0.641f, 0.644f,
      35             :   0.647f, 0.650f, 0.653f, 0.656f, 0.659f, 0.662f, 0.665f, 0.668f,
      36             :   0.671f, 0.674f, 0.677f, 0.680f, 0.683f, 0.685f, 0.688f, 0.691f,
      37             :   0.694f, 0.697f, 0.699f, 0.702f, 0.705f, 0.708f, 0.710f, 0.713f,
      38             :   0.716f, 0.718f, 0.721f, 0.724f, 0.726f, 0.729f, 0.731f, 0.734f,
      39             :   0.737f, 0.739f, 0.742f, 0.744f, 0.747f, 0.749f, 0.752f, 0.754f,
      40             :   0.757f, 0.759f, 0.762f, 0.764f, 0.767f, 0.769f, 0.772f, 0.774f,
      41             :   0.776f, 0.779f, 0.781f, 0.784f, 0.786f, 0.788f, 0.791f, 0.793f,
      42             :   0.795f, 0.798f, 0.800f, 0.802f, 0.805f, 0.807f, 0.809f, 0.812f,
      43             :   0.814f, 0.816f, 0.818f, 0.821f, 0.823f, 0.825f, 0.827f, 0.829f,
      44             :   0.832f, 0.834f, 0.836f, 0.838f, 0.840f, 0.843f, 0.845f, 0.847f,
      45             :   0.849f, 0.851f, 0.853f, 0.855f, 0.857f, 0.860f, 0.862f, 0.864f,
      46             :   0.866f, 0.868f, 0.870f, 0.872f, 0.874f, 0.876f, 0.878f, 0.880f,
      47             :   0.882f, 0.884f, 0.886f, 0.888f, 0.890f, 0.892f, 0.894f, 0.896f,
      48             :   0.898f, 0.900f, 0.902f, 0.904f, 0.906f, 0.908f, 0.910f, 0.912f,
      49             :   0.914f, 0.916f, 0.918f, 0.920f, 0.922f, 0.924f, 0.926f, 0.928f,
      50             :   0.930f, 0.931f, 0.933f, 0.935f, 0.937f, 0.939f, 0.941f, 0.943f,
      51             :   0.945f, 0.946f, 0.948f, 0.950f, 0.952f, 0.954f, 0.956f, 0.957f,
      52             :   0.959f, 0.961f, 0.963f, 0.965f, 0.967f, 0.968f, 0.970f, 0.972f,
      53             :   0.974f, 0.975f, 0.977f, 0.979f, 0.981f, 0.983f, 0.984f, 0.986f,
      54             :   0.988f, 0.990f, 0.991f, 0.993f, 0.995f, 0.997f, 0.998f, 1.000f
      55             : };
      56             : 
      57             : // c = n / 255
      58             : // c <= 0.04045f ? c / 12.92f : powf((c + 0.055f) / 1.055f, 2.4f)
      59             : static const float gsRGBToLinearRGBMap[256] = {
      60             :   0.000f, 0.000f, 0.001f, 0.001f, 0.001f, 0.002f, 0.002f, 0.002f,
      61             :   0.002f, 0.003f, 0.003f, 0.003f, 0.004f, 0.004f, 0.004f, 0.005f,
      62             :   0.005f, 0.006f, 0.006f, 0.007f, 0.007f, 0.007f, 0.008f, 0.009f,
      63             :   0.009f, 0.010f, 0.010f, 0.011f, 0.012f, 0.012f, 0.013f, 0.014f,
      64             :   0.014f, 0.015f, 0.016f, 0.017f, 0.018f, 0.019f, 0.019f, 0.020f,
      65             :   0.021f, 0.022f, 0.023f, 0.024f, 0.025f, 0.026f, 0.027f, 0.028f,
      66             :   0.030f, 0.031f, 0.032f, 0.033f, 0.034f, 0.036f, 0.037f, 0.038f,
      67             :   0.040f, 0.041f, 0.042f, 0.044f, 0.045f, 0.047f, 0.048f, 0.050f,
      68             :   0.051f, 0.053f, 0.054f, 0.056f, 0.058f, 0.060f, 0.061f, 0.063f,
      69             :   0.065f, 0.067f, 0.068f, 0.070f, 0.072f, 0.074f, 0.076f, 0.078f,
      70             :   0.080f, 0.082f, 0.084f, 0.087f, 0.089f, 0.091f, 0.093f, 0.095f,
      71             :   0.098f, 0.100f, 0.102f, 0.105f, 0.107f, 0.109f, 0.112f, 0.114f,
      72             :   0.117f, 0.120f, 0.122f, 0.125f, 0.127f, 0.130f, 0.133f, 0.136f,
      73             :   0.138f, 0.141f, 0.144f, 0.147f, 0.150f, 0.153f, 0.156f, 0.159f,
      74             :   0.162f, 0.165f, 0.168f, 0.171f, 0.175f, 0.178f, 0.181f, 0.184f,
      75             :   0.188f, 0.191f, 0.195f, 0.198f, 0.202f, 0.205f, 0.209f, 0.212f,
      76             :   0.216f, 0.220f, 0.223f, 0.227f, 0.231f, 0.235f, 0.238f, 0.242f,
      77             :   0.246f, 0.250f, 0.254f, 0.258f, 0.262f, 0.266f, 0.270f, 0.275f,
      78             :   0.279f, 0.283f, 0.287f, 0.292f, 0.296f, 0.301f, 0.305f, 0.309f,
      79             :   0.314f, 0.319f, 0.323f, 0.328f, 0.332f, 0.337f, 0.342f, 0.347f,
      80             :   0.352f, 0.356f, 0.361f, 0.366f, 0.371f, 0.376f, 0.381f, 0.386f,
      81             :   0.392f, 0.397f, 0.402f, 0.407f, 0.413f, 0.418f, 0.423f, 0.429f,
      82             :   0.434f, 0.440f, 0.445f, 0.451f, 0.456f, 0.462f, 0.468f, 0.474f,
      83             :   0.479f, 0.485f, 0.491f, 0.497f, 0.503f, 0.509f, 0.515f, 0.521f,
      84             :   0.527f, 0.533f, 0.539f, 0.546f, 0.552f, 0.558f, 0.565f, 0.571f,
      85             :   0.578f, 0.584f, 0.591f, 0.597f, 0.604f, 0.610f, 0.617f, 0.624f,
      86             :   0.631f, 0.638f, 0.644f, 0.651f, 0.658f, 0.665f, 0.672f, 0.680f,
      87             :   0.687f, 0.694f, 0.701f, 0.708f, 0.716f, 0.723f, 0.730f, 0.738f,
      88             :   0.745f, 0.753f, 0.761f, 0.768f, 0.776f, 0.784f, 0.791f, 0.799f,
      89             :   0.807f, 0.815f, 0.823f, 0.831f, 0.839f, 0.847f, 0.855f, 0.863f,
      90             :   0.871f, 0.880f, 0.888f, 0.896f, 0.905f, 0.913f, 0.922f, 0.930f,
      91             :   0.939f, 0.947f, 0.956f, 0.965f, 0.973f, 0.982f, 0.991f, 1.000f
      92             : };
      93             : 
      94             : namespace mozilla {
      95             : namespace gfx {
      96             : 
      97             : // Some convenience FilterNode creation functions.
      98             : 
      99             : namespace FilterWrappers {
     100             : 
     101             :   static already_AddRefed<FilterNode>
     102           0 :   Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
     103             :   {
     104           0 :     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
     105           0 :     if (filter) {
     106           0 :       filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
     107           0 :       return filter.forget();
     108             :     }
     109           0 :     return nullptr;
     110             :   }
     111             : 
     112             :   static already_AddRefed<FilterNode>
     113           0 :   Premultiply(DrawTarget* aDT, FilterNode* aInput)
     114             :   {
     115           0 :     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::PREMULTIPLY);
     116           0 :     if (filter) {
     117           0 :       filter->SetInput(IN_PREMULTIPLY_IN, aInput);
     118           0 :       return filter.forget();
     119             :     }
     120           0 :     return nullptr;
     121             :   }
     122             : 
     123             :   static already_AddRefed<FilterNode>
     124           0 :   LinearRGBToSRGB(DrawTarget* aDT, FilterNode* aInput)
     125             :   {
     126           0 :     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
     127           0 :     if (transfer) {
     128           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
     129           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
     130           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
     131           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
     132           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
     133           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
     134           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
     135           0 :       transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
     136           0 :       return transfer.forget();
     137             :     }
     138           0 :     return nullptr;
     139             :   }
     140             : 
     141             :   static already_AddRefed<FilterNode>
     142           0 :   SRGBToLinearRGB(DrawTarget* aDT, FilterNode* aInput)
     143             :   {
     144           0 :     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
     145           0 :     if (transfer) {
     146           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
     147           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
     148           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
     149           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
     150           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
     151           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
     152           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
     153           0 :       transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
     154           0 :       return transfer.forget();
     155             :     }
     156           0 :     return nullptr;
     157             :   }
     158             : 
     159             :   static already_AddRefed<FilterNode>
     160           0 :   Crop(DrawTarget* aDT, FilterNode* aInputFilter, const IntRect& aRect)
     161             :   {
     162           0 :     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CROP);
     163           0 :     if (filter) {
     164           0 :       filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
     165           0 :       filter->SetInput(IN_CROP_IN, aInputFilter);
     166           0 :       return filter.forget();
     167             :     }
     168           0 :     return nullptr;
     169             :   }
     170             : 
     171             :   static already_AddRefed<FilterNode>
     172           0 :   Offset(DrawTarget* aDT, FilterNode* aInputFilter, const IntPoint& aOffset)
     173             :   {
     174           0 :     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
     175           0 :     if (filter) {
     176           0 :       filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
     177           0 :       filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
     178           0 :       return filter.forget();
     179             :     }
     180           0 :     return nullptr;
     181             :   }
     182             : 
     183             :   static already_AddRefed<FilterNode>
     184           0 :   GaussianBlur(DrawTarget* aDT, FilterNode* aInputFilter, const Size& aStdDeviation)
     185             :   {
     186           0 :     float stdX = float(std::min(aStdDeviation.width, kMaxStdDeviation));
     187           0 :     float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
     188           0 :     if (stdX == stdY) {
     189           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
     190           0 :       if (filter) {
     191           0 :         filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
     192           0 :         filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
     193           0 :         return filter.forget();
     194             :       }
     195           0 :       return nullptr;
     196             :     }
     197           0 :     RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
     198           0 :     RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
     199           0 :     if (filterH && filterV) {
     200           0 :       filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
     201           0 :       filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
     202           0 :       filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
     203           0 :       filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
     204           0 :       filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
     205           0 :       filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
     206           0 :       return filterV.forget();
     207             :     }
     208           0 :     return nullptr;
     209             :   }
     210             : 
     211             :   static already_AddRefed<FilterNode>
     212           0 :   Clear(DrawTarget* aDT)
     213             :   {
     214           0 :     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
     215           0 :     if (filter) {
     216           0 :       filter->SetAttribute(ATT_FLOOD_COLOR, Color(0, 0, 0, 0));
     217           0 :       return filter.forget();
     218             :     }
     219           0 :     return nullptr;
     220             :   }
     221             : 
     222             :   static already_AddRefed<FilterNode>
     223           0 :   ForSurface(DrawTarget* aDT, SourceSurface* aSurface,
     224             :              const IntPoint& aSurfacePosition)
     225             :   {
     226           0 :     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
     227           0 :     if (filter) {
     228           0 :       filter->SetAttribute(ATT_TRANSFORM_MATRIX,
     229           0 :         Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
     230           0 :       filter->SetInput(IN_TRANSFORM_IN, aSurface);
     231           0 :       return filter.forget();
     232             :     }
     233           0 :     return nullptr;
     234             :   }
     235             : 
     236             :   static already_AddRefed<FilterNode>
     237           0 :   ToAlpha(DrawTarget* aDT, FilterNode* aInput)
     238             :   {
     239           0 :     float zero = 0.0f;
     240           0 :     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
     241           0 :     if (transfer) {
     242           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
     243           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
     244           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
     245           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
     246           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
     247           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
     248           0 :       transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
     249           0 :       transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
     250           0 :       return transfer.forget();
     251             :     }
     252           0 :     return nullptr;
     253             :   }
     254             : 
     255             : } // namespace FilterWrappers
     256             : 
     257             : // A class that wraps a FilterNode and handles conversion between different
     258             : // color models. Create FilterCachedColorModels with your original filter and
     259             : // the color model that this filter outputs in natively, and then call
     260             : // ->ForColorModel(colorModel) in order to get a FilterNode which outputs to
     261             : // the specified colorModel.
     262             : // Internally, this is achieved by wrapping the original FilterNode with
     263             : // conversion FilterNodes. These filter nodes are cached in such a way that no
     264             : // repeated or back-and-forth conversions happen.
     265             : class FilterCachedColorModels
     266             : {
     267             : public:
     268           0 :   NS_INLINE_DECL_REFCOUNTING(FilterCachedColorModels)
     269             :   // aFilter can be null. In that case, ForColorModel will return a non-null
     270             :   // completely transparent filter for all color models.
     271             :   FilterCachedColorModels(DrawTarget* aDT,
     272             :                           FilterNode* aFilter,
     273             :                           ColorModel aOriginalColorModel);
     274             : 
     275             :   // Get a FilterNode for the specified color model, guaranteed to be non-null.
     276             :   already_AddRefed<FilterNode> ForColorModel(ColorModel aColorModel);
     277             : 
     278           0 :   AlphaModel OriginalAlphaModel() const { return mOriginalColorModel.mAlphaModel; }
     279             : 
     280             : private:
     281             :   // Create the required FilterNode that will be cached by ForColorModel.
     282             :   already_AddRefed<FilterNode> WrapForColorModel(ColorModel aColorModel);
     283             : 
     284             :   RefPtr<DrawTarget> mDT;
     285             :   ColorModel mOriginalColorModel;
     286             : 
     287             :   // This array is indexed by ColorModel::ToIndex.
     288             :   RefPtr<FilterNode> mFilterForColorModel[4];
     289             : 
     290           0 :   ~FilterCachedColorModels() {}
     291             : };
     292             : 
     293           0 : FilterCachedColorModels::FilterCachedColorModels(DrawTarget* aDT,
     294             :                                                  FilterNode* aFilter,
     295           0 :                                                  ColorModel aOriginalColorModel)
     296             :  : mDT(aDT)
     297           0 :  , mOriginalColorModel(aOriginalColorModel)
     298             : {
     299           0 :   if (aFilter) {
     300           0 :     mFilterForColorModel[aOriginalColorModel.ToIndex()] = aFilter;
     301             :   } else {
     302           0 :     RefPtr<FilterNode> clear = FilterWrappers::Clear(aDT);
     303           0 :     mFilterForColorModel[0] = clear;
     304           0 :     mFilterForColorModel[1] = clear;
     305           0 :     mFilterForColorModel[2] = clear;
     306           0 :     mFilterForColorModel[3] = clear;
     307             :   }
     308           0 : }
     309             : 
     310             : already_AddRefed<FilterNode>
     311           0 : FilterCachedColorModels::ForColorModel(ColorModel aColorModel)
     312             : {
     313           0 :   if (aColorModel == mOriginalColorModel) {
     314             :     // Make sure to not call WrapForColorModel if our original filter node was
     315             :     // null, because then we'd get an infinite recursion.
     316           0 :     RefPtr<FilterNode> filter = mFilterForColorModel[mOriginalColorModel.ToIndex()];
     317           0 :     return filter.forget();
     318             :   }
     319             : 
     320           0 :   if (!mFilterForColorModel[aColorModel.ToIndex()]) {
     321           0 :     mFilterForColorModel[aColorModel.ToIndex()] = WrapForColorModel(aColorModel);
     322             :   }
     323           0 :   RefPtr<FilterNode> filter(mFilterForColorModel[aColorModel.ToIndex()]);
     324           0 :   return filter.forget();
     325             : }
     326             : 
     327             : already_AddRefed<FilterNode>
     328           0 : FilterCachedColorModels::WrapForColorModel(ColorModel aColorModel)
     329             : {
     330             :   // Convert one aspect at a time and recurse.
     331             :   // Conversions between premultiplied / unpremultiplied color channels for the
     332             :   // same color space can happen directly.
     333             :   // Conversions between different color spaces can only happen on
     334             :   // unpremultiplied color channels.
     335             : 
     336           0 :   if (aColorModel.mAlphaModel == AlphaModel::Premultiplied) {
     337             :     RefPtr<FilterNode> unpre =
     338           0 :       ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Unpremultiplied));
     339           0 :     return FilterWrappers::Premultiply(mDT, unpre);
     340             :   }
     341             : 
     342           0 :   MOZ_ASSERT(aColorModel.mAlphaModel == AlphaModel::Unpremultiplied);
     343           0 :   if (aColorModel.mColorSpace == mOriginalColorModel.mColorSpace) {
     344             :     RefPtr<FilterNode> premultiplied =
     345           0 :       ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Premultiplied));
     346           0 :     return FilterWrappers::Unpremultiply(mDT, premultiplied);
     347             :   }
     348             : 
     349             :   RefPtr<FilterNode> unpremultipliedOriginal =
     350           0 :     ForColorModel(ColorModel(mOriginalColorModel.mColorSpace, AlphaModel::Unpremultiplied));
     351           0 :   if (aColorModel.mColorSpace == ColorSpace::LinearRGB) {
     352           0 :     return FilterWrappers::SRGBToLinearRGB(mDT, unpremultipliedOriginal);
     353             :   }
     354           0 :   return FilterWrappers::LinearRGBToSRGB(mDT, unpremultipliedOriginal);
     355             : }
     356             : 
     357             : static const float identityMatrix[] =
     358             :   { 1, 0, 0, 0, 0,
     359             :     0, 1, 0, 0, 0,
     360             :     0, 0, 1, 0, 0,
     361             :     0, 0, 0, 1, 0 };
     362             : 
     363             : // When aAmount == 0, the identity matrix is returned.
     364             : // When aAmount == 1, aToMatrix is returned.
     365             : // When aAmount > 1, an exaggerated version of aToMatrix is returned. This can
     366             : // be useful in certain cases, such as producing a color matrix to oversaturate
     367             : // an image.
     368             : //
     369             : // This function is a shortcut of a full matrix addition and a scalar multiply,
     370             : // and it assumes that the following elements in aToMatrix are 0 and 1:
     371             : //   x x x 0 0
     372             : //   x x x 0 0
     373             : //   x x x 0 0
     374             : //   0 0 0 1 0
     375             : static void
     376           0 : InterpolateFromIdentityMatrix(const float aToMatrix[20], float aAmount,
     377             :                               float aOutMatrix[20])
     378             : {
     379           0 :   PodCopy(aOutMatrix, identityMatrix, 20);
     380             : 
     381           0 :   float oneMinusAmount = 1 - aAmount;
     382             : 
     383           0 :   aOutMatrix[0] = aAmount * aToMatrix[0] + oneMinusAmount;
     384           0 :   aOutMatrix[1] = aAmount * aToMatrix[1];
     385           0 :   aOutMatrix[2] = aAmount * aToMatrix[2];
     386             : 
     387           0 :   aOutMatrix[5] = aAmount * aToMatrix[5];
     388           0 :   aOutMatrix[6] = aAmount * aToMatrix[6] + oneMinusAmount;
     389           0 :   aOutMatrix[7] = aAmount * aToMatrix[7];
     390             : 
     391           0 :   aOutMatrix[10] = aAmount * aToMatrix[10];
     392           0 :   aOutMatrix[11] = aAmount * aToMatrix[11];
     393           0 :   aOutMatrix[12] = aAmount * aToMatrix[12] + oneMinusAmount;
     394           0 : }
     395             : 
     396             : // Create a 4x5 color matrix for the different ways to specify color matrices
     397             : // in SVG.
     398             : static nsresult
     399           0 : ComputeColorMatrix(uint32_t aColorMatrixType, const nsTArray<float>& aValues,
     400             :                    float aOutMatrix[20])
     401             : {
     402             :   // Luminance coefficients.
     403             :   static const float lumR = 0.2126f;
     404             :   static const float lumG = 0.7152f;
     405             :   static const float lumB = 0.0722f;
     406             : 
     407             :   static const float oneMinusLumR = 1 - lumR;
     408             :   static const float oneMinusLumG = 1 - lumG;
     409             :   static const float oneMinusLumB = 1 - lumB;
     410             : 
     411             :   static const float luminanceToAlphaMatrix[] =
     412             :     { 0,    0,    0,    0, 0,
     413             :       0,    0,    0,    0, 0,
     414             :       0,    0,    0,    0, 0,
     415             :       lumR, lumG, lumB, 0, 0 };
     416             : 
     417             :   static const float saturateMatrix[] =
     418             :     { lumR, lumG, lumB, 0, 0,
     419             :       lumR, lumG, lumB, 0, 0,
     420             :       lumR, lumG, lumB, 0, 0,
     421             :       0,    0,    0,    1, 0 };
     422             : 
     423             :   static const float sepiaMatrix[] =
     424             :     { 0.393f, 0.769f, 0.189f, 0, 0,
     425             :       0.349f, 0.686f, 0.168f, 0, 0,
     426             :       0.272f, 0.534f, 0.131f, 0, 0,
     427             :       0,      0,      0,      1, 0 };
     428             : 
     429             :   // Hue rotate specific coefficients.
     430             :   static const float hueRotateR = 0.143f;
     431             :   static const float hueRotateG = 0.140f;
     432             :   static const float hueRotateB = 0.283f;
     433             : 
     434           0 :   switch (aColorMatrixType) {
     435             : 
     436             :     case SVG_FECOLORMATRIX_TYPE_MATRIX:
     437             :     {
     438           0 :       if (aValues.Length() != 20) {
     439           0 :         return NS_ERROR_FAILURE;
     440             :       }
     441             : 
     442           0 :       PodCopy(aOutMatrix, aValues.Elements(), 20);
     443           0 :       break;
     444             :     }
     445             : 
     446             :     case SVG_FECOLORMATRIX_TYPE_SATURATE:
     447             :     {
     448           0 :       if (aValues.Length() != 1)
     449           0 :         return NS_ERROR_FAILURE;
     450             : 
     451           0 :       float s = aValues[0];
     452             : 
     453           0 :       if (s < 0)
     454           0 :         return NS_ERROR_FAILURE;
     455             : 
     456           0 :       InterpolateFromIdentityMatrix(saturateMatrix, 1 - s, aOutMatrix);
     457           0 :       break;
     458             :     }
     459             : 
     460             :     case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE:
     461             :     {
     462           0 :       if (aValues.Length() != 1)
     463           0 :         return NS_ERROR_FAILURE;
     464             : 
     465           0 :       PodCopy(aOutMatrix, identityMatrix, 20);
     466             : 
     467           0 :       float hueRotateValue = aValues[0];
     468             : 
     469           0 :       float c = static_cast<float>(cos(hueRotateValue * M_PI / 180));
     470           0 :       float s = static_cast<float>(sin(hueRotateValue * M_PI / 180));
     471             : 
     472           0 :       aOutMatrix[0] = lumR + oneMinusLumR * c - lumR * s;
     473           0 :       aOutMatrix[1] = lumG - lumG * c - lumG * s;
     474           0 :       aOutMatrix[2] = lumB - lumB * c + oneMinusLumB * s;
     475             : 
     476           0 :       aOutMatrix[5] = lumR - lumR * c + hueRotateR * s;
     477           0 :       aOutMatrix[6] = lumG + oneMinusLumG * c + hueRotateG * s;
     478           0 :       aOutMatrix[7] = lumB - lumB * c - hueRotateB * s;
     479             : 
     480           0 :       aOutMatrix[10] = lumR - lumR * c - oneMinusLumR * s;
     481           0 :       aOutMatrix[11] = lumG - lumG * c + lumG * s;
     482           0 :       aOutMatrix[12] = lumB + oneMinusLumB * c + lumB * s;
     483             : 
     484           0 :       break;
     485             :     }
     486             : 
     487             :     case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA:
     488             :     {
     489           0 :       PodCopy(aOutMatrix, luminanceToAlphaMatrix, 20);
     490           0 :       break;
     491             :     }
     492             : 
     493             :     case SVG_FECOLORMATRIX_TYPE_SEPIA:
     494             :     {
     495           0 :       if (aValues.Length() != 1)
     496           0 :         return NS_ERROR_FAILURE;
     497             : 
     498           0 :       float amount = aValues[0];
     499             : 
     500           0 :       if (amount < 0 || amount > 1)
     501           0 :         return NS_ERROR_FAILURE;
     502             : 
     503           0 :       InterpolateFromIdentityMatrix(sepiaMatrix, amount, aOutMatrix);
     504           0 :       break;
     505             :     }
     506             : 
     507             :     default:
     508           0 :       return NS_ERROR_FAILURE;
     509             : 
     510             :   }
     511             : 
     512           0 :   return NS_OK;
     513             : }
     514             : 
     515             : static void
     516           0 : DisableAllTransfers(FilterNode* aTransferFilterNode)
     517             : {
     518           0 :   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_R, true);
     519           0 :   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_G, true);
     520           0 :   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_B, true);
     521           0 :   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_A, true);
     522           0 : }
     523             : 
     524             : // Called for one channel at a time.
     525             : // This function creates the required FilterNodes on demand and tries to
     526             : // merge conversions of different channels into the same FilterNode if
     527             : // possible.
     528             : // There's a mismatch between the way SVG and the Moz2D API handle transfer
     529             : // functions: In SVG, it's possible to specify a different transfer function
     530             : // type for each color channel, but in Moz2D, a given transfer function type
     531             : // applies to all color channels.
     532             : //
     533             : //  @param aFunctionAttributes The attributes of the transfer function for this
     534             : //                             channel.
     535             : //  @param aChannel The color channel that this function applies to, where
     536             : //                  0 = red, 1 = green, 2 = blue, 3 = alpha
     537             : //  @param aDT The DrawTarget that the FilterNodes should be created for.
     538             : //  @param aTableTransfer Existing FilterNode holders (which may still be
     539             : //                        null) that the resulting FilterNodes from this
     540             : //                        function will be stored in.
     541             : //           
     542             : static void
     543           0 : ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes,
     544             :                                          int32_t aChannel,
     545             :                                          DrawTarget* aDT,
     546             :                                          RefPtr<FilterNode>& aTableTransfer,
     547             :                                          RefPtr<FilterNode>& aDiscreteTransfer,
     548             :                                          RefPtr<FilterNode>& aLinearTransfer,
     549             :                                          RefPtr<FilterNode>& aGammaTransfer)
     550             : {
     551             :   static const TransferAtts disableAtt[4] = {
     552             :     ATT_TRANSFER_DISABLE_R,
     553             :     ATT_TRANSFER_DISABLE_G,
     554             :     ATT_TRANSFER_DISABLE_B,
     555             :     ATT_TRANSFER_DISABLE_A
     556             :   };
     557             : 
     558           0 :   RefPtr<FilterNode> filter;
     559             : 
     560           0 :   uint32_t type = aFunctionAttributes.GetUint(eComponentTransferFunctionType);
     561             : 
     562           0 :   switch (type) {
     563             :   case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
     564             :   {
     565             :     const nsTArray<float>& tableValues =
     566           0 :       aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
     567           0 :     if (tableValues.Length() < 2)
     568           0 :       return;
     569             : 
     570           0 :     if (!aTableTransfer) {
     571           0 :       aTableTransfer = aDT->CreateFilter(FilterType::TABLE_TRANSFER);
     572           0 :       if (!aTableTransfer) {
     573           0 :         return;
     574             :       }
     575           0 :       DisableAllTransfers(aTableTransfer);
     576             :     }
     577           0 :     filter = aTableTransfer;
     578             :     static const TableTransferAtts tableAtt[4] = {
     579             :       ATT_TABLE_TRANSFER_TABLE_R,
     580             :       ATT_TABLE_TRANSFER_TABLE_G,
     581             :       ATT_TABLE_TRANSFER_TABLE_B,
     582             :       ATT_TABLE_TRANSFER_TABLE_A
     583             :     };
     584           0 :     filter->SetAttribute(disableAtt[aChannel], false);
     585           0 :     filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
     586           0 :     break;
     587             :   }
     588             : 
     589             :   case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
     590             :   {
     591             :     const nsTArray<float>& tableValues =
     592           0 :       aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
     593           0 :     if (tableValues.Length() < 1)
     594           0 :       return;
     595             : 
     596           0 :     if (!aDiscreteTransfer) {
     597           0 :       aDiscreteTransfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
     598           0 :       if (!aDiscreteTransfer) {
     599           0 :         return;
     600             :       }
     601           0 :       DisableAllTransfers(aDiscreteTransfer);
     602             :     }
     603           0 :     filter = aDiscreteTransfer;
     604             :     static const DiscreteTransferAtts tableAtt[4] = {
     605             :       ATT_DISCRETE_TRANSFER_TABLE_R,
     606             :       ATT_DISCRETE_TRANSFER_TABLE_G,
     607             :       ATT_DISCRETE_TRANSFER_TABLE_B,
     608             :       ATT_DISCRETE_TRANSFER_TABLE_A
     609             :     };
     610           0 :     filter->SetAttribute(disableAtt[aChannel], false);
     611           0 :     filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
     612             : 
     613           0 :     break;
     614             :   }
     615             : 
     616             :   case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
     617             :   {
     618             :     static const LinearTransferAtts slopeAtt[4] = {
     619             :       ATT_LINEAR_TRANSFER_SLOPE_R,
     620             :       ATT_LINEAR_TRANSFER_SLOPE_G,
     621             :       ATT_LINEAR_TRANSFER_SLOPE_B,
     622             :       ATT_LINEAR_TRANSFER_SLOPE_A
     623             :     };
     624             :     static const LinearTransferAtts interceptAtt[4] = {
     625             :       ATT_LINEAR_TRANSFER_INTERCEPT_R,
     626             :       ATT_LINEAR_TRANSFER_INTERCEPT_G,
     627             :       ATT_LINEAR_TRANSFER_INTERCEPT_B,
     628             :       ATT_LINEAR_TRANSFER_INTERCEPT_A
     629             :     };
     630           0 :     if (!aLinearTransfer) {
     631           0 :       aLinearTransfer = aDT->CreateFilter(FilterType::LINEAR_TRANSFER);
     632           0 :       if (!aLinearTransfer) {
     633           0 :         return;
     634             :       }
     635           0 :       DisableAllTransfers(aLinearTransfer);
     636             :     }
     637           0 :     filter = aLinearTransfer;
     638           0 :     filter->SetAttribute(disableAtt[aChannel], false);
     639           0 :     float slope = aFunctionAttributes.GetFloat(eComponentTransferFunctionSlope);
     640           0 :     float intercept = aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
     641           0 :     filter->SetAttribute(slopeAtt[aChannel], slope);
     642           0 :     filter->SetAttribute(interceptAtt[aChannel], intercept);
     643           0 :     break;
     644             :   }
     645             : 
     646             :   case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
     647             :   {
     648             :     static const GammaTransferAtts amplitudeAtt[4] = {
     649             :       ATT_GAMMA_TRANSFER_AMPLITUDE_R,
     650             :       ATT_GAMMA_TRANSFER_AMPLITUDE_G,
     651             :       ATT_GAMMA_TRANSFER_AMPLITUDE_B,
     652             :       ATT_GAMMA_TRANSFER_AMPLITUDE_A
     653             :     };
     654             :     static const GammaTransferAtts exponentAtt[4] = {
     655             :       ATT_GAMMA_TRANSFER_EXPONENT_R,
     656             :       ATT_GAMMA_TRANSFER_EXPONENT_G,
     657             :       ATT_GAMMA_TRANSFER_EXPONENT_B,
     658             :       ATT_GAMMA_TRANSFER_EXPONENT_A
     659             :     };
     660             :     static const GammaTransferAtts offsetAtt[4] = {
     661             :       ATT_GAMMA_TRANSFER_OFFSET_R,
     662             :       ATT_GAMMA_TRANSFER_OFFSET_G,
     663             :       ATT_GAMMA_TRANSFER_OFFSET_B,
     664             :       ATT_GAMMA_TRANSFER_OFFSET_A
     665             :     };
     666           0 :     if (!aGammaTransfer) {
     667           0 :       aGammaTransfer = aDT->CreateFilter(FilterType::GAMMA_TRANSFER);
     668           0 :       if (!aGammaTransfer) {
     669           0 :         return;
     670             :       }
     671           0 :       DisableAllTransfers(aGammaTransfer);
     672             :     }
     673           0 :     filter = aGammaTransfer;
     674           0 :     filter->SetAttribute(disableAtt[aChannel], false);
     675           0 :     float amplitude = aFunctionAttributes.GetFloat(eComponentTransferFunctionAmplitude);
     676           0 :     float exponent = aFunctionAttributes.GetFloat(eComponentTransferFunctionExponent);
     677           0 :     float offset = aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
     678           0 :     filter->SetAttribute(amplitudeAtt[aChannel], amplitude);
     679           0 :     filter->SetAttribute(exponentAtt[aChannel], exponent);
     680           0 :     filter->SetAttribute(offsetAtt[aChannel], offset);
     681           0 :     break;
     682             :   }
     683             : 
     684             :   case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
     685             :   default:
     686           0 :     break;
     687             :   }
     688             : }
     689             : 
     690             : const int32_t kMorphologyMaxRadius = 100000;
     691             : 
     692             : // Handle the different primitive description types and create the necessary
     693             : // FilterNode(s) for each.
     694             : // Returns nullptr for invalid filter primitives. This should be interpreted as
     695             : // transparent black by the caller.
     696             : // aSourceRegions contains the filter primitive subregions of the source
     697             : // primitives; only needed for eTile primitives.
     698             : // aInputImages carries additional surfaces that are used by eImage primitives.
     699             : static already_AddRefed<FilterNode>
     700           0 : FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescription,
     701             :                                    DrawTarget* aDT,
     702             :                                    nsTArray<RefPtr<FilterNode> >& aSources,
     703             :                                    nsTArray<IntRect>& aSourceRegions,
     704             :                                    nsTArray<RefPtr<SourceSurface>>& aInputImages)
     705             : {
     706           0 :   const AttributeMap& atts = aDescription.Attributes();
     707           0 :   switch (aDescription.Type()) {
     708             : 
     709             :     case PrimitiveType::Empty:
     710           0 :       return nullptr;
     711             : 
     712             :     case PrimitiveType::Blend:
     713             :     {
     714           0 :       uint32_t mode = atts.GetUint(eBlendBlendmode);
     715           0 :       RefPtr<FilterNode> filter;
     716           0 :       if (mode == SVG_FEBLEND_MODE_UNKNOWN) {
     717           0 :         return nullptr;
     718             :       }
     719           0 :       if (mode == SVG_FEBLEND_MODE_NORMAL) {
     720           0 :         filter = aDT->CreateFilter(FilterType::COMPOSITE);
     721           0 :         if (!filter) {
     722           0 :           return nullptr;
     723             :         }
     724           0 :         filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
     725           0 :         filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
     726             :       } else {
     727           0 :         filter = aDT->CreateFilter(FilterType::BLEND);
     728           0 :         if (!filter) {
     729           0 :           return nullptr;
     730             :         }
     731             :         static const uint8_t blendModes[SVG_FEBLEND_MODE_LUMINOSITY + 1] = {
     732             :           0,
     733             :           0,
     734             :           BLEND_MODE_MULTIPLY,
     735             :           BLEND_MODE_SCREEN,
     736             :           BLEND_MODE_DARKEN,
     737             :           BLEND_MODE_LIGHTEN,
     738             :           BLEND_MODE_OVERLAY,
     739             :           BLEND_MODE_COLOR_DODGE,
     740             :           BLEND_MODE_COLOR_BURN,
     741             :           BLEND_MODE_HARD_LIGHT,
     742             :           BLEND_MODE_SOFT_LIGHT,
     743             :           BLEND_MODE_DIFFERENCE,
     744             :           BLEND_MODE_EXCLUSION,
     745             :           BLEND_MODE_HUE,
     746             :           BLEND_MODE_SATURATION,
     747             :           BLEND_MODE_COLOR,
     748             :           BLEND_MODE_LUMINOSITY
     749             :         };
     750           0 :         filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)blendModes[mode]);
     751             :         // The correct input order for both software and D2D filters is flipped
     752             :         // from our source order, so flip here.
     753           0 :         filter->SetInput(IN_BLEND_IN, aSources[1]);
     754           0 :         filter->SetInput(IN_BLEND_IN2, aSources[0]);
     755             :       }
     756           0 :       return filter.forget();
     757             :     }
     758             : 
     759             :     case PrimitiveType::ColorMatrix:
     760             :     {
     761             :       float colorMatrix[20];
     762           0 :       uint32_t type = atts.GetUint(eColorMatrixType);
     763           0 :       const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
     764           0 :       if (NS_FAILED(ComputeColorMatrix(type, values, colorMatrix)) ||
     765           0 :           PodEqual(colorMatrix, identityMatrix)) {
     766           0 :         RefPtr<FilterNode> filter(aSources[0]);
     767           0 :         return filter.forget();
     768             :       }
     769             :       Matrix5x4 matrix(colorMatrix[0], colorMatrix[5], colorMatrix[10],  colorMatrix[15],
     770             :                        colorMatrix[1], colorMatrix[6], colorMatrix[11],  colorMatrix[16],
     771             :                        colorMatrix[2], colorMatrix[7], colorMatrix[12],  colorMatrix[17],
     772             :                        colorMatrix[3], colorMatrix[8], colorMatrix[13],  colorMatrix[18],
     773           0 :                        colorMatrix[4], colorMatrix[9], colorMatrix[14],  colorMatrix[19]);
     774           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COLOR_MATRIX);
     775           0 :       if (!filter) {
     776           0 :         return nullptr;
     777             :       }
     778           0 :       filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
     779           0 :       filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
     780           0 :       filter->SetInput(IN_COLOR_MATRIX_IN, aSources[0]);
     781           0 :       return filter.forget();
     782             :     }
     783             : 
     784             :     case PrimitiveType::Morphology:
     785             :     {
     786           0 :       Size radii = atts.GetSize(eMorphologyRadii);
     787           0 :       int32_t rx = radii.width;
     788           0 :       int32_t ry = radii.height;
     789           0 :       if (rx < 0 || ry < 0) {
     790             :         // XXX SVGContentUtils::ReportToConsole()
     791           0 :         return nullptr;
     792             :       }
     793           0 :       if (rx == 0 && ry == 0) {
     794           0 :         return nullptr;
     795             :       }
     796             : 
     797             :       // Clamp radii to prevent completely insane values:
     798           0 :       rx = std::min(rx, kMorphologyMaxRadius);
     799           0 :       ry = std::min(ry, kMorphologyMaxRadius);
     800             : 
     801           0 :       MorphologyOperator op = atts.GetUint(eMorphologyOperator) == SVG_OPERATOR_ERODE ?
     802           0 :         MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE;
     803             : 
     804           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::MORPHOLOGY);
     805           0 :       if (!filter) {
     806           0 :         return nullptr;
     807             :       }
     808           0 :       filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
     809           0 :       filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
     810           0 :       filter->SetInput(IN_MORPHOLOGY_IN, aSources[0]);
     811           0 :       return filter.forget();
     812             :     }
     813             : 
     814             :     case PrimitiveType::Flood:
     815             :     {
     816           0 :       Color color = atts.GetColor(eFloodColor);
     817           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
     818           0 :       if (!filter) {
     819           0 :         return nullptr;
     820             :       }
     821           0 :       filter->SetAttribute(ATT_FLOOD_COLOR, color);
     822           0 :       return filter.forget();
     823             :     }
     824             : 
     825             :     case PrimitiveType::Tile:
     826             :     {
     827           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TILE);
     828           0 :       if (!filter) {
     829           0 :         return nullptr;
     830             :       }
     831           0 :       filter->SetAttribute(ATT_TILE_SOURCE_RECT, aSourceRegions[0]);
     832           0 :       filter->SetInput(IN_TILE_IN, aSources[0]);
     833           0 :       return filter.forget();
     834             :     }
     835             : 
     836             :     case PrimitiveType::ComponentTransfer:
     837             :     {
     838           0 :       RefPtr<FilterNode> filters[4]; // one for each FILTER_*_TRANSFER type
     839             :       static const AttributeName componentFunctionNames[4] = {
     840             :         eComponentTransferFunctionR,
     841             :         eComponentTransferFunctionG,
     842             :         eComponentTransferFunctionB,
     843             :         eComponentTransferFunctionA
     844             :       };
     845           0 :       for (int32_t i = 0; i < 4; i++) {
     846             :         AttributeMap functionAttributes =
     847           0 :           atts.GetAttributeMap(componentFunctionNames[i]);
     848             :         ConvertComponentTransferFunctionToFilter(functionAttributes, i, aDT,
     849           0 :           filters[0], filters[1], filters[2], filters[3]);
     850             :       }
     851             : 
     852             :       // Connect all used filters nodes.
     853           0 :       RefPtr<FilterNode> lastFilter = aSources[0];
     854           0 :       for (int32_t i = 0; i < 4; i++) {
     855           0 :         if (filters[i]) {
     856           0 :           filters[i]->SetInput(0, lastFilter);
     857           0 :           lastFilter = filters[i];
     858             :         }
     859             :       }
     860             : 
     861           0 :       return lastFilter.forget();
     862             :     }
     863             : 
     864             :     case PrimitiveType::ConvolveMatrix:
     865             :     {
     866           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
     867           0 :       if (!filter) {
     868           0 :         return nullptr;
     869             :       }
     870           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, atts.GetIntSize(eConvolveMatrixKernelSize));
     871           0 :       const nsTArray<float>& matrix = atts.GetFloats(eConvolveMatrixKernelMatrix);
     872           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,
     873           0 :                            matrix.Elements(), matrix.Length());
     874           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR,
     875           0 :                            atts.GetFloat(eConvolveMatrixDivisor));
     876           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS,
     877           0 :                            atts.GetFloat(eConvolveMatrixBias));
     878           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET,
     879           0 :                            atts.GetIntPoint(eConvolveMatrixTarget));
     880           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT,
     881           0 :                            aSourceRegions[0]);
     882           0 :       uint32_t edgeMode = atts.GetUint(eConvolveMatrixEdgeMode);
     883             :       static const uint8_t edgeModes[SVG_EDGEMODE_NONE+1] = {
     884             :         EDGE_MODE_NONE,      // SVG_EDGEMODE_UNKNOWN
     885             :         EDGE_MODE_DUPLICATE, // SVG_EDGEMODE_DUPLICATE
     886             :         EDGE_MODE_WRAP,      // SVG_EDGEMODE_WRAP
     887             :         EDGE_MODE_NONE       // SVG_EDGEMODE_NONE
     888             :       };
     889           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)edgeModes[edgeMode]);
     890           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH,
     891           0 :                            atts.GetSize(eConvolveMatrixKernelUnitLength));
     892           0 :       filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA,
     893           0 :                            atts.GetBool(eConvolveMatrixPreserveAlpha));
     894           0 :       filter->SetInput(IN_CONVOLVE_MATRIX_IN, aSources[0]);
     895           0 :       return filter.forget();
     896             :     }
     897             : 
     898             :     case PrimitiveType::Offset:
     899             :     {
     900           0 :       return FilterWrappers::Offset(aDT, aSources[0],
     901           0 :                                     atts.GetIntPoint(eOffsetOffset));
     902             :     }
     903             : 
     904             :     case PrimitiveType::DisplacementMap:
     905             :     {
     906           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
     907           0 :       if (!filter) {
     908           0 :         return nullptr;
     909             :       }
     910           0 :       filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE,
     911           0 :                            atts.GetFloat(eDisplacementMapScale));
     912             :       static const uint8_t channel[SVG_CHANNEL_A+1] = {
     913             :         COLOR_CHANNEL_R, // SVG_CHANNEL_UNKNOWN
     914             :         COLOR_CHANNEL_R, // SVG_CHANNEL_R
     915             :         COLOR_CHANNEL_G, // SVG_CHANNEL_G
     916             :         COLOR_CHANNEL_B, // SVG_CHANNEL_B
     917             :         COLOR_CHANNEL_A  // SVG_CHANNEL_A
     918             :       };
     919           0 :       filter->SetAttribute(ATT_DISPLACEMENT_MAP_X_CHANNEL,
     920           0 :                            (uint32_t)channel[atts.GetUint(eDisplacementMapXChannel)]);
     921           0 :       filter->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL,
     922           0 :                            (uint32_t)channel[atts.GetUint(eDisplacementMapYChannel)]);
     923           0 :       filter->SetInput(IN_DISPLACEMENT_MAP_IN, aSources[0]);
     924           0 :       filter->SetInput(IN_DISPLACEMENT_MAP_IN2, aSources[1]);
     925           0 :       return filter.forget();
     926             :     }
     927             : 
     928             :     case PrimitiveType::Turbulence:
     929             :     {
     930           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TURBULENCE);
     931           0 :       if (!filter) {
     932           0 :         return nullptr;
     933             :       }
     934           0 :       filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
     935           0 :                            atts.GetSize(eTurbulenceBaseFrequency));
     936           0 :       filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES,
     937           0 :                            atts.GetUint(eTurbulenceNumOctaves));
     938           0 :       filter->SetAttribute(ATT_TURBULENCE_STITCHABLE,
     939           0 :                            atts.GetBool(eTurbulenceStitchable));
     940           0 :       filter->SetAttribute(ATT_TURBULENCE_SEED,
     941           0 :                            (uint32_t)atts.GetFloat(eTurbulenceSeed));
     942             :       static const uint8_t type[SVG_TURBULENCE_TYPE_TURBULENCE+1] = {
     943             :         TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_UNKNOWN
     944             :         TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_FRACTALNOISE
     945             :         TURBULENCE_TYPE_TURBULENCE     // SVG_TURBULENCE_TYPE_TURBULENCE
     946             :       };
     947           0 :       filter->SetAttribute(ATT_TURBULENCE_TYPE,
     948           0 :                            (uint32_t)type[atts.GetUint(eTurbulenceType)]);
     949           0 :       filter->SetAttribute(ATT_TURBULENCE_RECT,
     950           0 :                            aDescription.PrimitiveSubregion() - atts.GetIntPoint(eTurbulenceOffset));
     951           0 :       return FilterWrappers::Offset(aDT, filter, atts.GetIntPoint(eTurbulenceOffset));
     952             :     }
     953             : 
     954             :     case PrimitiveType::Composite:
     955             :     {
     956           0 :       RefPtr<FilterNode> filter;
     957           0 :       uint32_t op = atts.GetUint(eCompositeOperator);
     958           0 :       if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
     959           0 :         const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
     960             :         static const float allZero[4] = { 0, 0, 0, 0 };
     961           0 :         filter = aDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
     962             :         // All-zero coefficients sometimes occur in junk filters.
     963           0 :         if (!filter ||
     964           0 :             (coefficients.Length() == ArrayLength(allZero) &&
     965           0 :              PodEqual(coefficients.Elements(), allZero, ArrayLength(allZero)))) {
     966           0 :           return nullptr;
     967             :         }
     968           0 :         filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS,
     969           0 :                              coefficients.Elements(), coefficients.Length());
     970           0 :         filter->SetInput(IN_ARITHMETIC_COMBINE_IN, aSources[0]);
     971           0 :         filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, aSources[1]);
     972             :       } else {
     973           0 :         filter = aDT->CreateFilter(FilterType::COMPOSITE);
     974           0 :         if (!filter) {
     975           0 :           return nullptr;
     976             :         }
     977             :         static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
     978             :           COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
     979             :           COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
     980             :           COMPOSITE_OPERATOR_IN,   // SVG_FECOMPOSITE_OPERATOR_IN
     981             :           COMPOSITE_OPERATOR_OUT,  // SVG_FECOMPOSITE_OPERATOR_OUT
     982             :           COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
     983             :           COMPOSITE_OPERATOR_XOR   // SVG_FECOMPOSITE_OPERATOR_XOR
     984             :         };
     985           0 :         filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)operators[op]);
     986           0 :         filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
     987           0 :         filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
     988             :       }
     989           0 :       return filter.forget();
     990             :     }
     991             : 
     992             :     case PrimitiveType::Merge:
     993             :     {
     994           0 :       if (aSources.Length() == 0) {
     995           0 :         return nullptr;
     996             :       }
     997           0 :       if (aSources.Length() == 1) {
     998           0 :         RefPtr<FilterNode> filter(aSources[0]);
     999           0 :         return filter.forget();
    1000             :       }
    1001           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
    1002           0 :       if (!filter) {
    1003           0 :         return nullptr;
    1004             :       }
    1005           0 :       filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
    1006           0 :       for (size_t i = 0; i < aSources.Length(); i++) {
    1007           0 :         filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
    1008             :       }
    1009           0 :       return filter.forget();
    1010             :     }
    1011             : 
    1012             :     case PrimitiveType::GaussianBlur:
    1013             :     {
    1014           0 :       return FilterWrappers::GaussianBlur(aDT, aSources[0],
    1015           0 :                                           atts.GetSize(eGaussianBlurStdDeviation));
    1016             :     }
    1017             : 
    1018             :     case PrimitiveType::DropShadow:
    1019             :     {
    1020           0 :       RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(aDT, aSources[0]);
    1021           0 :       RefPtr<FilterNode> blur = FilterWrappers::GaussianBlur(aDT, alpha,
    1022           0 :                                   atts.GetSize(eDropShadowStdDeviation));
    1023           0 :       RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
    1024           0 :                                         atts.GetIntPoint(eDropShadowOffset));
    1025           0 :       RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
    1026           0 :       if (!flood) {
    1027           0 :         return nullptr;
    1028             :       }
    1029           0 :       Color color = atts.GetColor(eDropShadowColor);
    1030           0 :       if (aDescription.InputColorSpace(0) == ColorSpace::LinearRGB) {
    1031           0 :         color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
    1032           0 :                       gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
    1033           0 :                       gsRGBToLinearRGBMap[uint8_t(color.b * 255)],
    1034             :                       color.a);
    1035             :       }
    1036           0 :       flood->SetAttribute(ATT_FLOOD_COLOR, color);
    1037             : 
    1038           0 :       RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
    1039           0 :       if (!composite) {
    1040           0 :         return nullptr;
    1041             :       }
    1042           0 :       composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
    1043           0 :       composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
    1044           0 :       composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
    1045             : 
    1046           0 :       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
    1047           0 :       if (!filter) {
    1048           0 :         return nullptr;
    1049             :       }
    1050           0 :       filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
    1051           0 :       filter->SetInput(IN_COMPOSITE_IN_START, composite);
    1052           0 :       filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
    1053           0 :       return filter.forget();
    1054             :     }
    1055             : 
    1056             :     case PrimitiveType::DiffuseLighting:
    1057             :     case PrimitiveType::SpecularLighting:
    1058             :     {
    1059             :       bool isSpecular =
    1060           0 :         aDescription.Type() == PrimitiveType::SpecularLighting;
    1061             : 
    1062           0 :       AttributeMap lightAttributes = atts.GetAttributeMap(eLightingLight);
    1063             : 
    1064           0 :       if (lightAttributes.GetUint(eLightType) == eLightTypeNone) {
    1065           0 :         return nullptr;
    1066             :       }
    1067             : 
    1068           0 :       enum { POINT = 0, SPOT, DISTANT } lightType = POINT;
    1069             : 
    1070           0 :       switch (lightAttributes.GetUint(eLightType)) {
    1071           0 :         case eLightTypePoint:   lightType = POINT;   break;
    1072           0 :         case eLightTypeSpot:    lightType = SPOT;    break;
    1073           0 :         case eLightTypeDistant: lightType = DISTANT; break;
    1074             :       }
    1075             : 
    1076             :       static const FilterType filterType[2][DISTANT+1] = {
    1077             :         { FilterType::POINT_DIFFUSE, FilterType::SPOT_DIFFUSE, FilterType::DISTANT_DIFFUSE },
    1078             :         { FilterType::POINT_SPECULAR, FilterType::SPOT_SPECULAR, FilterType::DISTANT_SPECULAR }
    1079             :       };
    1080             :       RefPtr<FilterNode> filter =
    1081           0 :         aDT->CreateFilter(filterType[isSpecular][lightType]);
    1082           0 :       if (!filter) {
    1083           0 :         return nullptr;
    1084             :       }
    1085             : 
    1086           0 :       filter->SetAttribute(ATT_LIGHTING_COLOR,
    1087           0 :                            atts.GetColor(eLightingColor));
    1088           0 :       filter->SetAttribute(ATT_LIGHTING_SURFACE_SCALE,
    1089           0 :                            atts.GetFloat(eLightingSurfaceScale));
    1090           0 :       filter->SetAttribute(ATT_LIGHTING_KERNEL_UNIT_LENGTH,
    1091           0 :                            atts.GetSize(eLightingKernelUnitLength));
    1092             : 
    1093           0 :       if (isSpecular) {
    1094           0 :         filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
    1095           0 :                              atts.GetFloat(eSpecularLightingSpecularConstant));
    1096           0 :         filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT,
    1097           0 :                              atts.GetFloat(eSpecularLightingSpecularExponent));
    1098             :       } else {
    1099           0 :         filter->SetAttribute(ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT,
    1100           0 :                              atts.GetFloat(eDiffuseLightingDiffuseConstant));
    1101             :       }
    1102             : 
    1103           0 :       switch (lightType) {
    1104             :         case POINT:
    1105           0 :           filter->SetAttribute(ATT_POINT_LIGHT_POSITION,
    1106           0 :                                lightAttributes.GetPoint3D(ePointLightPosition));
    1107           0 :           break;
    1108             :         case SPOT:
    1109           0 :           filter->SetAttribute(ATT_SPOT_LIGHT_POSITION,
    1110           0 :                                lightAttributes.GetPoint3D(eSpotLightPosition));
    1111           0 :           filter->SetAttribute(ATT_SPOT_LIGHT_POINTS_AT,
    1112           0 :                                lightAttributes.GetPoint3D(eSpotLightPointsAt));
    1113           0 :           filter->SetAttribute(ATT_SPOT_LIGHT_FOCUS,
    1114           0 :                                lightAttributes.GetFloat(eSpotLightFocus));
    1115           0 :           filter->SetAttribute(ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,
    1116           0 :                                lightAttributes.GetFloat(eSpotLightLimitingConeAngle));
    1117           0 :           break;
    1118             :         case DISTANT:
    1119           0 :           filter->SetAttribute(ATT_DISTANT_LIGHT_AZIMUTH,
    1120           0 :                                lightAttributes.GetFloat(eDistantLightAzimuth));
    1121           0 :           filter->SetAttribute(ATT_DISTANT_LIGHT_ELEVATION,
    1122           0 :                                lightAttributes.GetFloat(eDistantLightElevation));
    1123           0 :           break;
    1124             :       }
    1125             : 
    1126           0 :       filter->SetInput(IN_LIGHTING_IN, aSources[0]);
    1127             : 
    1128           0 :       return filter.forget();
    1129             :     }
    1130             : 
    1131             :     case PrimitiveType::Image:
    1132             :     {
    1133           0 :       Matrix TM = atts.GetMatrix(eImageTransform);
    1134           0 :       if (!TM.Determinant()) {
    1135           0 :         return nullptr;
    1136             :       }
    1137             : 
    1138             :       // Pull the image from the additional image list using the index that's
    1139             :       // stored in the primitive description.
    1140             :       RefPtr<SourceSurface> inputImage =
    1141           0 :         aInputImages[atts.GetUint(eImageInputIndex)];
    1142             : 
    1143           0 :       RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
    1144           0 :       if (!transform) {
    1145           0 :         return nullptr;
    1146             :       }
    1147           0 :       transform->SetInput(IN_TRANSFORM_IN, inputImage);
    1148           0 :       transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
    1149           0 :       transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
    1150           0 :       return transform.forget();
    1151             :     }
    1152             : 
    1153             :     case PrimitiveType::ToAlpha:
    1154             :     {
    1155           0 :       return FilterWrappers::ToAlpha(aDT, aSources[0]);
    1156             :     }
    1157             : 
    1158             :     default:
    1159           0 :       return nullptr;
    1160             :   }
    1161             : }
    1162             : 
    1163             : template<typename T>
    1164             : static const T&
    1165           0 : ElementForIndex(int32_t aIndex,
    1166             :                 const nsTArray<T>& aPrimitiveElements,
    1167             :                 const T& aSourceGraphicElement,
    1168             :                 const T& aFillPaintElement,
    1169             :                 const T& aStrokePaintElement)
    1170             : {
    1171           0 :   switch (aIndex) {
    1172             :     case FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic:
    1173             :     case FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha:
    1174           0 :       return aSourceGraphicElement;
    1175             :     case FilterPrimitiveDescription::kPrimitiveIndexFillPaint:
    1176           0 :       return aFillPaintElement;
    1177             :     case FilterPrimitiveDescription::kPrimitiveIndexStrokePaint:
    1178           0 :       return aStrokePaintElement;
    1179             :     default:
    1180           0 :       MOZ_ASSERT(aIndex >= 0, "bad index");
    1181           0 :       return aPrimitiveElements[aIndex];
    1182             :   }
    1183             : }
    1184             : 
    1185             : static AlphaModel
    1186           0 : InputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
    1187             :                             int32_t aInputIndex,
    1188             :                             AlphaModel aOriginalAlphaModel)
    1189             : {
    1190           0 :   switch (aDescr.Type()) {
    1191             :     case PrimitiveType::Tile:
    1192             :     case PrimitiveType::Offset:
    1193             :     case PrimitiveType::ToAlpha:
    1194           0 :       return aOriginalAlphaModel;
    1195             : 
    1196             :     case PrimitiveType::ColorMatrix:
    1197             :     case PrimitiveType::ComponentTransfer:
    1198           0 :       return AlphaModel::Unpremultiplied;
    1199             : 
    1200             :     case PrimitiveType::DisplacementMap:
    1201           0 :       return aInputIndex == 0 ?
    1202           0 :         AlphaModel::Premultiplied : AlphaModel::Unpremultiplied;
    1203             : 
    1204             :     case PrimitiveType::ConvolveMatrix:
    1205           0 :       return aDescr.Attributes().GetBool(eConvolveMatrixPreserveAlpha) ?
    1206           0 :         AlphaModel::Unpremultiplied : AlphaModel::Premultiplied;
    1207             : 
    1208             :     default:
    1209           0 :       return AlphaModel::Premultiplied;
    1210             :   }
    1211             : }
    1212             : 
    1213             : static AlphaModel
    1214           0 : OutputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
    1215             :                              const nsTArray<AlphaModel>& aInputAlphaModels)
    1216             : {
    1217           0 :   if (aInputAlphaModels.Length()) {
    1218             :     // For filters with inputs, the output is premultiplied if and only if the
    1219             :     // first input is premultiplied.
    1220           0 :     return InputAlphaModelForPrimitive(aDescr, 0, aInputAlphaModels[0]);
    1221             :   }
    1222             : 
    1223             :   // All filters without inputs produce premultiplied alpha.
    1224           0 :   return AlphaModel::Premultiplied;
    1225             : }
    1226             : 
    1227             : // Returns the output FilterNode, in premultiplied sRGB space.
    1228             : static already_AddRefed<FilterNode>
    1229           0 : FilterNodeGraphFromDescription(DrawTarget* aDT,
    1230             :                                const FilterDescription& aFilter,
    1231             :                                const Rect& aResultNeededRect,
    1232             :                                SourceSurface* aSourceGraphic,
    1233             :                                const IntRect& aSourceGraphicRect,
    1234             :                                SourceSurface* aFillPaint,
    1235             :                                const IntRect& aFillPaintRect,
    1236             :                                SourceSurface* aStrokePaint,
    1237             :                                const IntRect& aStrokePaintRect,
    1238             :                                nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
    1239             : {
    1240           0 :   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
    1241           0 :   MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
    1242             : 
    1243           0 :   RefPtr<FilterCachedColorModels> sourceFilters[4];
    1244           0 :   nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters;
    1245             : 
    1246           0 :   for (size_t i = 0; i < primitives.Length(); ++i) {
    1247           0 :     const FilterPrimitiveDescription& descr = primitives[i];
    1248             : 
    1249           0 :     nsTArray<RefPtr<FilterNode> > inputFilterNodes;
    1250           0 :     nsTArray<IntRect> inputSourceRects;
    1251           0 :     nsTArray<AlphaModel> inputAlphaModels;
    1252             : 
    1253           0 :     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
    1254             : 
    1255           0 :       int32_t inputIndex = descr.InputPrimitiveIndex(j);
    1256           0 :       if (inputIndex < 0) {
    1257           0 :         inputSourceRects.AppendElement(descr.FilterSpaceBounds());
    1258             :       } else {
    1259           0 :         inputSourceRects.AppendElement(primitives[inputIndex].PrimitiveSubregion());
    1260             :       }
    1261             : 
    1262           0 :       RefPtr<FilterCachedColorModels> inputFilter;
    1263           0 :       if (inputIndex >= 0) {
    1264           0 :         MOZ_ASSERT(inputIndex < (int64_t)primitiveFilters.Length(), "out-of-bounds input index!");
    1265           0 :         inputFilter = primitiveFilters[inputIndex];
    1266           0 :         MOZ_ASSERT(inputFilter, "Referred to input filter that comes after the current one?");
    1267             :       } else {
    1268           0 :         int32_t sourceIndex = -inputIndex - 1;
    1269           0 :         MOZ_ASSERT(sourceIndex >= 0, "invalid source index");
    1270           0 :         MOZ_ASSERT(sourceIndex < 4, "invalid source index");
    1271           0 :         inputFilter = sourceFilters[sourceIndex];
    1272           0 :         if (!inputFilter) {
    1273           0 :           RefPtr<FilterNode> sourceFilterNode;
    1274             : 
    1275           0 :           nsTArray<SourceSurface*> primitiveSurfaces;
    1276           0 :           nsTArray<IntRect> primitiveSurfaceRects;
    1277             :           RefPtr<SourceSurface> surf =
    1278             :             ElementForIndex(inputIndex, primitiveSurfaces,
    1279           0 :                             aSourceGraphic, aFillPaint, aStrokePaint);
    1280             :           IntRect surfaceRect =
    1281             :             ElementForIndex(inputIndex, primitiveSurfaceRects,
    1282           0 :                             aSourceGraphicRect, aFillPaintRect, aStrokePaintRect);
    1283           0 :           if (surf) {
    1284           0 :             IntPoint offset = surfaceRect.TopLeft();
    1285           0 :             sourceFilterNode = FilterWrappers::ForSurface(aDT, surf, offset);
    1286             : 
    1287             :             // Clip the original SourceGraphic to the first filter region if the
    1288             :             // surface isn't already sized appropriately.
    1289           0 :             if ((inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic ||
    1290           0 :                  inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) &&
    1291           0 :                 !descr.FilterSpaceBounds().Contains(aSourceGraphicRect)) {
    1292             :               sourceFilterNode =
    1293           0 :                 FilterWrappers::Crop(aDT, sourceFilterNode, descr.FilterSpaceBounds());
    1294             :             }
    1295             : 
    1296           0 :             if (inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) {
    1297           0 :               sourceFilterNode = FilterWrappers::ToAlpha(aDT, sourceFilterNode);
    1298             :             }
    1299             :           }
    1300             : 
    1301             :           inputFilter = new FilterCachedColorModels(aDT, sourceFilterNode,
    1302           0 :                                                     ColorModel::PremulSRGB());
    1303           0 :           sourceFilters[sourceIndex] = inputFilter;
    1304             :         }
    1305             :       }
    1306           0 :       MOZ_ASSERT(inputFilter);
    1307             : 
    1308             :       AlphaModel inputAlphaModel =
    1309           0 :         InputAlphaModelForPrimitive(descr, j, inputFilter->OriginalAlphaModel());
    1310           0 :       inputAlphaModels.AppendElement(inputAlphaModel);
    1311           0 :       ColorModel inputColorModel(descr.InputColorSpace(j), inputAlphaModel);
    1312           0 :       inputFilterNodes.AppendElement(inputFilter->ForColorModel(inputColorModel));
    1313             :     }
    1314             : 
    1315             :     RefPtr<FilterNode> primitiveFilterNode =
    1316           0 :       FilterNodeFromPrimitiveDescription(descr, aDT, inputFilterNodes,
    1317           0 :                                          inputSourceRects, aAdditionalImages);
    1318             : 
    1319           0 :     if (primitiveFilterNode) {
    1320             :       primitiveFilterNode =
    1321           0 :         FilterWrappers::Crop(aDT, primitiveFilterNode, descr.PrimitiveSubregion());
    1322             :     }
    1323             : 
    1324             :     ColorModel outputColorModel(descr.OutputColorSpace(),
    1325           0 :       OutputAlphaModelForPrimitive(descr, inputAlphaModels));
    1326             :     RefPtr<FilterCachedColorModels> primitiveFilter =
    1327           0 :       new FilterCachedColorModels(aDT, primitiveFilterNode, outputColorModel);
    1328             : 
    1329           0 :     primitiveFilters.AppendElement(primitiveFilter);
    1330             :   }
    1331             : 
    1332           0 :   MOZ_RELEASE_ASSERT(!primitiveFilters.IsEmpty());
    1333           0 :   return primitiveFilters.LastElement()->ForColorModel(ColorModel::PremulSRGB());
    1334             : }
    1335             : 
    1336             : // FilterSupport
    1337             : 
    1338             : void
    1339           0 : FilterSupport::RenderFilterDescription(DrawTarget* aDT,
    1340             :                                        const FilterDescription& aFilter,
    1341             :                                        const Rect& aRenderRect,
    1342             :                                        SourceSurface* aSourceGraphic,
    1343             :                                        const IntRect& aSourceGraphicRect,
    1344             :                                        SourceSurface* aFillPaint,
    1345             :                                        const IntRect& aFillPaintRect,
    1346             :                                        SourceSurface* aStrokePaint,
    1347             :                                        const IntRect& aStrokePaintRect,
    1348             :                                        nsTArray<RefPtr<SourceSurface>>& aAdditionalImages,
    1349             :                                        const Point& aDestPoint,
    1350             :                                        const DrawOptions& aOptions)
    1351             : {
    1352             :   RefPtr<FilterNode> resultFilter =
    1353           0 :     FilterNodeGraphFromDescription(aDT, aFilter, aRenderRect,
    1354             :                                    aSourceGraphic, aSourceGraphicRect, aFillPaint, aFillPaintRect,
    1355           0 :                                    aStrokePaint, aStrokePaintRect, aAdditionalImages);
    1356           0 :   if (!resultFilter) {
    1357           0 :     gfxWarning() << "Filter is NULL.";
    1358           0 :     return;
    1359             :   }
    1360           0 :   aDT->DrawFilter(resultFilter, aRenderRect, aDestPoint, aOptions);
    1361             : }
    1362             : 
    1363             : static nsIntRegion
    1364           0 : UnionOfRegions(const nsTArray<nsIntRegion>& aRegions)
    1365             : {
    1366           0 :   nsIntRegion result;
    1367           0 :   for (size_t i = 0; i < aRegions.Length(); i++) {
    1368           0 :     result.Or(result, aRegions[i]);
    1369             :   }
    1370           0 :   return result;
    1371             : }
    1372             : 
    1373             : static int32_t
    1374           0 : InflateSizeForBlurStdDev(float aStdDev)
    1375             : {
    1376           0 :   double size = std::min(aStdDev, kMaxStdDeviation) * (3 * sqrt(2 * M_PI) / 4) * 1.5;
    1377           0 :   return uint32_t(floor(size + 0.5));
    1378             : }
    1379             : 
    1380             : static nsIntRegion
    1381           0 : ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
    1382             :                                const nsTArray<nsIntRegion>& aInputChangeRegions)
    1383             : {
    1384           0 :   const AttributeMap& atts = aDescription.Attributes();
    1385           0 :   switch (aDescription.Type()) {
    1386             : 
    1387             :     case PrimitiveType::Empty:
    1388             :     case PrimitiveType::Flood:
    1389             :     case PrimitiveType::Turbulence:
    1390             :     case PrimitiveType::Image:
    1391           0 :       return nsIntRegion();
    1392             : 
    1393             :     case PrimitiveType::Blend:
    1394             :     case PrimitiveType::Composite:
    1395             :     case PrimitiveType::Merge:
    1396           0 :       return UnionOfRegions(aInputChangeRegions);
    1397             : 
    1398             :     case PrimitiveType::ColorMatrix:
    1399             :     case PrimitiveType::ComponentTransfer:
    1400             :     case PrimitiveType::ToAlpha:
    1401           0 :       return aInputChangeRegions[0];
    1402             : 
    1403             :     case PrimitiveType::Morphology:
    1404             :     {
    1405           0 :       Size radii = atts.GetSize(eMorphologyRadii);
    1406           0 :       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
    1407           0 :       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
    1408           0 :       return aInputChangeRegions[0].Inflated(nsIntMargin(ry, rx, ry, rx));
    1409             :     }
    1410             : 
    1411             :     case PrimitiveType::Tile:
    1412           0 :       return aDescription.PrimitiveSubregion();
    1413             : 
    1414             :     case PrimitiveType::ConvolveMatrix:
    1415             :     {
    1416           0 :       if (atts.GetUint(eConvolveMatrixEdgeMode) != EDGE_MODE_NONE) {
    1417           0 :         return aDescription.PrimitiveSubregion();
    1418             :       }
    1419           0 :       Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
    1420           0 :       IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
    1421           0 :       IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
    1422           0 :       nsIntMargin m(ceil(kernelUnitLength.width * (target.x)),
    1423           0 :                     ceil(kernelUnitLength.height * (target.y)),
    1424           0 :                     ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
    1425           0 :                     ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)));
    1426           0 :       return aInputChangeRegions[0].Inflated(m);
    1427             :     }
    1428             : 
    1429             :     case PrimitiveType::Offset:
    1430             :     {
    1431           0 :       IntPoint offset = atts.GetIntPoint(eOffsetOffset);
    1432           0 :       return aInputChangeRegions[0].MovedBy(offset.x, offset.y);
    1433             :     }
    1434             : 
    1435             :     case PrimitiveType::DisplacementMap:
    1436             :     {
    1437           0 :       int32_t scale = ceil(std::abs(atts.GetFloat(eDisplacementMapScale)));
    1438           0 :       return aInputChangeRegions[0].Inflated(nsIntMargin(scale, scale, scale, scale));
    1439             :     }
    1440             : 
    1441             :     case PrimitiveType::GaussianBlur:
    1442             :     {
    1443           0 :       Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
    1444           0 :       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
    1445           0 :       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
    1446           0 :       return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
    1447             :     }
    1448             : 
    1449             :     case PrimitiveType::DropShadow:
    1450             :     {
    1451           0 :       IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
    1452           0 :       nsIntRegion offsetRegion = aInputChangeRegions[0].MovedBy(offset.x, offset.y);
    1453           0 :       Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
    1454           0 :       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
    1455           0 :       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
    1456           0 :       nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
    1457           0 :       blurRegion.Or(blurRegion, aInputChangeRegions[0]);
    1458           0 :       return blurRegion;
    1459             :     }
    1460             : 
    1461             :     case PrimitiveType::DiffuseLighting:
    1462             :     case PrimitiveType::SpecularLighting:
    1463             :     {
    1464           0 :       Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
    1465           0 :       int32_t dx = ceil(kernelUnitLength.width);
    1466           0 :       int32_t dy = ceil(kernelUnitLength.height);
    1467           0 :       return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
    1468             :     }
    1469             : 
    1470             :     default:
    1471           0 :       return nsIntRegion();
    1472             :   }
    1473             : }
    1474             : 
    1475             : /* static */ nsIntRegion
    1476           0 : FilterSupport::ComputeResultChangeRegion(const FilterDescription& aFilter,
    1477             :                                          const nsIntRegion& aSourceGraphicChange,
    1478             :                                          const nsIntRegion& aFillPaintChange,
    1479             :                                          const nsIntRegion& aStrokePaintChange)
    1480             : {
    1481           0 :   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
    1482           0 :   MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
    1483             : 
    1484           0 :   nsTArray<nsIntRegion> resultChangeRegions;
    1485             : 
    1486           0 :   for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
    1487           0 :     const FilterPrimitiveDescription& descr = primitives[i];
    1488             : 
    1489           0 :     nsTArray<nsIntRegion> inputChangeRegions;
    1490           0 :     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
    1491           0 :       int32_t inputIndex = descr.InputPrimitiveIndex(j);
    1492           0 :       MOZ_ASSERT(inputIndex < i, "bad input index");
    1493             :       nsIntRegion inputChangeRegion =
    1494             :         ElementForIndex(inputIndex, resultChangeRegions,
    1495             :                         aSourceGraphicChange, aFillPaintChange,
    1496           0 :                         aStrokePaintChange);
    1497           0 :       inputChangeRegions.AppendElement(inputChangeRegion);
    1498             :     }
    1499             :     nsIntRegion changeRegion =
    1500           0 :       ResultChangeRegionForPrimitive(descr, inputChangeRegions);
    1501           0 :     changeRegion.And(changeRegion, descr.PrimitiveSubregion());
    1502           0 :     resultChangeRegions.AppendElement(changeRegion);
    1503             :   }
    1504             : 
    1505           0 :   MOZ_RELEASE_ASSERT(!resultChangeRegions.IsEmpty());
    1506           0 :   return resultChangeRegions[resultChangeRegions.Length() - 1];
    1507             : }
    1508             : 
    1509             : static float
    1510           0 : ResultOfZeroUnderTransferFunction(const AttributeMap& aFunctionAttributes)
    1511             : {
    1512           0 :   switch (aFunctionAttributes.GetUint(eComponentTransferFunctionType)) {
    1513             :     case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
    1514             :     {
    1515             :       const nsTArray<float>& tableValues =
    1516           0 :         aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
    1517           0 :       if (tableValues.Length() < 2) {
    1518           0 :         return 0.0f;
    1519             :       }
    1520           0 :       return tableValues[0];
    1521             :     }
    1522             : 
    1523             :     case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
    1524             :     {
    1525             :       const nsTArray<float>& tableValues =
    1526           0 :         aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
    1527           0 :       if (tableValues.Length() < 1) {
    1528           0 :         return 0.0f;
    1529             :       }
    1530           0 :       return tableValues[0];
    1531             :     }
    1532             : 
    1533             :     case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
    1534           0 :       return aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
    1535             : 
    1536             :     case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
    1537           0 :       return aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
    1538             : 
    1539             :     case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
    1540             :     default:
    1541           0 :       return 0.0f;
    1542             :   }
    1543             : }
    1544             : 
    1545             : nsIntRegion
    1546           0 : FilterSupport::PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
    1547             :                                              const nsTArray<nsIntRegion>& aInputExtents)
    1548             : {
    1549           0 :   const AttributeMap& atts = aDescription.Attributes();
    1550           0 :   switch (aDescription.Type()) {
    1551             : 
    1552             :     case PrimitiveType::Empty:
    1553           0 :       return IntRect();
    1554             : 
    1555             :     case PrimitiveType::Composite:
    1556             :     {
    1557           0 :       uint32_t op = atts.GetUint(eCompositeOperator);
    1558           0 :       if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
    1559             :         // The arithmetic composite primitive can draw outside the bounding
    1560             :         // box of its source images.
    1561           0 :         const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
    1562           0 :         MOZ_ASSERT(coefficients.Length() == 4);
    1563             : 
    1564             :         // The calculation is:
    1565             :         // r = c[0] * in[0] * in[1] + c[1] * in[0] + c[2] * in[1] + c[3]
    1566           0 :         nsIntRegion region;
    1567           0 :         if (coefficients[0] > 0.0f) {
    1568           0 :           region = aInputExtents[0].Intersect(aInputExtents[1]);
    1569             :         }
    1570           0 :         if (coefficients[1] > 0.0f) {
    1571           0 :           region.Or(region, aInputExtents[0]);
    1572             :         }
    1573           0 :         if (coefficients[2] > 0.0f) {
    1574           0 :           region.Or(region, aInputExtents[1]);
    1575             :         }
    1576           0 :         if (coefficients[3] > 0.0f) {
    1577           0 :           region = aDescription.PrimitiveSubregion();
    1578             :         }
    1579           0 :         return region;
    1580             :       }
    1581           0 :       if (op == SVG_FECOMPOSITE_OPERATOR_IN) {
    1582           0 :         return aInputExtents[0].Intersect(aInputExtents[1]);
    1583             :       }
    1584           0 :       return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
    1585             :     }
    1586             : 
    1587             :     case PrimitiveType::Flood:
    1588             :     {
    1589           0 :       if (atts.GetColor(eFloodColor).a == 0.0f) {
    1590           0 :         return IntRect();
    1591             :       }
    1592           0 :       return aDescription.PrimitiveSubregion();
    1593             :     }
    1594             : 
    1595             :     case PrimitiveType::ColorMatrix:
    1596             :     {
    1597           0 :       if (atts.GetUint(eColorMatrixType) == (uint32_t)SVG_FECOLORMATRIX_TYPE_MATRIX) {
    1598           0 :         const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
    1599           0 :         if (values.Length() == 20 && values[19] > 0.0f) {
    1600           0 :           return aDescription.PrimitiveSubregion();
    1601             :         }
    1602             :       }
    1603           0 :       return aInputExtents[0];
    1604             :     }
    1605             : 
    1606             :     case PrimitiveType::ComponentTransfer:
    1607             :     {
    1608             :       AttributeMap functionAttributes =
    1609           0 :         atts.GetAttributeMap(eComponentTransferFunctionA);
    1610           0 :       if (ResultOfZeroUnderTransferFunction(functionAttributes) > 0.0f) {
    1611           0 :         return aDescription.PrimitiveSubregion();
    1612             :       }
    1613           0 :       return aInputExtents[0];
    1614             :     }
    1615             : 
    1616             :     case PrimitiveType::Turbulence:
    1617             :     case PrimitiveType::Image:
    1618             :     case PrimitiveType::DiffuseLighting:
    1619             :     case PrimitiveType::SpecularLighting:
    1620             :     {
    1621           0 :       return aDescription.PrimitiveSubregion();
    1622             :     }
    1623             : 
    1624             :     case PrimitiveType::Morphology:
    1625             :     {
    1626           0 :       uint32_t op = atts.GetUint(eMorphologyOperator);
    1627           0 :       if (op == SVG_OPERATOR_ERODE) {
    1628           0 :         return aInputExtents[0];
    1629             :       }
    1630           0 :       Size radii = atts.GetSize(eMorphologyRadii);
    1631           0 :       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
    1632           0 :       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
    1633           0 :       return aInputExtents[0].Inflated(nsIntMargin(ry, rx, ry, rx));
    1634             :     }
    1635             : 
    1636             :     default:
    1637           0 :       return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
    1638             :   }
    1639             : }
    1640             : 
    1641             : /* static */ nsIntRegion
    1642           0 : FilterSupport::ComputePostFilterExtents(const FilterDescription& aFilter,
    1643             :                                         const nsIntRegion& aSourceGraphicExtents)
    1644             : {
    1645           0 :   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
    1646           0 :   MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
    1647           0 :   nsTArray<nsIntRegion> postFilterExtents;
    1648             : 
    1649           0 :   for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
    1650           0 :     const FilterPrimitiveDescription& descr = primitives[i];
    1651           0 :     nsIntRegion filterSpace = descr.FilterSpaceBounds();
    1652             : 
    1653           0 :     nsTArray<nsIntRegion> inputExtents;
    1654           0 :     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
    1655           0 :       int32_t inputIndex = descr.InputPrimitiveIndex(j);
    1656           0 :       MOZ_ASSERT(inputIndex < i, "bad input index");
    1657             :       nsIntRegion inputExtent =
    1658             :         ElementForIndex(inputIndex, postFilterExtents,
    1659           0 :                         aSourceGraphicExtents, filterSpace, filterSpace);
    1660           0 :       inputExtents.AppendElement(inputExtent);
    1661             :     }
    1662           0 :     nsIntRegion extent = PostFilterExtentsForPrimitive(descr, inputExtents);
    1663           0 :     extent.And(extent, descr.PrimitiveSubregion());
    1664           0 :     postFilterExtents.AppendElement(extent);
    1665             :   }
    1666             : 
    1667           0 :   MOZ_RELEASE_ASSERT(!postFilterExtents.IsEmpty());
    1668           0 :   return postFilterExtents[postFilterExtents.Length() - 1];
    1669             : }
    1670             : 
    1671             : static nsIntRegion
    1672           0 : SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
    1673             :                                const nsIntRegion& aResultNeededRegion,
    1674             :                                int32_t aInputIndex)
    1675             : {
    1676           0 :   const AttributeMap& atts = aDescription.Attributes();
    1677           0 :   switch (aDescription.Type()) {
    1678             : 
    1679             :     case PrimitiveType::Flood:
    1680             :     case PrimitiveType::Turbulence:
    1681             :     case PrimitiveType::Image:
    1682           0 :       MOZ_CRASH("GFX: this shouldn't be called for filters without inputs");
    1683             :       return nsIntRegion();
    1684             : 
    1685             :     case PrimitiveType::Empty:
    1686           0 :       return nsIntRegion();
    1687             : 
    1688             :     case PrimitiveType::Blend:
    1689             :     case PrimitiveType::Composite:
    1690             :     case PrimitiveType::Merge:
    1691             :     case PrimitiveType::ColorMatrix:
    1692             :     case PrimitiveType::ComponentTransfer:
    1693             :     case PrimitiveType::ToAlpha:
    1694           0 :       return aResultNeededRegion;
    1695             : 
    1696             :     case PrimitiveType::Morphology:
    1697             :     {
    1698           0 :       Size radii = atts.GetSize(eMorphologyRadii);
    1699           0 :       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
    1700           0 :       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
    1701           0 :       return aResultNeededRegion.Inflated(nsIntMargin(ry, rx, ry, rx));
    1702             :     }
    1703             : 
    1704             :     case PrimitiveType::Tile:
    1705           0 :       return IntRect(INT32_MIN/2, INT32_MIN/2, INT32_MAX, INT32_MAX);
    1706             : 
    1707             :     case PrimitiveType::ConvolveMatrix:
    1708             :     {
    1709           0 :       Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
    1710           0 :       IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
    1711           0 :       IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
    1712           0 :       nsIntMargin m(ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
    1713           0 :                     ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)),
    1714           0 :                     ceil(kernelUnitLength.width * (target.x)),
    1715           0 :                     ceil(kernelUnitLength.height * (target.y)));
    1716           0 :       return aResultNeededRegion.Inflated(m);
    1717             :     }
    1718             : 
    1719             :     case PrimitiveType::Offset:
    1720             :     {
    1721           0 :       IntPoint offset = atts.GetIntPoint(eOffsetOffset);
    1722           0 :       return aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
    1723             :     }
    1724             : 
    1725             :     case PrimitiveType::DisplacementMap:
    1726             :     {
    1727           0 :       if (aInputIndex == 1) {
    1728           0 :         return aResultNeededRegion;
    1729             :       }
    1730           0 :       int32_t scale = ceil(std::abs(atts.GetFloat(eDisplacementMapScale)));
    1731           0 :       return aResultNeededRegion.Inflated(nsIntMargin(scale, scale, scale, scale));
    1732             :     }
    1733             : 
    1734             :     case PrimitiveType::GaussianBlur:
    1735             :     {
    1736           0 :       Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
    1737           0 :       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
    1738           0 :       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
    1739           0 :       return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
    1740             :     }
    1741             : 
    1742             :     case PrimitiveType::DropShadow:
    1743             :     {
    1744           0 :       IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
    1745             :       nsIntRegion offsetRegion =
    1746           0 :         aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
    1747           0 :       Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
    1748           0 :       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
    1749           0 :       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
    1750           0 :       nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
    1751           0 :       blurRegion.Or(blurRegion, aResultNeededRegion);
    1752           0 :       return blurRegion;
    1753             :     }
    1754             : 
    1755             :     case PrimitiveType::DiffuseLighting:
    1756             :     case PrimitiveType::SpecularLighting:
    1757             :     {
    1758           0 :       Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
    1759           0 :       int32_t dx = ceil(kernelUnitLength.width);
    1760           0 :       int32_t dy = ceil(kernelUnitLength.height);
    1761           0 :       return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
    1762             :     }
    1763             : 
    1764             :     default:
    1765           0 :       return nsIntRegion();
    1766             :   }
    1767             : 
    1768             : }
    1769             : 
    1770             : /* static */ void
    1771           0 : FilterSupport::ComputeSourceNeededRegions(const FilterDescription& aFilter,
    1772             :                                           const nsIntRegion& aResultNeededRegion,
    1773             :                                           nsIntRegion& aSourceGraphicNeededRegion,
    1774             :                                           nsIntRegion& aFillPaintNeededRegion,
    1775             :                                           nsIntRegion& aStrokePaintNeededRegion)
    1776             : {
    1777           0 :   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
    1778           0 :   MOZ_ASSERT(!primitives.IsEmpty());
    1779           0 :   if (primitives.IsEmpty()) {
    1780           0 :     return;
    1781             :   }
    1782             : 
    1783           0 :   nsTArray<nsIntRegion> primitiveNeededRegions;
    1784           0 :   primitiveNeededRegions.AppendElements(primitives.Length());
    1785             : 
    1786           0 :   primitiveNeededRegions[primitives.Length() - 1] = aResultNeededRegion;
    1787             : 
    1788           0 :   for (int32_t i = primitives.Length() - 1; i >= 0; --i) {
    1789           0 :     const FilterPrimitiveDescription& descr = primitives[i];
    1790           0 :     nsIntRegion neededRegion = primitiveNeededRegions[i];
    1791           0 :     neededRegion.And(neededRegion, descr.PrimitiveSubregion());
    1792             : 
    1793           0 :     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
    1794           0 :       int32_t inputIndex = descr.InputPrimitiveIndex(j);
    1795           0 :       MOZ_ASSERT(inputIndex < i, "bad input index");
    1796             :       nsIntRegion* inputNeededRegion = const_cast<nsIntRegion*>(
    1797             :         &ElementForIndex(inputIndex, primitiveNeededRegions,
    1798             :                          aSourceGraphicNeededRegion,
    1799           0 :                          aFillPaintNeededRegion, aStrokePaintNeededRegion));
    1800             :       inputNeededRegion->Or(*inputNeededRegion,
    1801           0 :         SourceNeededRegionForPrimitive(descr, neededRegion, j));
    1802             :     }
    1803             :   }
    1804             : 
    1805             :   // Clip original SourceGraphic to first filter region.
    1806           0 :   const FilterPrimitiveDescription& firstDescr = primitives[0];
    1807             :   aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
    1808           0 :                                  firstDescr.FilterSpaceBounds());
    1809             : }
    1810             : 
    1811             : // FilterPrimitiveDescription
    1812             : 
    1813           0 : FilterPrimitiveDescription::FilterPrimitiveDescription()
    1814             :  : mType(PrimitiveType::Empty)
    1815             :  , mOutputColorSpace(ColorSpace::SRGB)
    1816           0 :  , mIsTainted(false)
    1817             : {
    1818           0 : }
    1819             : 
    1820           0 : FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType)
    1821             :  : mType(aType)
    1822             :  , mOutputColorSpace(ColorSpace::SRGB)
    1823           0 :  , mIsTainted(false)
    1824             : {
    1825           0 : }
    1826             : 
    1827           0 : FilterPrimitiveDescription::FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther)
    1828           0 :  : mType(aOther.mType)
    1829             :  , mAttributes(aOther.mAttributes)
    1830             :  , mInputPrimitives(aOther.mInputPrimitives)
    1831             :  , mFilterPrimitiveSubregion(aOther.mFilterPrimitiveSubregion)
    1832             :  , mFilterSpaceBounds(aOther.mFilterSpaceBounds)
    1833             :  , mInputColorSpaces(aOther.mInputColorSpaces)
    1834           0 :  , mOutputColorSpace(aOther.mOutputColorSpace)
    1835           0 :  , mIsTainted(aOther.mIsTainted)
    1836             : {
    1837           0 : }
    1838             : 
    1839             : FilterPrimitiveDescription&
    1840           0 : FilterPrimitiveDescription::operator=(const FilterPrimitiveDescription& aOther)
    1841             : {
    1842           0 :   if (this != &aOther) {
    1843           0 :     mType = aOther.mType;
    1844           0 :     mAttributes = aOther.mAttributes;
    1845           0 :     mInputPrimitives = aOther.mInputPrimitives;
    1846           0 :     mFilterPrimitiveSubregion = aOther.mFilterPrimitiveSubregion;
    1847           0 :     mFilterSpaceBounds = aOther.mFilterSpaceBounds;
    1848           0 :     mInputColorSpaces = aOther.mInputColorSpaces;
    1849           0 :     mOutputColorSpace = aOther.mOutputColorSpace;
    1850           0 :     mIsTainted = aOther.mIsTainted;
    1851             :   }
    1852           0 :   return *this;
    1853             : }
    1854             : 
    1855             : bool
    1856           0 : FilterPrimitiveDescription::operator==(const FilterPrimitiveDescription& aOther) const
    1857             : {
    1858           0 :   return mType == aOther.mType &&
    1859           0 :     mFilterPrimitiveSubregion.IsEqualInterior(aOther.mFilterPrimitiveSubregion) &&
    1860           0 :     mFilterSpaceBounds.IsEqualInterior(aOther.mFilterSpaceBounds) &&
    1861           0 :     mOutputColorSpace == aOther.mOutputColorSpace &&
    1862           0 :     mIsTainted == aOther.mIsTainted &&
    1863           0 :     mInputPrimitives == aOther.mInputPrimitives &&
    1864           0 :     mInputColorSpaces == aOther.mInputColorSpaces &&
    1865           0 :     mAttributes == aOther.mAttributes;
    1866             : }
    1867             : 
    1868             : // FilterDescription
    1869             : 
    1870             : bool
    1871           0 : FilterDescription::operator==(const FilterDescription& aOther) const
    1872             : {
    1873           0 :   return mPrimitives == aOther.mPrimitives;
    1874             : }
    1875             : 
    1876             : // AttributeMap
    1877             : 
    1878             : // A class that wraps different types for easy storage in a hashtable. Only
    1879             : // used by AttributeMap.
    1880             : struct FilterAttribute {
    1881             :   FilterAttribute(const FilterAttribute& aOther);
    1882             :   ~FilterAttribute();
    1883             : 
    1884             :   bool operator==(const FilterAttribute& aOther) const;
    1885           0 :   bool operator!=(const FilterAttribute& aOther) const
    1886             :   {
    1887           0 :     return !(*this == aOther);
    1888             :   }
    1889             : 
    1890           0 :   AttributeType Type() const { return mType; }
    1891             : 
    1892             : #define MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(type, typeLabel)   \
    1893             :   explicit FilterAttribute(type aValue)                        \
    1894             :    : mType(AttributeType::e##typeLabel), m##typeLabel(aValue)  \
    1895             :   {}                                                           \
    1896             :   type As##typeLabel() {                                       \
    1897             :     MOZ_ASSERT(mType == AttributeType::e##typeLabel);          \
    1898             :     return m##typeLabel;                                       \
    1899             :   }
    1900             : 
    1901             : #define MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(className)         \
    1902             :   explicit FilterAttribute(const className& aValue)            \
    1903             :    : mType(AttributeType::e##className), m##className(new className(aValue)) \
    1904             :   {}                                                           \
    1905             :   className As##className() {                                  \
    1906             :     MOZ_ASSERT(mType == AttributeType::e##className);          \
    1907             :     return *m##className;                                      \
    1908             :   }
    1909             : 
    1910           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(bool, Bool)
    1911           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(uint32_t, Uint)
    1912           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(float, Float)
    1913           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Size)
    1914           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntSize)
    1915           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntPoint)
    1916           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix)
    1917           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix5x4)
    1918           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Point3D)
    1919           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Color)
    1920           0 :   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(AttributeMap)
    1921             : 
    1922             : #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC
    1923             : #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS
    1924             : 
    1925           0 :   FilterAttribute(const float* aValue, uint32_t aLength)
    1926           0 :    : mType(AttributeType::eFloats)
    1927             :   {
    1928           0 :     mFloats = new nsTArray<float>();
    1929           0 :     mFloats->AppendElements(aValue, aLength);
    1930           0 :   }
    1931             : 
    1932           0 :   const nsTArray<float>& AsFloats() const {
    1933           0 :     MOZ_ASSERT(mType == AttributeType::eFloats);
    1934           0 :     return *mFloats;
    1935             :   }
    1936             : 
    1937             : private:
    1938             :   const AttributeType mType;
    1939             : 
    1940             :   union {
    1941             :     bool mBool;
    1942             :     uint32_t mUint;
    1943             :     float mFloat;
    1944             :     Size* mSize;
    1945             :     IntSize* mIntSize;
    1946             :     IntPoint* mIntPoint;
    1947             :     Matrix* mMatrix;
    1948             :     Matrix5x4* mMatrix5x4;
    1949             :     Point3D* mPoint3D;
    1950             :     Color* mColor;
    1951             :     AttributeMap* mAttributeMap;
    1952             :     nsTArray<float>* mFloats;
    1953             :   };
    1954             : };
    1955             : 
    1956           0 : FilterAttribute::FilterAttribute(const FilterAttribute& aOther)
    1957           0 :  : mType(aOther.mType)
    1958             : {
    1959           0 :   switch (mType) {
    1960             :     case AttributeType::eBool:
    1961           0 :       mBool = aOther.mBool;
    1962           0 :       break;
    1963             :     case AttributeType::eUint:
    1964           0 :       mUint = aOther.mUint;
    1965           0 :       break;
    1966             :     case AttributeType::eFloat:
    1967           0 :       mFloat = aOther.mFloat;
    1968           0 :       break;
    1969             : 
    1970             : #define HANDLE_CLASS(className)                            \
    1971             :     case AttributeType::e##className:                      \
    1972             :       m##className = new className(*aOther.m##className);  \
    1973             :       break;
    1974             : 
    1975           0 :     HANDLE_CLASS(Size)
    1976           0 :     HANDLE_CLASS(IntSize)
    1977           0 :     HANDLE_CLASS(IntPoint)
    1978           0 :     HANDLE_CLASS(Matrix)
    1979           0 :     HANDLE_CLASS(Matrix5x4)
    1980           0 :     HANDLE_CLASS(Point3D)
    1981           0 :     HANDLE_CLASS(Color)
    1982           0 :     HANDLE_CLASS(AttributeMap)
    1983             : 
    1984             : #undef HANDLE_CLASS
    1985             : 
    1986             :     case AttributeType::eFloats:
    1987           0 :       mFloats = new nsTArray<float>(*aOther.mFloats);
    1988           0 :       break;
    1989             :     case AttributeType::Max:
    1990           0 :       break;
    1991             :   }
    1992           0 : }
    1993             : 
    1994           0 : FilterAttribute::~FilterAttribute() {
    1995           0 :   switch (mType) {
    1996             :     case AttributeType::Max:
    1997             :     case AttributeType::eBool:
    1998             :     case AttributeType::eUint:
    1999             :     case AttributeType::eFloat:
    2000           0 :       break;
    2001             : 
    2002             : #define HANDLE_CLASS(className)                            \
    2003             :     case AttributeType::e##className:                      \
    2004             :       delete m##className;                                 \
    2005             :       break;
    2006             : 
    2007           0 :     HANDLE_CLASS(Size)
    2008           0 :     HANDLE_CLASS(IntSize)
    2009           0 :     HANDLE_CLASS(IntPoint)
    2010           0 :     HANDLE_CLASS(Matrix)
    2011           0 :     HANDLE_CLASS(Matrix5x4)
    2012           0 :     HANDLE_CLASS(Point3D)
    2013           0 :     HANDLE_CLASS(Color)
    2014           0 :     HANDLE_CLASS(AttributeMap)
    2015             : 
    2016             : #undef HANDLE_CLASS
    2017             : 
    2018             :     case AttributeType::eFloats:
    2019           0 :       delete mFloats;
    2020           0 :       break;
    2021             :   }
    2022           0 : }
    2023             : 
    2024             : bool
    2025           0 : FilterAttribute::operator==(const FilterAttribute& aOther) const
    2026             : {
    2027           0 :   if (mType != aOther.mType) {
    2028           0 :     return false;
    2029             :   }
    2030             : 
    2031           0 :   switch (mType) {
    2032             : 
    2033             : #define HANDLE_TYPE(typeName)                              \
    2034             :     case AttributeType::e##typeName:                       \
    2035             :       return m##typeName == aOther.m##typeName;
    2036             : 
    2037           0 :     HANDLE_TYPE(Bool)
    2038           0 :     HANDLE_TYPE(Uint)
    2039           0 :     HANDLE_TYPE(Float)
    2040           0 :     HANDLE_TYPE(Size)
    2041           0 :     HANDLE_TYPE(IntSize)
    2042           0 :     HANDLE_TYPE(IntPoint)
    2043           0 :     HANDLE_TYPE(Matrix)
    2044           0 :     HANDLE_TYPE(Matrix5x4)
    2045           0 :     HANDLE_TYPE(Point3D)
    2046           0 :     HANDLE_TYPE(Color)
    2047           0 :     HANDLE_TYPE(AttributeMap)
    2048           0 :     HANDLE_TYPE(Floats)
    2049             : 
    2050             : #undef HANDLE_TYPE
    2051             : 
    2052             :     default:
    2053           0 :       return false;
    2054             :   }
    2055             : }
    2056             : 
    2057             : typedef FilterAttribute Attribute;
    2058             : 
    2059           0 : AttributeMap::AttributeMap()
    2060             : {
    2061           0 : }
    2062             : 
    2063           0 : AttributeMap::~AttributeMap()
    2064             : {
    2065           0 : }
    2066             : 
    2067           0 : AttributeMap::AttributeMap(const AttributeMap& aOther)
    2068             : {
    2069           0 :   for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
    2070           0 :     const uint32_t& attributeName = iter.Key();
    2071           0 :     Attribute* attribute = iter.UserData();
    2072           0 :     mMap.Put(attributeName, new Attribute(*attribute));
    2073             :   }
    2074           0 : }
    2075             : 
    2076             : AttributeMap&
    2077           0 : AttributeMap::operator=(const AttributeMap& aOther)
    2078             : {
    2079           0 :   if (this != &aOther) {
    2080           0 :     mMap.Clear();
    2081           0 :     for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
    2082           0 :       const uint32_t& attributeName = iter.Key();
    2083           0 :       Attribute* attribute = iter.UserData();
    2084           0 :       mMap.Put(attributeName, new Attribute(*attribute));
    2085             :     }
    2086             :   }
    2087           0 :   return *this;
    2088             : }
    2089             : 
    2090             : bool
    2091           0 : AttributeMap::operator==(const AttributeMap& aOther) const
    2092             : {
    2093           0 :   if (mMap.Count() != aOther.mMap.Count()) {
    2094           0 :     return false;
    2095             :   }
    2096             : 
    2097           0 :   for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
    2098           0 :     const uint32_t& attributeName = iter.Key();
    2099           0 :     Attribute* attribute = iter.UserData();
    2100           0 :     Attribute* matchingAttribute = mMap.Get(attributeName);
    2101           0 :     if (!matchingAttribute || *matchingAttribute != *attribute) {
    2102           0 :       return false;
    2103             :     }
    2104             :   }
    2105             : 
    2106           0 :   return true;
    2107             : }
    2108             : 
    2109             : uint32_t
    2110           0 : AttributeMap::Count() const
    2111             : {
    2112           0 :   return mMap.Count();
    2113             : }
    2114             : 
    2115             : nsClassHashtable<nsUint32HashKey, FilterAttribute>::Iterator
    2116           0 : AttributeMap::ConstIter() const
    2117             : {
    2118           0 :   return mMap.ConstIter();
    2119             : }
    2120             : 
    2121             : /* static */ AttributeType
    2122           0 : AttributeMap::GetType(FilterAttribute* aAttribute)
    2123             : {
    2124           0 :   return aAttribute->Type();
    2125             : }
    2126             : 
    2127             : #define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \
    2128             :   type                                                               \
    2129             :   AttributeMap::Get##typeLabel(AttributeName aName) const {          \
    2130             :     Attribute* value = mMap.Get(aName);                              \
    2131             :     return value ? value->As##typeLabel() : defaultValue;            \
    2132             :   }                                                                  \
    2133             :   void                                                               \
    2134             :   AttributeMap::Set(AttributeName aName, type aValue) {              \
    2135             :     mMap.Put(aName, new Attribute(aValue));                          \
    2136             :   }
    2137             : 
    2138             : #define MAKE_ATTRIBUTE_HANDLERS_CLASS(className)                     \
    2139             :   className                                                          \
    2140             :   AttributeMap::Get##className(AttributeName aName) const {          \
    2141             :     Attribute* value = mMap.Get(aName);                              \
    2142             :     return value ? value->As##className() : className();             \
    2143             :   }                                                                  \
    2144             :   void                                                               \
    2145             :   AttributeMap::Set(AttributeName aName, const className& aValue) {  \
    2146             :     mMap.Put(aName, new Attribute(aValue));                          \
    2147             :   }
    2148             : 
    2149           0 : MAKE_ATTRIBUTE_HANDLERS_BASIC(bool, Bool, false)
    2150           0 : MAKE_ATTRIBUTE_HANDLERS_BASIC(uint32_t, Uint, 0)
    2151           0 : MAKE_ATTRIBUTE_HANDLERS_BASIC(float, Float, 0)
    2152           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Size)
    2153           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(IntSize)
    2154           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(IntPoint)
    2155           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix)
    2156           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix5x4)
    2157           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Point3D)
    2158           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(Color)
    2159           0 : MAKE_ATTRIBUTE_HANDLERS_CLASS(AttributeMap)
    2160             : 
    2161             : #undef MAKE_ATTRIBUTE_HANDLERS_BASIC
    2162             : #undef MAKE_ATTRIBUTE_HANDLERS_CLASS
    2163             : 
    2164             : const nsTArray<float>&
    2165           0 : AttributeMap::GetFloats(AttributeName aName) const
    2166             : {
    2167           0 :   Attribute* value = mMap.LookupForAdd(aName).OrInsert(
    2168           0 :     [] () { return new Attribute(nullptr, 0); });
    2169           0 :   return value->AsFloats();
    2170             : }
    2171             : 
    2172             : void
    2173           0 : AttributeMap::Set(AttributeName aName, const float* aValues, int32_t aLength)
    2174             : {
    2175           0 :   mMap.Put(aName, new Attribute(aValues, aLength));
    2176           0 : }
    2177             : 
    2178             : } // namespace gfx
    2179             : } // namespace mozilla

Generated by: LCOV version 1.13