gfx/src/FilterSupport.cpp

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

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

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

     1 /* -*- Mode: C++; tab-width: 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/. */
     6 #include "FilterSupport.h"
     8 #include "mozilla/gfx/2D.h"
     9 #include "mozilla/gfx/Filters.h"
    10 #include "mozilla/PodOperations.h"
    12 #include "gfxContext.h"
    13 #include "gfxPattern.h"
    14 #include "gfxPlatform.h"
    15 #include "gfx2DGlue.h"
    17 #include "nsMargin.h"
    19 // c = n / 255
    20 // c <= 0.0031308f ? c * 12.92f : 1.055f * powf(c, 1 / 2.4f) - 0.055f
    21 static const float glinearRGBTosRGBMap[256] = {
    22   0.000f, 0.050f, 0.085f, 0.111f, 0.132f, 0.150f, 0.166f, 0.181f,
    23   0.194f, 0.207f, 0.219f, 0.230f, 0.240f, 0.250f, 0.260f, 0.269f,
    24   0.278f, 0.286f, 0.295f, 0.303f, 0.310f, 0.318f, 0.325f, 0.332f,
    25   0.339f, 0.346f, 0.352f, 0.359f, 0.365f, 0.371f, 0.378f, 0.383f,
    26   0.389f, 0.395f, 0.401f, 0.406f, 0.412f, 0.417f, 0.422f, 0.427f,
    27   0.433f, 0.438f, 0.443f, 0.448f, 0.452f, 0.457f, 0.462f, 0.466f,
    28   0.471f, 0.476f, 0.480f, 0.485f, 0.489f, 0.493f, 0.498f, 0.502f,
    29   0.506f, 0.510f, 0.514f, 0.518f, 0.522f, 0.526f, 0.530f, 0.534f,
    30   0.538f, 0.542f, 0.546f, 0.549f, 0.553f, 0.557f, 0.561f, 0.564f,
    31   0.568f, 0.571f, 0.575f, 0.579f, 0.582f, 0.586f, 0.589f, 0.592f,
    32   0.596f, 0.599f, 0.603f, 0.606f, 0.609f, 0.613f, 0.616f, 0.619f,
    33   0.622f, 0.625f, 0.629f, 0.632f, 0.635f, 0.638f, 0.641f, 0.644f,
    34   0.647f, 0.650f, 0.653f, 0.656f, 0.659f, 0.662f, 0.665f, 0.668f,
    35   0.671f, 0.674f, 0.677f, 0.680f, 0.683f, 0.685f, 0.688f, 0.691f,
    36   0.694f, 0.697f, 0.699f, 0.702f, 0.705f, 0.708f, 0.710f, 0.713f,
    37   0.716f, 0.718f, 0.721f, 0.724f, 0.726f, 0.729f, 0.731f, 0.734f,
    38   0.737f, 0.739f, 0.742f, 0.744f, 0.747f, 0.749f, 0.752f, 0.754f,
    39   0.757f, 0.759f, 0.762f, 0.764f, 0.767f, 0.769f, 0.772f, 0.774f,
    40   0.776f, 0.779f, 0.781f, 0.784f, 0.786f, 0.788f, 0.791f, 0.793f,
    41   0.795f, 0.798f, 0.800f, 0.802f, 0.805f, 0.807f, 0.809f, 0.812f,
    42   0.814f, 0.816f, 0.818f, 0.821f, 0.823f, 0.825f, 0.827f, 0.829f,
    43   0.832f, 0.834f, 0.836f, 0.838f, 0.840f, 0.843f, 0.845f, 0.847f,
    44   0.849f, 0.851f, 0.853f, 0.855f, 0.857f, 0.860f, 0.862f, 0.864f,
    45   0.866f, 0.868f, 0.870f, 0.872f, 0.874f, 0.876f, 0.878f, 0.880f,
    46   0.882f, 0.884f, 0.886f, 0.888f, 0.890f, 0.892f, 0.894f, 0.896f,
    47   0.898f, 0.900f, 0.902f, 0.904f, 0.906f, 0.908f, 0.910f, 0.912f,
    48   0.914f, 0.916f, 0.918f, 0.920f, 0.922f, 0.924f, 0.926f, 0.928f,
    49   0.930f, 0.931f, 0.933f, 0.935f, 0.937f, 0.939f, 0.941f, 0.943f,
    50   0.945f, 0.946f, 0.948f, 0.950f, 0.952f, 0.954f, 0.956f, 0.957f,
    51   0.959f, 0.961f, 0.963f, 0.965f, 0.967f, 0.968f, 0.970f, 0.972f,
    52   0.974f, 0.975f, 0.977f, 0.979f, 0.981f, 0.983f, 0.984f, 0.986f,
    53   0.988f, 0.990f, 0.991f, 0.993f, 0.995f, 0.997f, 0.998f, 1.000f
    54 };
    56 // c = n / 255
    57 // c <= 0.04045f ? c / 12.92f : powf((c + 0.055f) / 1.055f, 2.4f)
    58 static const float gsRGBToLinearRGBMap[256] = {
    59   0.000f, 0.000f, 0.001f, 0.001f, 0.001f, 0.002f, 0.002f, 0.002f,
    60   0.002f, 0.003f, 0.003f, 0.003f, 0.004f, 0.004f, 0.004f, 0.005f,
    61   0.005f, 0.006f, 0.006f, 0.007f, 0.007f, 0.007f, 0.008f, 0.009f,
    62   0.009f, 0.010f, 0.010f, 0.011f, 0.012f, 0.012f, 0.013f, 0.014f,
    63   0.014f, 0.015f, 0.016f, 0.017f, 0.018f, 0.019f, 0.019f, 0.020f,
    64   0.021f, 0.022f, 0.023f, 0.024f, 0.025f, 0.026f, 0.027f, 0.028f,
    65   0.030f, 0.031f, 0.032f, 0.033f, 0.034f, 0.036f, 0.037f, 0.038f,
    66   0.040f, 0.041f, 0.042f, 0.044f, 0.045f, 0.047f, 0.048f, 0.050f,
    67   0.051f, 0.053f, 0.054f, 0.056f, 0.058f, 0.060f, 0.061f, 0.063f,
    68   0.065f, 0.067f, 0.068f, 0.070f, 0.072f, 0.074f, 0.076f, 0.078f,
    69   0.080f, 0.082f, 0.084f, 0.087f, 0.089f, 0.091f, 0.093f, 0.095f,
    70   0.098f, 0.100f, 0.102f, 0.105f, 0.107f, 0.109f, 0.112f, 0.114f,
    71   0.117f, 0.120f, 0.122f, 0.125f, 0.127f, 0.130f, 0.133f, 0.136f,
    72   0.138f, 0.141f, 0.144f, 0.147f, 0.150f, 0.153f, 0.156f, 0.159f,
    73   0.162f, 0.165f, 0.168f, 0.171f, 0.175f, 0.178f, 0.181f, 0.184f,
    74   0.188f, 0.191f, 0.195f, 0.198f, 0.202f, 0.205f, 0.209f, 0.212f,
    75   0.216f, 0.220f, 0.223f, 0.227f, 0.231f, 0.235f, 0.238f, 0.242f,
    76   0.246f, 0.250f, 0.254f, 0.258f, 0.262f, 0.266f, 0.270f, 0.275f,
    77   0.279f, 0.283f, 0.287f, 0.292f, 0.296f, 0.301f, 0.305f, 0.309f,
    78   0.314f, 0.319f, 0.323f, 0.328f, 0.332f, 0.337f, 0.342f, 0.347f,
    79   0.352f, 0.356f, 0.361f, 0.366f, 0.371f, 0.376f, 0.381f, 0.386f,
    80   0.392f, 0.397f, 0.402f, 0.407f, 0.413f, 0.418f, 0.423f, 0.429f,
    81   0.434f, 0.440f, 0.445f, 0.451f, 0.456f, 0.462f, 0.468f, 0.474f,
    82   0.479f, 0.485f, 0.491f, 0.497f, 0.503f, 0.509f, 0.515f, 0.521f,
    83   0.527f, 0.533f, 0.539f, 0.546f, 0.552f, 0.558f, 0.565f, 0.571f,
    84   0.578f, 0.584f, 0.591f, 0.597f, 0.604f, 0.610f, 0.617f, 0.624f,
    85   0.631f, 0.638f, 0.644f, 0.651f, 0.658f, 0.665f, 0.672f, 0.680f,
    86   0.687f, 0.694f, 0.701f, 0.708f, 0.716f, 0.723f, 0.730f, 0.738f,
    87   0.745f, 0.753f, 0.761f, 0.768f, 0.776f, 0.784f, 0.791f, 0.799f,
    88   0.807f, 0.815f, 0.823f, 0.831f, 0.839f, 0.847f, 0.855f, 0.863f,
    89   0.871f, 0.880f, 0.888f, 0.896f, 0.905f, 0.913f, 0.922f, 0.930f,
    90   0.939f, 0.947f, 0.956f, 0.965f, 0.973f, 0.982f, 0.991f, 1.000f
    91 };
    93 namespace mozilla {
    94 namespace gfx {
    96 // Some convenience FilterNode creation functions.
    98 static const float kMaxStdDeviation = 500;
   100 namespace FilterWrappers {
   102   static TemporaryRef<FilterNode>
   103   Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
   104   {
   105     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
   106     filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
   107     return filter;
   108   }
   110   static TemporaryRef<FilterNode>
   111   Premultiply(DrawTarget* aDT, FilterNode* aInput)
   112   {
   113     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::PREMULTIPLY);
   114     filter->SetInput(IN_PREMULTIPLY_IN, aInput);
   115     return filter;
   116   }
   118   static TemporaryRef<FilterNode>
   119   LinearRGBToSRGB(DrawTarget* aDT, FilterNode* aInput)
   120   {
   121     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   122     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
   123     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
   124     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
   125     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
   126     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
   127     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
   128     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
   129     transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
   130     return transfer;
   131   }
   133   static TemporaryRef<FilterNode>
   134   SRGBToLinearRGB(DrawTarget* aDT, FilterNode* aInput)
   135   {
   136     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   137     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
   138     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
   139     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
   140     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
   141     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
   142     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
   143     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
   144     transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
   145     return transfer;
   146   }
   148   static TemporaryRef<FilterNode>
   149   Crop(DrawTarget* aDT, FilterNode* aInputFilter, const IntRect& aRect)
   150   {
   151     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CROP);
   152     filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
   153     filter->SetInput(IN_CROP_IN, aInputFilter);
   154     return filter;
   155   }
   157   static TemporaryRef<FilterNode>
   158   Offset(DrawTarget* aDT, FilterNode* aInputFilter, const IntPoint& aOffset)
   159   {
   160     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
   161     filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
   162     filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
   163     return filter;
   164   }
   166   static TemporaryRef<FilterNode>
   167   GaussianBlur(DrawTarget* aDT, FilterNode* aInputFilter, const Size& aStdDeviation)
   168   {
   169     float stdX = float(std::min(aStdDeviation.width, kMaxStdDeviation));
   170     float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
   171     if (stdX == stdY) {
   172       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
   173       filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
   174       filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
   175       return filter;
   176     }
   177     RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
   178     RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
   179     filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
   180     filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
   181     filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
   182     filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
   183     filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
   184     filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
   185     return filterV;
   186   }
   188   static TemporaryRef<FilterNode>
   189   Clear(DrawTarget* aDT)
   190   {
   191     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
   192     filter->SetAttribute(ATT_FLOOD_COLOR, Color(0,0,0,0));
   193     return filter;
   194   }
   196   static TemporaryRef<FilterNode>
   197   ForSurface(DrawTarget* aDT, SourceSurface* aSurface,
   198              const IntPoint& aSurfacePosition)
   199   {
   200     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
   201     filter->SetAttribute(ATT_TRANSFORM_MATRIX,
   202       Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
   203     filter->SetInput(IN_TRANSFORM_IN, aSurface);
   204     return filter;
   205   }
   207   static TemporaryRef<FilterNode>
   208   ToAlpha(DrawTarget* aDT, FilterNode* aInput)
   209   {
   210     float zero = 0.0f;
   211     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   212     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
   213     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
   214     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
   215     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
   216     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
   217     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
   218     transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
   219     transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
   220     return transfer;
   221   }
   223 }
   225 // A class that wraps a FilterNode and handles conversion between different
   226 // color models. Create FilterCachedColorModels with your original filter and
   227 // the color model that this filter outputs in natively, and then call
   228 // ->ForColorModel(colorModel) in order to get a FilterNode which outputs to
   229 // the specified colorModel.
   230 // Internally, this is achieved by wrapping the original FilterNode with
   231 // conversion FilterNodes. These filter nodes are cached in such a way that no
   232 // repeated or back-and-forth conversions happen.
   233 class FilterCachedColorModels
   234 {
   235 public:
   236   NS_INLINE_DECL_REFCOUNTING(FilterCachedColorModels)
   237   // aFilter can be null. In that case, ForColorModel will return a non-null
   238   // completely transparent filter for all color models.
   239   FilterCachedColorModels(DrawTarget* aDT,
   240                           FilterNode* aFilter,
   241                           ColorModel aOriginalColorModel);
   243   // Get a FilterNode for the specified color model, guaranteed to be non-null.
   244   TemporaryRef<FilterNode> ForColorModel(ColorModel aColorModel);
   246   AlphaModel OriginalAlphaModel() const { return mOriginalColorModel.mAlphaModel; }
   248 private:
   249   // Create the required FilterNode that will be cached by ForColorModel.
   250   TemporaryRef<FilterNode> WrapForColorModel(ColorModel aColorModel);
   252   RefPtr<DrawTarget> mDT;
   253   ColorModel mOriginalColorModel;
   255   // This array is indexed by ColorModel::ToIndex.
   256   RefPtr<FilterNode> mFilterForColorModel[4];
   257 };
   259 FilterCachedColorModels::FilterCachedColorModels(DrawTarget* aDT,
   260                                                  FilterNode* aFilter,
   261                                                  ColorModel aOriginalColorModel)
   262  : mDT(aDT)
   263  , mOriginalColorModel(aOriginalColorModel)
   264 {
   265   if (aFilter) {
   266     mFilterForColorModel[aOriginalColorModel.ToIndex()] = aFilter;
   267   } else {
   268     RefPtr<FilterNode> clear = FilterWrappers::Clear(aDT);
   269     mFilterForColorModel[0] = clear;
   270     mFilterForColorModel[1] = clear;
   271     mFilterForColorModel[2] = clear;
   272     mFilterForColorModel[3] = clear;
   273   }
   274 }
   276 TemporaryRef<FilterNode>
   277 FilterCachedColorModels::ForColorModel(ColorModel aColorModel)
   278 {
   279   if (!mFilterForColorModel[aColorModel.ToIndex()]) {
   280     mFilterForColorModel[aColorModel.ToIndex()] = WrapForColorModel(aColorModel);
   281   }
   282   return mFilterForColorModel[aColorModel.ToIndex()];
   283 }
   285 TemporaryRef<FilterNode>
   286 FilterCachedColorModels::WrapForColorModel(ColorModel aColorModel)
   287 {
   288   // Convert one aspect at a time and recurse.
   289   // Conversions between premultiplied / unpremultiplied color channels for the
   290   // same color space can happen directly.
   291   // Conversions between different color spaces can only happen on
   292   // unpremultiplied color channels.
   294   if (aColorModel.mAlphaModel == AlphaModel::Premultiplied) {
   295     RefPtr<FilterNode> unpre =
   296       ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Unpremultiplied));
   297     return FilterWrappers::Premultiply(mDT, unpre);
   298   }
   300   MOZ_ASSERT(aColorModel.mAlphaModel == AlphaModel::Unpremultiplied);
   301   if (aColorModel.mColorSpace == mOriginalColorModel.mColorSpace) {
   302     RefPtr<FilterNode> premultiplied =
   303       ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Premultiplied));
   304     return FilterWrappers::Unpremultiply(mDT, premultiplied);
   305   }
   307   RefPtr<FilterNode> unpremultipliedOriginal =
   308     ForColorModel(ColorModel(mOriginalColorModel.mColorSpace, AlphaModel::Unpremultiplied));
   309   if (aColorModel.mColorSpace == ColorSpace::LinearRGB) {
   310     return FilterWrappers::SRGBToLinearRGB(mDT, unpremultipliedOriginal);
   311   }
   312   return FilterWrappers::LinearRGBToSRGB(mDT, unpremultipliedOriginal);
   313 }
   315 // Create a 4x5 color matrix for the different ways to specify color matrices
   316 // in SVG.
   317 static nsresult
   318 ComputeColorMatrix(uint32_t aColorMatrixType, const nsTArray<float>& aValues,
   319                    float aOutMatrix[20])
   320 {
   321   static const float identityMatrix[] =
   322     { 1, 0, 0, 0, 0,
   323       0, 1, 0, 0, 0,
   324       0, 0, 1, 0, 0,
   325       0, 0, 0, 1, 0 };
   327   static const float luminanceToAlphaMatrix[] =
   328     { 0,       0,       0,       0, 0,
   329       0,       0,       0,       0, 0,
   330       0,       0,       0,       0, 0,
   331       0.2125f, 0.7154f, 0.0721f, 0, 0 };
   333   switch (aColorMatrixType) {
   335     case SVG_FECOLORMATRIX_TYPE_MATRIX:
   336     {
   337       if (aValues.Length() != 20)
   338         return NS_ERROR_FAILURE;
   340       PodCopy(aOutMatrix, aValues.Elements(), 20);
   341       break;
   342     }
   344     case SVG_FECOLORMATRIX_TYPE_SATURATE:
   345     {
   346       if (aValues.Length() != 1)
   347         return NS_ERROR_FAILURE;
   349       float s = aValues[0];
   351       if (s < 0)
   352         return NS_ERROR_FAILURE;
   354       PodCopy(aOutMatrix, identityMatrix, 20);
   356       aOutMatrix[0] = 0.213f + 0.787f * s;
   357       aOutMatrix[1] = 0.715f - 0.715f * s;
   358       aOutMatrix[2] = 0.072f - 0.072f * s;
   360       aOutMatrix[5] = 0.213f - 0.213f * s;
   361       aOutMatrix[6] = 0.715f + 0.285f * s;
   362       aOutMatrix[7] = 0.072f - 0.072f * s;
   364       aOutMatrix[10] = 0.213f - 0.213f * s;
   365       aOutMatrix[11] = 0.715f - 0.715f * s;
   366       aOutMatrix[12] = 0.072f + 0.928f * s;
   368       break;
   369     }
   371     case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE:
   372     {
   373       if (aValues.Length() != 1)
   374         return NS_ERROR_FAILURE;
   376       PodCopy(aOutMatrix, identityMatrix, 20);
   378       float hueRotateValue = aValues[0];
   380       float c = static_cast<float>(cos(hueRotateValue * M_PI / 180));
   381       float s = static_cast<float>(sin(hueRotateValue * M_PI / 180));
   383       aOutMatrix[0] = 0.213f + 0.787f * c - 0.213f * s;
   384       aOutMatrix[1] = 0.715f - 0.715f * c - 0.715f * s;
   385       aOutMatrix[2] = 0.072f - 0.072f * c + 0.928f * s;
   387       aOutMatrix[5] = 0.213f - 0.213f * c + 0.143f * s;
   388       aOutMatrix[6] = 0.715f + 0.285f * c + 0.140f * s;
   389       aOutMatrix[7] = 0.072f - 0.072f * c - 0.283f * s;
   391       aOutMatrix[10] = 0.213f - 0.213f * c - 0.787f * s;
   392       aOutMatrix[11] = 0.715f - 0.715f * c + 0.715f * s;
   393       aOutMatrix[12] = 0.072f + 0.928f * c + 0.072f * s;
   395       break;
   396     }
   398     case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA:
   399     {
   400       PodCopy(aOutMatrix, luminanceToAlphaMatrix, 20);
   401       break;
   402     }
   404     default:
   405       return NS_ERROR_FAILURE;
   407   }
   409   return NS_OK;
   410 }
   412 static void
   413 DisableAllTransfers(FilterNode* aTransferFilterNode)
   414 {
   415   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_R, true);
   416   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_G, true);
   417   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_B, true);
   418   aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_A, true);
   419 }
   421 // Called for one channel at a time.
   422 // This function creates the required FilterNodes on demand and tries to
   423 // merge conversions of different channels into the same FilterNode if
   424 // possible.
   425 // There's a mismatch between the way SVG and the Moz2D API handle transfer
   426 // functions: In SVG, it's possible to specify a different transfer function
   427 // type for each color channel, but in Moz2D, a given transfer function type
   428 // applies to all color channels.
   429 //
   430 //  @param aFunctionAttributes The attributes of the transfer function for this
   431 //                             channel.
   432 //  @param aChannel The color channel that this function applies to, where
   433 //                  0 = red, 1 = green, 2 = blue, 3 = alpha
   434 //  @param aDT The DrawTarget that the FilterNodes should be created for.
   435 //  @param aTableTransfer Existing FilterNode holders (which may still be
   436 //                        null) that the resulting FilterNodes from this
   437 //                        function will be stored in.
   438 //           
   439 static void
   440 ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes,
   441                                          int32_t aChannel,
   442                                          DrawTarget* aDT,
   443                                          RefPtr<FilterNode>& aTableTransfer,
   444                                          RefPtr<FilterNode>& aDiscreteTransfer,
   445                                          RefPtr<FilterNode>& aLinearTransfer,
   446                                          RefPtr<FilterNode>& aGammaTransfer)
   447 {
   448   static const TransferAtts disableAtt[4] = {
   449     ATT_TRANSFER_DISABLE_R,
   450     ATT_TRANSFER_DISABLE_G,
   451     ATT_TRANSFER_DISABLE_B,
   452     ATT_TRANSFER_DISABLE_A
   453   };
   455   RefPtr<FilterNode> filter;
   457   uint32_t type = aFunctionAttributes.GetUint(eComponentTransferFunctionType);
   459   switch (type) {
   460   case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
   461   {
   462     const nsTArray<float>& tableValues =
   463       aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
   464     if (tableValues.Length() < 2)
   465       return;
   467     if (!aTableTransfer) {
   468       aTableTransfer = aDT->CreateFilter(FilterType::TABLE_TRANSFER);
   469       DisableAllTransfers(aTableTransfer);
   470     }
   471     filter = aTableTransfer;
   472     static const TableTransferAtts tableAtt[4] = {
   473       ATT_TABLE_TRANSFER_TABLE_R,
   474       ATT_TABLE_TRANSFER_TABLE_G,
   475       ATT_TABLE_TRANSFER_TABLE_B,
   476       ATT_TABLE_TRANSFER_TABLE_A
   477     };
   478     filter->SetAttribute(disableAtt[aChannel], false);
   479     filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
   480     break;
   481   }
   483   case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
   484   {
   485     const nsTArray<float>& tableValues =
   486       aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
   487     if (tableValues.Length() < 1)
   488       return;
   490     if (!aDiscreteTransfer) {
   491       aDiscreteTransfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   492       DisableAllTransfers(aDiscreteTransfer);
   493     }
   494     filter = aDiscreteTransfer;
   495     static const DiscreteTransferAtts tableAtt[4] = {
   496       ATT_DISCRETE_TRANSFER_TABLE_R,
   497       ATT_DISCRETE_TRANSFER_TABLE_G,
   498       ATT_DISCRETE_TRANSFER_TABLE_B,
   499       ATT_DISCRETE_TRANSFER_TABLE_A
   500     };
   501     filter->SetAttribute(disableAtt[aChannel], false);
   502     filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
   504     break;
   505   }
   507   case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
   508   {
   509     static const LinearTransferAtts slopeAtt[4] = {
   510       ATT_LINEAR_TRANSFER_SLOPE_R,
   511       ATT_LINEAR_TRANSFER_SLOPE_G,
   512       ATT_LINEAR_TRANSFER_SLOPE_B,
   513       ATT_LINEAR_TRANSFER_SLOPE_A
   514     };
   515     static const LinearTransferAtts interceptAtt[4] = {
   516       ATT_LINEAR_TRANSFER_INTERCEPT_R,
   517       ATT_LINEAR_TRANSFER_INTERCEPT_G,
   518       ATT_LINEAR_TRANSFER_INTERCEPT_B,
   519       ATT_LINEAR_TRANSFER_INTERCEPT_A
   520     };
   521     if (!aLinearTransfer) {
   522       aLinearTransfer = aDT->CreateFilter(FilterType::LINEAR_TRANSFER);
   523       DisableAllTransfers(aLinearTransfer);
   524     }
   525     filter = aLinearTransfer;
   526     filter->SetAttribute(disableAtt[aChannel], false);
   527     float slope = aFunctionAttributes.GetFloat(eComponentTransferFunctionSlope);
   528     float intercept = aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
   529     filter->SetAttribute(slopeAtt[aChannel], slope);
   530     filter->SetAttribute(interceptAtt[aChannel], intercept);
   531     break;
   532   }
   534   case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
   535   {
   536     static const GammaTransferAtts amplitudeAtt[4] = {
   537       ATT_GAMMA_TRANSFER_AMPLITUDE_R,
   538       ATT_GAMMA_TRANSFER_AMPLITUDE_G,
   539       ATT_GAMMA_TRANSFER_AMPLITUDE_B,
   540       ATT_GAMMA_TRANSFER_AMPLITUDE_A
   541     };
   542     static const GammaTransferAtts exponentAtt[4] = {
   543       ATT_GAMMA_TRANSFER_EXPONENT_R,
   544       ATT_GAMMA_TRANSFER_EXPONENT_G,
   545       ATT_GAMMA_TRANSFER_EXPONENT_B,
   546       ATT_GAMMA_TRANSFER_EXPONENT_A
   547     };
   548     static const GammaTransferAtts offsetAtt[4] = {
   549       ATT_GAMMA_TRANSFER_OFFSET_R,
   550       ATT_GAMMA_TRANSFER_OFFSET_G,
   551       ATT_GAMMA_TRANSFER_OFFSET_B,
   552       ATT_GAMMA_TRANSFER_OFFSET_A
   553     };
   554     if (!aGammaTransfer) {
   555       aGammaTransfer = aDT->CreateFilter(FilterType::GAMMA_TRANSFER);
   556       DisableAllTransfers(aGammaTransfer);
   557     }
   558     filter = aGammaTransfer;
   559     filter->SetAttribute(disableAtt[aChannel], false);
   560     float amplitude = aFunctionAttributes.GetFloat(eComponentTransferFunctionAmplitude);
   561     float exponent = aFunctionAttributes.GetFloat(eComponentTransferFunctionExponent);
   562     float offset = aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
   563     filter->SetAttribute(amplitudeAtt[aChannel], amplitude);
   564     filter->SetAttribute(exponentAtt[aChannel], exponent);
   565     filter->SetAttribute(offsetAtt[aChannel], offset);
   566     break;
   567   }
   569   case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
   570   default:
   571     break;
   572   }
   573 }
   575 const int32_t kMorphologyMaxRadius = 100000;
   577 // Handle the different primitive description types and create the necessary
   578 // FilterNode(s) for each.
   579 // Returns nullptr for invalid filter primitives. This should be interpreted as
   580 // transparent black by the caller.
   581 // aSourceRegions contains the filter primitive subregions of the source
   582 // primitives; only needed for eTile primitives.
   583 // aInputImages carries additional surfaces that are used by eImage primitives.
   584 static TemporaryRef<FilterNode>
   585 FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescription,
   586                                    DrawTarget* aDT,
   587                                    nsTArray<RefPtr<FilterNode> >& aSources,
   588                                    nsTArray<IntRect>& aSourceRegions,
   589                                    nsTArray<RefPtr<SourceSurface>>& aInputImages)
   590 {
   591   const AttributeMap& atts = aDescription.Attributes();
   592   switch (aDescription.Type()) {
   594     case PrimitiveType::Empty:
   595       return nullptr;
   597     case PrimitiveType::Blend:
   598     {
   599       uint32_t mode = atts.GetUint(eBlendBlendmode);
   600       RefPtr<FilterNode> filter;
   601       if (mode == SVG_FEBLEND_MODE_UNKNOWN) {
   602         return nullptr;
   603       }
   604       if (mode == SVG_FEBLEND_MODE_NORMAL) {
   605         filter = aDT->CreateFilter(FilterType::COMPOSITE);
   606         filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
   607         filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
   608       } else {
   609         filter = aDT->CreateFilter(FilterType::BLEND);
   610         static const uint8_t blendModes[SVG_FEBLEND_MODE_LIGHTEN + 1] = {
   611           0,
   612           0,
   613           BLEND_MODE_MULTIPLY,
   614           BLEND_MODE_SCREEN,
   615           BLEND_MODE_DARKEN,
   616           BLEND_MODE_LIGHTEN
   617         };
   618         filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)blendModes[mode]);
   619         filter->SetInput(IN_BLEND_IN, aSources[0]);
   620         filter->SetInput(IN_BLEND_IN2, aSources[1]);
   621       }
   622       return filter;
   623     }
   625     case PrimitiveType::ColorMatrix:
   626     {
   627       float colorMatrix[20];
   628       uint32_t type = atts.GetUint(eColorMatrixType);
   629       const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
   630       if (NS_FAILED(ComputeColorMatrix(type, values, colorMatrix))) {
   631         return aSources[0];
   632       }
   633       Matrix5x4 matrix(colorMatrix[0], colorMatrix[5], colorMatrix[10],  colorMatrix[15],
   634                        colorMatrix[1], colorMatrix[6], colorMatrix[11],  colorMatrix[16],
   635                        colorMatrix[2], colorMatrix[7], colorMatrix[12],  colorMatrix[17],
   636                        colorMatrix[3], colorMatrix[8], colorMatrix[13],  colorMatrix[18],
   637                        colorMatrix[4], colorMatrix[9], colorMatrix[14],  colorMatrix[19]);
   638       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COLOR_MATRIX);
   639       filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
   640       filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
   641       filter->SetInput(IN_COLOR_MATRIX_IN, aSources[0]);
   642       return filter;
   643     }
   645     case PrimitiveType::Morphology:
   646     {
   647       Size radii = atts.GetSize(eMorphologyRadii);
   648       int32_t rx = radii.width;
   649       int32_t ry = radii.height;
   650       if (rx < 0 || ry < 0) {
   651         // XXX SVGContentUtils::ReportToConsole()
   652         return nullptr;
   653       }
   654       if (rx == 0 && ry == 0) {
   655         return nullptr;
   656       }
   658       // Clamp radii to prevent completely insane values:
   659       rx = std::min(rx, kMorphologyMaxRadius);
   660       ry = std::min(ry, kMorphologyMaxRadius);
   662       MorphologyOperator op = atts.GetUint(eMorphologyOperator) == SVG_OPERATOR_ERODE ?
   663         MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE;
   665       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::MORPHOLOGY);
   666       filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
   667       filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
   668       filter->SetInput(IN_MORPHOLOGY_IN, aSources[0]);
   669       return filter;
   670     }
   672     case PrimitiveType::Flood:
   673     {
   674       Color color = atts.GetColor(eFloodColor);
   675       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
   676       filter->SetAttribute(ATT_FLOOD_COLOR, color);
   677       return filter;
   678     }
   680     case PrimitiveType::Tile:
   681     {
   682       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TILE);
   683       filter->SetAttribute(ATT_TILE_SOURCE_RECT, aSourceRegions[0]);
   684       filter->SetInput(IN_TILE_IN, aSources[0]);
   685       return filter;
   686     }
   688     case PrimitiveType::ComponentTransfer:
   689     {
   690       RefPtr<FilterNode> filters[4]; // one for each FILTER_*_TRANSFER type
   691       static const AttributeName componentFunctionNames[4] = {
   692         eComponentTransferFunctionR,
   693         eComponentTransferFunctionG,
   694         eComponentTransferFunctionB,
   695         eComponentTransferFunctionA
   696       };
   697       for (int32_t i = 0; i < 4; i++) {
   698         AttributeMap functionAttributes =
   699           atts.GetAttributeMap(componentFunctionNames[i]);
   700         ConvertComponentTransferFunctionToFilter(functionAttributes, i, aDT,
   701           filters[0], filters[1], filters[2], filters[3]);
   702       }
   704       // Connect all used filters nodes.
   705       RefPtr<FilterNode> lastFilter = aSources[0];
   706       for (int32_t i = 0; i < 4; i++) {
   707         if (filters[i]) {
   708           filters[i]->SetInput(0, lastFilter);
   709           lastFilter = filters[i];
   710         }
   711       }
   713       return lastFilter;
   714     }
   716     case PrimitiveType::ConvolveMatrix:
   717     {
   718       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
   719       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, atts.GetIntSize(eConvolveMatrixKernelSize));
   720       const nsTArray<float>& matrix = atts.GetFloats(eConvolveMatrixKernelMatrix);
   721       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,
   722                            matrix.Elements(), matrix.Length());
   723       filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR,
   724                            atts.GetFloat(eConvolveMatrixDivisor));
   725       filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS,
   726                            atts.GetFloat(eConvolveMatrixBias));
   727       filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET,
   728                            atts.GetIntPoint(eConvolveMatrixTarget));
   729       filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT,
   730                            aSourceRegions[0]);
   731       uint32_t edgeMode = atts.GetUint(eConvolveMatrixEdgeMode);
   732       static const uint8_t edgeModes[SVG_EDGEMODE_NONE+1] = {
   733         EDGE_MODE_NONE,      // SVG_EDGEMODE_UNKNOWN
   734         EDGE_MODE_DUPLICATE, // SVG_EDGEMODE_DUPLICATE
   735         EDGE_MODE_WRAP,      // SVG_EDGEMODE_WRAP
   736         EDGE_MODE_NONE       // SVG_EDGEMODE_NONE
   737       };
   738       filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)edgeModes[edgeMode]);
   739       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH,
   740                            atts.GetSize(eConvolveMatrixKernelUnitLength));
   741       filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA,
   742                            atts.GetBool(eConvolveMatrixPreserveAlpha));
   743       filter->SetInput(IN_CONVOLVE_MATRIX_IN, aSources[0]);
   744       return filter;
   745     }
   747     case PrimitiveType::Offset:
   748     {
   749       return FilterWrappers::Offset(aDT, aSources[0],
   750                                     atts.GetIntPoint(eOffsetOffset));
   751     }
   753     case PrimitiveType::DisplacementMap:
   754     {
   755       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
   756       filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE,
   757                            atts.GetFloat(eDisplacementMapScale));
   758       static const uint8_t channel[SVG_CHANNEL_A+1] = {
   759         COLOR_CHANNEL_R, // SVG_CHANNEL_UNKNOWN
   760         COLOR_CHANNEL_R, // SVG_CHANNEL_R
   761         COLOR_CHANNEL_G, // SVG_CHANNEL_G
   762         COLOR_CHANNEL_B, // SVG_CHANNEL_B
   763         COLOR_CHANNEL_A  // SVG_CHANNEL_A
   764       };
   765       filter->SetAttribute(ATT_DISPLACEMENT_MAP_X_CHANNEL,
   766                            (uint32_t)channel[atts.GetUint(eDisplacementMapXChannel)]);
   767       filter->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL,
   768                            (uint32_t)channel[atts.GetUint(eDisplacementMapYChannel)]);
   769       filter->SetInput(IN_DISPLACEMENT_MAP_IN, aSources[0]);
   770       filter->SetInput(IN_DISPLACEMENT_MAP_IN2, aSources[1]);
   771       return filter;
   772     }
   774     case PrimitiveType::Turbulence:
   775     {
   776       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TURBULENCE);
   777       filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
   778                            atts.GetSize(eTurbulenceBaseFrequency));
   779       filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES,
   780                            atts.GetUint(eTurbulenceNumOctaves));
   781       filter->SetAttribute(ATT_TURBULENCE_STITCHABLE,
   782                            atts.GetBool(eTurbulenceStitchable));
   783       filter->SetAttribute(ATT_TURBULENCE_SEED,
   784                            (uint32_t)atts.GetFloat(eTurbulenceSeed));
   785       static const uint8_t type[SVG_TURBULENCE_TYPE_TURBULENCE+1] = {
   786         TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_UNKNOWN
   787         TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_FRACTALNOISE
   788         TURBULENCE_TYPE_TURBULENCE     // SVG_TURBULENCE_TYPE_TURBULENCE
   789       };
   790       filter->SetAttribute(ATT_TURBULENCE_TYPE,
   791                            (uint32_t)type[atts.GetUint(eTurbulenceType)]);
   792       filter->SetAttribute(ATT_TURBULENCE_RECT,
   793                            aDescription.PrimitiveSubregion() - atts.GetIntPoint(eTurbulenceOffset));
   794       return FilterWrappers::Offset(aDT, filter, atts.GetIntPoint(eTurbulenceOffset));
   795     }
   797     case PrimitiveType::Composite:
   798     {
   799       RefPtr<FilterNode> filter;
   800       uint32_t op = atts.GetUint(eCompositeOperator);
   801       if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
   802         filter = aDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
   803         const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
   804         filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS,
   805                              coefficients.Elements(), coefficients.Length());
   806         filter->SetInput(IN_ARITHMETIC_COMBINE_IN, aSources[0]);
   807         filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, aSources[1]);
   808       } else {
   809         filter = aDT->CreateFilter(FilterType::COMPOSITE);
   810         static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
   811           COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
   812           COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
   813           COMPOSITE_OPERATOR_IN,   // SVG_FECOMPOSITE_OPERATOR_IN
   814           COMPOSITE_OPERATOR_OUT,  // SVG_FECOMPOSITE_OPERATOR_OUT
   815           COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
   816           COMPOSITE_OPERATOR_XOR   // SVG_FECOMPOSITE_OPERATOR_XOR
   817         };
   818         filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)operators[op]);
   819         filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
   820         filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
   821       }
   822       return filter;
   823     }
   825     case PrimitiveType::Merge:
   826     {
   827       if (aSources.Length() == 0) {
   828         return nullptr;
   829       }
   830       if (aSources.Length() == 1) {
   831         return aSources[0];
   832       }
   833       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
   834       filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
   835       for (size_t i = 0; i < aSources.Length(); i++) {
   836         filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
   837       }
   838       return filter;
   839     }
   841     case PrimitiveType::GaussianBlur:
   842     {
   843       return FilterWrappers::GaussianBlur(aDT, aSources[0],
   844                                           atts.GetSize(eGaussianBlurStdDeviation));
   845     }
   847     case PrimitiveType::DropShadow:
   848     {
   849       RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(aDT, aSources[0]);
   850       RefPtr<FilterNode> blur = FilterWrappers::GaussianBlur(aDT, alpha,
   851                                   atts.GetSize(eDropShadowStdDeviation));
   852       RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
   853                                         atts.GetIntPoint(eDropShadowOffset));
   854       RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
   855       Color color = atts.GetColor(eDropShadowColor);
   856       if (aDescription.InputColorSpace(0) == ColorSpace::LinearRGB) {
   857         color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
   858                       gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
   859                       gsRGBToLinearRGBMap[uint8_t(color.b * 255)],
   860                       color.a);
   861       }
   862       flood->SetAttribute(ATT_FLOOD_COLOR, color);
   864       RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
   865       composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
   866       composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
   867       composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
   869       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
   870       filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
   871       filter->SetInput(IN_COMPOSITE_IN_START, composite);
   872       filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
   873       return filter;
   874     }
   876     case PrimitiveType::DiffuseLighting:
   877     case PrimitiveType::SpecularLighting:
   878     {
   879       bool isSpecular =
   880         aDescription.Type() == PrimitiveType::SpecularLighting;
   882       AttributeMap lightAttributes = atts.GetAttributeMap(eLightingLight);
   884       if (lightAttributes.GetUint(eLightType) == eLightTypeNone) {
   885         return nullptr;
   886       }
   888       enum { POINT = 0, SPOT, DISTANT } lightType = POINT;
   890       switch (lightAttributes.GetUint(eLightType)) {
   891         case eLightTypePoint:   lightType = POINT;   break;
   892         case eLightTypeSpot:    lightType = SPOT;    break;
   893         case eLightTypeDistant: lightType = DISTANT; break;
   894       }
   896       static const FilterType filterType[2][DISTANT+1] = {
   897         { FilterType::POINT_DIFFUSE, FilterType::SPOT_DIFFUSE, FilterType::DISTANT_DIFFUSE },
   898         { FilterType::POINT_SPECULAR, FilterType::SPOT_SPECULAR, FilterType::DISTANT_SPECULAR }
   899       };
   900       RefPtr<FilterNode> filter =
   901         aDT->CreateFilter(filterType[isSpecular][lightType]);
   903       filter->SetAttribute(ATT_LIGHTING_COLOR,
   904                            atts.GetColor(eLightingColor));
   905       filter->SetAttribute(ATT_LIGHTING_SURFACE_SCALE,
   906                            atts.GetFloat(eLightingSurfaceScale));
   907       filter->SetAttribute(ATT_LIGHTING_KERNEL_UNIT_LENGTH,
   908                            atts.GetSize(eLightingKernelUnitLength));
   910       if (isSpecular) {
   911         filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
   912                              atts.GetFloat(eSpecularLightingSpecularConstant));
   913         filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT,
   914                              atts.GetFloat(eSpecularLightingSpecularExponent));
   915       } else {
   916         filter->SetAttribute(ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT,
   917                              atts.GetFloat(eDiffuseLightingDiffuseConstant));
   918       }
   920       switch (lightType) {
   921         case POINT:
   922           filter->SetAttribute(ATT_POINT_LIGHT_POSITION,
   923                                lightAttributes.GetPoint3D(ePointLightPosition));
   924           break;
   925         case SPOT:
   926           filter->SetAttribute(ATT_SPOT_LIGHT_POSITION,
   927                                lightAttributes.GetPoint3D(eSpotLightPosition));
   928           filter->SetAttribute(ATT_SPOT_LIGHT_POINTS_AT,
   929                                lightAttributes.GetPoint3D(eSpotLightPointsAt));
   930           filter->SetAttribute(ATT_SPOT_LIGHT_FOCUS,
   931                                lightAttributes.GetFloat(eSpotLightFocus));
   932           filter->SetAttribute(ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,
   933                                lightAttributes.GetFloat(eSpotLightLimitingConeAngle));
   934           break;
   935         case DISTANT:
   936           filter->SetAttribute(ATT_DISTANT_LIGHT_AZIMUTH,
   937                                lightAttributes.GetFloat(eDistantLightAzimuth));
   938           filter->SetAttribute(ATT_DISTANT_LIGHT_ELEVATION,
   939                                lightAttributes.GetFloat(eDistantLightElevation));
   940           break;
   941       }
   943       filter->SetInput(IN_LIGHTING_IN, aSources[0]);
   945       return filter;
   946     }
   948     case PrimitiveType::Image:
   949     {
   950       Matrix TM = atts.GetMatrix(eImageTransform);
   951       if (!TM.Determinant()) {
   952         return nullptr;
   953       }
   955       // Pull the image from the additional image list using the index that's
   956       // stored in the primitive description.
   957       RefPtr<SourceSurface> inputImage =
   958         aInputImages[atts.GetUint(eImageInputIndex)];
   960       RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
   961       transform->SetInput(IN_TRANSFORM_IN, inputImage);
   962       transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
   963       transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
   964       return transform;
   965     }
   967     default:
   968       return nullptr;
   969   }
   970 }
   972 template<typename T>
   973 static const T&
   974 ElementForIndex(int32_t aIndex,
   975                 const nsTArray<T>& aPrimitiveElements,
   976                 const T& aSourceGraphicElement,
   977                 const T& aFillPaintElement,
   978                 const T& aStrokePaintElement)
   979 {
   980   switch (aIndex) {
   981     case FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic:
   982     case FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha:
   983       return aSourceGraphicElement;
   984     case FilterPrimitiveDescription::kPrimitiveIndexFillPaint:
   985       return aFillPaintElement;
   986     case FilterPrimitiveDescription::kPrimitiveIndexStrokePaint:
   987       return aStrokePaintElement;
   988     default:
   989       MOZ_ASSERT(aIndex >= 0, "bad index");
   990       return aPrimitiveElements[aIndex];
   991   }
   992 }
   994 static AlphaModel
   995 InputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
   996                             int32_t aInputIndex,
   997                             AlphaModel aOriginalAlphaModel)
   998 {
   999   switch (aDescr.Type()) {
  1000     case PrimitiveType::Tile:
  1001     case PrimitiveType::Offset:
  1002       return aOriginalAlphaModel;
  1004     case PrimitiveType::ColorMatrix:
  1005     case PrimitiveType::ComponentTransfer:
  1006       return AlphaModel::Unpremultiplied;
  1008     case PrimitiveType::DisplacementMap:
  1009       return aInputIndex == 0 ?
  1010         AlphaModel::Premultiplied : AlphaModel::Unpremultiplied;
  1012     case PrimitiveType::ConvolveMatrix:
  1013       return aDescr.Attributes().GetBool(eConvolveMatrixPreserveAlpha) ?
  1014         AlphaModel::Unpremultiplied : AlphaModel::Premultiplied;
  1016     default:
  1017       return AlphaModel::Premultiplied;
  1021 static AlphaModel
  1022 OutputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
  1023                              const nsTArray<AlphaModel>& aInputAlphaModels)
  1025   if (aInputAlphaModels.Length()) {
  1026     // For filters with inputs, the output is premultiplied if and only if the
  1027     // first input is premultiplied.
  1028     return InputAlphaModelForPrimitive(aDescr, 0, aInputAlphaModels[0]);
  1031   // All filters without inputs produce premultiplied alpha.
  1032   return AlphaModel::Premultiplied;
  1035 // Returns the output FilterNode, in premultiplied sRGB space.
  1036 static TemporaryRef<FilterNode>
  1037 FilterNodeGraphFromDescription(DrawTarget* aDT,
  1038                                const FilterDescription& aFilter,
  1039                                const Rect& aResultNeededRect,
  1040                                SourceSurface* aSourceGraphic,
  1041                                const IntRect& aSourceGraphicRect,
  1042                                SourceSurface* aFillPaint,
  1043                                const IntRect& aFillPaintRect,
  1044                                SourceSurface* aStrokePaint,
  1045                                const IntRect& aStrokePaintRect,
  1046                                nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
  1048   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1049   const IntRect& filterSpaceBounds = aFilter.mFilterSpaceBounds;
  1051   Rect resultNeededRect(aResultNeededRect);
  1052   resultNeededRect.RoundOut();
  1054   RefPtr<FilterCachedColorModels> sourceFilters[4];
  1055   nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters;
  1057   for (size_t i = 0; i < primitives.Length(); ++i) {
  1058     const FilterPrimitiveDescription& descr = primitives[i];
  1060     nsTArray<RefPtr<FilterNode> > inputFilterNodes;
  1061     nsTArray<IntRect> inputSourceRects;
  1062     nsTArray<AlphaModel> inputAlphaModels;
  1064     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1066       int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1067       if (inputIndex < 0) {
  1068         inputSourceRects.AppendElement(filterSpaceBounds);
  1069       } else {
  1070         inputSourceRects.AppendElement(filterSpaceBounds.Intersect(
  1071           primitives[inputIndex].PrimitiveSubregion()));
  1074       RefPtr<FilterCachedColorModels> inputFilter;
  1075       if (inputIndex >= 0) {
  1076         MOZ_ASSERT(inputIndex < (int64_t)primitiveFilters.Length(), "out-of-bounds input index!");
  1077         inputFilter = primitiveFilters[inputIndex];
  1078         MOZ_ASSERT(inputFilter, "Referred to input filter that comes after the current one?");
  1079       } else {
  1080         int32_t sourceIndex = -inputIndex - 1;
  1081         MOZ_ASSERT(sourceIndex >= 0, "invalid source index");
  1082         MOZ_ASSERT(sourceIndex < 4, "invalid source index");
  1083         inputFilter = sourceFilters[sourceIndex];
  1084         if (!inputFilter) {
  1085           RefPtr<FilterNode> sourceFilterNode;
  1087           nsTArray<SourceSurface*> primitiveSurfaces;
  1088           nsTArray<IntRect> primitiveSurfaceRects;
  1089           RefPtr<SourceSurface> surf =
  1090             ElementForIndex(inputIndex, primitiveSurfaces,
  1091                             aSourceGraphic, aFillPaint, aStrokePaint);
  1092           IntRect surfaceRect =
  1093             ElementForIndex(inputIndex, primitiveSurfaceRects,
  1094                             aSourceGraphicRect, aFillPaintRect, aStrokePaintRect);
  1095           if (surf) {
  1096             IntPoint offset = surfaceRect.TopLeft();
  1097             sourceFilterNode = FilterWrappers::ForSurface(aDT, surf, offset);
  1099             if (inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) {
  1100               sourceFilterNode = FilterWrappers::ToAlpha(aDT, sourceFilterNode);
  1104           inputFilter = new FilterCachedColorModels(aDT, sourceFilterNode,
  1105                                                     ColorModel::PremulSRGB());
  1106           sourceFilters[sourceIndex] = inputFilter;
  1109       MOZ_ASSERT(inputFilter);
  1111       AlphaModel inputAlphaModel =
  1112         InputAlphaModelForPrimitive(descr, j, inputFilter->OriginalAlphaModel());
  1113       inputAlphaModels.AppendElement(inputAlphaModel);
  1114       ColorModel inputColorModel(descr.InputColorSpace(j), inputAlphaModel);
  1115       inputFilterNodes.AppendElement(inputFilter->ForColorModel(inputColorModel));
  1118     RefPtr<FilterNode> primitiveFilterNode =
  1119       FilterNodeFromPrimitiveDescription(descr, aDT, inputFilterNodes,
  1120                                          inputSourceRects, aAdditionalImages);
  1122     if (primitiveFilterNode) {
  1123       IntRect cropRect = filterSpaceBounds.Intersect(descr.PrimitiveSubregion());
  1124       primitiveFilterNode = FilterWrappers::Crop(aDT, primitiveFilterNode, cropRect);
  1127     ColorModel outputColorModel(descr.OutputColorSpace(),
  1128       OutputAlphaModelForPrimitive(descr, inputAlphaModels));
  1129     RefPtr<FilterCachedColorModels> primitiveFilter =
  1130       new FilterCachedColorModels(aDT, primitiveFilterNode, outputColorModel);
  1132     primitiveFilters.AppendElement(primitiveFilter);
  1135   return primitiveFilters.LastElement()->ForColorModel(ColorModel::PremulSRGB());
  1138 // FilterSupport
  1140 void
  1141 FilterSupport::RenderFilterDescription(DrawTarget* aDT,
  1142                                        const FilterDescription& aFilter,
  1143                                        const Rect& aRenderRect,
  1144                                        SourceSurface* aSourceGraphic,
  1145                                        const IntRect& aSourceGraphicRect,
  1146                                        SourceSurface* aFillPaint,
  1147                                        const IntRect& aFillPaintRect,
  1148                                        SourceSurface* aStrokePaint,
  1149                                        const IntRect& aStrokePaintRect,
  1150                                        nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
  1152   RefPtr<FilterNode> resultFilter =
  1153     FilterNodeGraphFromDescription(aDT, aFilter, aRenderRect,
  1154                                    aSourceGraphic, aSourceGraphicRect, aFillPaint, aFillPaintRect,
  1155                                    aStrokePaint, aStrokePaintRect, aAdditionalImages);
  1157   aDT->DrawFilter(resultFilter, aRenderRect, Point(0, 0));
  1160 static nsIntRegion
  1161 UnionOfRegions(const nsTArray<nsIntRegion>& aRegions)
  1163   nsIntRegion result;
  1164   for (size_t i = 0; i < aRegions.Length(); i++) {
  1165     result.Or(result, aRegions[i]);
  1167   return result;
  1170 static int32_t
  1171 InflateSizeForBlurStdDev(float aStdDev)
  1173   double size = std::min(aStdDev, kMaxStdDeviation) * (3 * sqrt(2 * M_PI) / 4) * 1.5;
  1174   return uint32_t(floor(size + 0.5));
  1177 static nsIntRegion
  1178 ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
  1179                                const nsTArray<nsIntRegion>& aInputChangeRegions)
  1181   const AttributeMap& atts = aDescription.Attributes();
  1182   switch (aDescription.Type()) {
  1184     case PrimitiveType::Empty:
  1185     case PrimitiveType::Flood:
  1186     case PrimitiveType::Turbulence:
  1187     case PrimitiveType::Image:
  1188       return nsIntRegion();
  1190     case PrimitiveType::Blend:
  1191     case PrimitiveType::Composite:
  1192     case PrimitiveType::Merge:
  1193       return UnionOfRegions(aInputChangeRegions);
  1195     case PrimitiveType::ColorMatrix:
  1196     case PrimitiveType::ComponentTransfer:
  1197       return aInputChangeRegions[0];
  1199     case PrimitiveType::Morphology:
  1201       Size radii = atts.GetSize(eMorphologyRadii);
  1202       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
  1203       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
  1204       return aInputChangeRegions[0].Inflated(nsIntMargin(ry, rx, ry, rx));
  1207     case PrimitiveType::Tile:
  1208       return ThebesIntRect(aDescription.PrimitiveSubregion());
  1210     case PrimitiveType::ConvolveMatrix:
  1212       Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
  1213       IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
  1214       IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
  1215       nsIntMargin m(ceil(kernelUnitLength.width * (target.x)),
  1216                     ceil(kernelUnitLength.height * (target.y)),
  1217                     ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
  1218                     ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)));
  1219       return aInputChangeRegions[0].Inflated(m);
  1222     case PrimitiveType::Offset:
  1224       IntPoint offset = atts.GetIntPoint(eOffsetOffset);
  1225       return aInputChangeRegions[0].MovedBy(offset.x, offset.y);
  1228     case PrimitiveType::DisplacementMap:
  1230       int32_t scale = ceil(abs(atts.GetFloat(eDisplacementMapScale)));
  1231       return aInputChangeRegions[0].Inflated(nsIntMargin(scale, scale, scale, scale));
  1234     case PrimitiveType::GaussianBlur:
  1236       Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
  1237       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1238       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1239       return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
  1242     case PrimitiveType::DropShadow:
  1244       IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
  1245       nsIntRegion offsetRegion = aInputChangeRegions[0].MovedBy(offset.x, offset.y);
  1246       Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
  1247       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1248       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1249       nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1250       blurRegion.Or(blurRegion, aInputChangeRegions[0]);
  1251       return blurRegion;
  1254     case PrimitiveType::DiffuseLighting:
  1255     case PrimitiveType::SpecularLighting:
  1257       Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
  1258       int32_t dx = ceil(kernelUnitLength.width);
  1259       int32_t dy = ceil(kernelUnitLength.height);
  1260       return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
  1263     default:
  1264       return nsIntRegion();
  1268 /* static */ nsIntRegion
  1269 FilterSupport::ComputeResultChangeRegion(const FilterDescription& aFilter,
  1270                                          const nsIntRegion& aSourceGraphicChange,
  1271                                          const nsIntRegion& aFillPaintChange,
  1272                                          const nsIntRegion& aStrokePaintChange)
  1274   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1275   nsTArray<nsIntRegion> resultChangeRegions;
  1277   for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
  1278     const FilterPrimitiveDescription& descr = primitives[i];
  1280     nsTArray<nsIntRegion> inputChangeRegions;
  1281     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1282       int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1283       MOZ_ASSERT(inputIndex < i, "bad input index");
  1284       nsIntRegion inputChangeRegion =
  1285         ElementForIndex(inputIndex, resultChangeRegions,
  1286                         aSourceGraphicChange, aFillPaintChange,
  1287                         aStrokePaintChange);
  1288       inputChangeRegions.AppendElement(inputChangeRegion);
  1290     nsIntRegion changeRegion =
  1291       ResultChangeRegionForPrimitive(descr, inputChangeRegions);
  1292     IntRect cropRect =
  1293       descr.PrimitiveSubregion().Intersect(aFilter.mFilterSpaceBounds);
  1294     changeRegion.And(changeRegion, ThebesIntRect(cropRect));
  1295     resultChangeRegions.AppendElement(changeRegion);
  1298   return resultChangeRegions[resultChangeRegions.Length() - 1];
  1301 static nsIntRegion
  1302 PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
  1303                               const nsTArray<nsIntRegion>& aInputExtents)
  1305   const AttributeMap& atts = aDescription.Attributes();
  1306   switch (aDescription.Type()) {
  1308     case PrimitiveType::Empty:
  1309       return nsIntRect();
  1311     case PrimitiveType::Composite:
  1313       uint32_t op = atts.GetUint(eCompositeOperator);
  1314       if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
  1315         // The arithmetic composite primitive can draw outside the bounding
  1316         // box of its source images.
  1317         const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
  1318         MOZ_ASSERT(coefficients.Length() == 4);
  1320         // The calculation is:
  1321         // r = c[0] * in[0] * in[1] + c[1] * in[0] + c[2] * in[1] + c[3]
  1322         nsIntRegion region;
  1323         if (coefficients[0] > 0.0f) {
  1324           region = aInputExtents[0].Intersect(aInputExtents[1]);
  1326         if (coefficients[1] > 0.0f) {
  1327           region.Or(region, aInputExtents[0]);
  1329         if (coefficients[2] > 0.0f) {
  1330           region.Or(region, aInputExtents[1]);
  1332         if (coefficients[3] > 0.0f) {
  1333           region = ThebesIntRect(aDescription.PrimitiveSubregion());
  1335         return region;
  1337       if (op == SVG_FECOMPOSITE_OPERATOR_IN) {
  1338         return aInputExtents[0].Intersect(aInputExtents[1]);
  1340       return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
  1343     case PrimitiveType::Flood:
  1345       if (atts.GetColor(eFloodColor).a == 0.0f) {
  1346         return nsIntRect();
  1348       return ThebesIntRect(aDescription.PrimitiveSubregion());
  1351     case PrimitiveType::Turbulence:
  1352     case PrimitiveType::Image:
  1354       return ThebesIntRect(aDescription.PrimitiveSubregion());
  1357     case PrimitiveType::Morphology:
  1359       uint32_t op = atts.GetUint(eMorphologyOperator);
  1360       if (op == SVG_OPERATOR_ERODE) {
  1361         return aInputExtents[0];
  1363       Size radii = atts.GetSize(eMorphologyRadii);
  1364       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
  1365       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
  1366       return aInputExtents[0].Inflated(nsIntMargin(ry, rx, ry, rx));
  1369     default:
  1370       return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
  1374 /* static */ nsIntRegion
  1375 FilterSupport::ComputePostFilterExtents(const FilterDescription& aFilter,
  1376                                         const nsIntRegion& aSourceGraphicExtents)
  1378   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1379   nsIntRegion filterSpace = ThebesIntRect(aFilter.mFilterSpaceBounds);
  1380   nsTArray<nsIntRegion> postFilterExtents;
  1382   for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
  1383     const FilterPrimitiveDescription& descr = primitives[i];
  1385     nsTArray<nsIntRegion> inputExtents;
  1386     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1387       int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1388       MOZ_ASSERT(inputIndex < i, "bad input index");
  1389       nsIntRegion inputExtent =
  1390         ElementForIndex(inputIndex, postFilterExtents,
  1391                         aSourceGraphicExtents, filterSpace, filterSpace);
  1392       inputExtents.AppendElement(inputExtent);
  1394     nsIntRegion extent = PostFilterExtentsForPrimitive(descr, inputExtents);
  1395     IntRect cropRect =
  1396       descr.PrimitiveSubregion().Intersect(aFilter.mFilterSpaceBounds);
  1397     extent.And(extent, ThebesIntRect(cropRect));
  1398     postFilterExtents.AppendElement(extent);
  1401   return postFilterExtents[postFilterExtents.Length() - 1];
  1404 static nsIntRegion
  1405 SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
  1406                                const nsIntRegion& aResultNeededRegion,
  1407                                int32_t aInputIndex)
  1409   const AttributeMap& atts = aDescription.Attributes();
  1410   switch (aDescription.Type()) {
  1412     case PrimitiveType::Flood:
  1413     case PrimitiveType::Turbulence:
  1414     case PrimitiveType::Image:
  1415       MOZ_CRASH("this shouldn't be called for filters without inputs");
  1416       return nsIntRegion();
  1418     case PrimitiveType::Empty:
  1419       return nsIntRegion();
  1421     case PrimitiveType::Blend:
  1422     case PrimitiveType::Composite:
  1423     case PrimitiveType::Merge:
  1424     case PrimitiveType::ColorMatrix:
  1425     case PrimitiveType::ComponentTransfer:
  1426       return aResultNeededRegion;
  1428     case PrimitiveType::Morphology:
  1430       Size radii = atts.GetSize(eMorphologyRadii);
  1431       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
  1432       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
  1433       return aResultNeededRegion.Inflated(nsIntMargin(ry, rx, ry, rx));
  1436     case PrimitiveType::Tile:
  1437       return nsIntRect(INT32_MIN/2, INT32_MIN/2, INT32_MAX, INT32_MAX);
  1439     case PrimitiveType::ConvolveMatrix:
  1441       Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
  1442       IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
  1443       IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
  1444       nsIntMargin m(ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
  1445                     ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)),
  1446                     ceil(kernelUnitLength.width * (target.x)),
  1447                     ceil(kernelUnitLength.height * (target.y)));
  1448       return aResultNeededRegion.Inflated(m);
  1451     case PrimitiveType::Offset:
  1453       IntPoint offset = atts.GetIntPoint(eOffsetOffset);
  1454       return aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
  1457     case PrimitiveType::DisplacementMap:
  1459       if (aInputIndex == 1) {
  1460         return aResultNeededRegion;
  1462       int32_t scale = ceil(abs(atts.GetFloat(eDisplacementMapScale)));
  1463       return aResultNeededRegion.Inflated(nsIntMargin(scale, scale, scale, scale));
  1466     case PrimitiveType::GaussianBlur:
  1468       Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
  1469       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1470       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1471       return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1474     case PrimitiveType::DropShadow:
  1476       IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
  1477       nsIntRegion offsetRegion =
  1478         aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
  1479       Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
  1480       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1481       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1482       nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1483       blurRegion.Or(blurRegion, aResultNeededRegion);
  1484       return blurRegion;
  1487     case PrimitiveType::DiffuseLighting:
  1488     case PrimitiveType::SpecularLighting:
  1490       Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
  1491       int32_t dx = ceil(kernelUnitLength.width);
  1492       int32_t dy = ceil(kernelUnitLength.height);
  1493       return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1496     default:
  1497       return nsIntRegion();
  1502 /* static */ void
  1503 FilterSupport::ComputeSourceNeededRegions(const FilterDescription& aFilter,
  1504                                           const nsIntRegion& aResultNeededRegion,
  1505                                           nsIntRegion& aSourceGraphicNeededRegion,
  1506                                           nsIntRegion& aFillPaintNeededRegion,
  1507                                           nsIntRegion& aStrokePaintNeededRegion)
  1509   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1510   nsTArray<nsIntRegion> primitiveNeededRegions;
  1511   primitiveNeededRegions.AppendElements(primitives.Length());
  1513   primitiveNeededRegions[primitives.Length() - 1] = aResultNeededRegion;
  1515   for (int32_t i = primitives.Length() - 1; i >= 0; --i) {
  1516     const FilterPrimitiveDescription& descr = primitives[i];
  1517     nsIntRegion neededRegion = primitiveNeededRegions[i];
  1518     neededRegion.And(neededRegion, ThebesIntRect(descr.PrimitiveSubregion()));
  1520     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1521       int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1522       MOZ_ASSERT(inputIndex < i, "bad input index");
  1523       nsIntRegion* inputNeededRegion = const_cast<nsIntRegion*>(
  1524         &ElementForIndex(inputIndex, primitiveNeededRegions,
  1525                          aSourceGraphicNeededRegion,
  1526                          aFillPaintNeededRegion, aStrokePaintNeededRegion));
  1527       inputNeededRegion->Or(*inputNeededRegion,
  1528         SourceNeededRegionForPrimitive(descr, neededRegion, j));
  1532   aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
  1533                                  ThebesIntRect(aFilter.mFilterSpaceBounds));
  1536 // FilterPrimitiveDescription
  1538 FilterPrimitiveDescription::FilterPrimitiveDescription()
  1539  : mType(PrimitiveType::Empty)
  1540  , mOutputColorSpace(ColorSpace::SRGB)
  1541  , mIsTainted(false)
  1545 FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType)
  1546  : mType(aType)
  1547  , mOutputColorSpace(ColorSpace::SRGB)
  1548  , mIsTainted(false)
  1552 FilterPrimitiveDescription::FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther)
  1553  : mType(aOther.mType)
  1554  , mAttributes(aOther.mAttributes)
  1555  , mInputPrimitives(aOther.mInputPrimitives)
  1556  , mFilterPrimitiveSubregion(aOther.mFilterPrimitiveSubregion)
  1557  , mInputColorSpaces(aOther.mInputColorSpaces)
  1558  , mOutputColorSpace(aOther.mOutputColorSpace)
  1559  , mIsTainted(aOther.mIsTainted)
  1563 FilterPrimitiveDescription&
  1564 FilterPrimitiveDescription::operator=(const FilterPrimitiveDescription& aOther)
  1566   if (this != &aOther) {
  1567     mType = aOther.mType;
  1568     mAttributes = aOther.mAttributes;
  1569     mInputPrimitives = aOther.mInputPrimitives;
  1570     mFilterPrimitiveSubregion = aOther.mFilterPrimitiveSubregion;
  1571     mInputColorSpaces = aOther.mInputColorSpaces;
  1572     mOutputColorSpace = aOther.mOutputColorSpace;
  1573     mIsTainted = aOther.mIsTainted;
  1575   return *this;
  1578 bool
  1579 FilterPrimitiveDescription::operator==(const FilterPrimitiveDescription& aOther) const
  1581   return mType == aOther.mType &&
  1582     mFilterPrimitiveSubregion.IsEqualInterior(aOther.mFilterPrimitiveSubregion) &&
  1583     mOutputColorSpace == aOther.mOutputColorSpace &&
  1584     mIsTainted == aOther.mIsTainted &&
  1585     mInputPrimitives == aOther.mInputPrimitives &&
  1586     mInputColorSpaces == aOther.mInputColorSpaces &&
  1587     mAttributes == aOther.mAttributes;
  1590 // FilterDescription
  1592 bool
  1593 FilterDescription::operator==(const FilterDescription& aOther) const
  1595   return mFilterSpaceBounds.IsEqualInterior(aOther.mFilterSpaceBounds) &&
  1596     mPrimitives == aOther.mPrimitives;
  1599 // AttributeMap
  1601 // A class that wraps different types for easy storage in a hashtable. Only
  1602 // used by AttributeMap.
  1603 struct FilterAttribute {
  1604   FilterAttribute(const FilterAttribute& aOther);
  1605   ~FilterAttribute();
  1607   bool operator==(const FilterAttribute& aOther) const;
  1608   bool operator!=(const FilterAttribute& aOther) const
  1610     return !(*this == aOther);
  1613   AttributeType Type() const { return mType; }
  1615 #define MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(type, typeLabel)   \
  1616   FilterAttribute(type aValue)                                 \
  1617    : mType(AttributeType::e##typeLabel), m##typeLabel(aValue)  \
  1618   {}                                                           \
  1619   type As##typeLabel() {                                       \
  1620     MOZ_ASSERT(mType == AttributeType::e##typeLabel);          \
  1621     return m##typeLabel;                                       \
  1624 #define MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(className)         \
  1625   FilterAttribute(const className& aValue)                     \
  1626    : mType(AttributeType::e##className), m##className(new className(aValue)) \
  1627   {}                                                           \
  1628   className As##className() {                                  \
  1629     MOZ_ASSERT(mType == AttributeType::e##className);          \
  1630     return *m##className;                                      \
  1633   MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(bool, Bool)
  1634   MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(uint32_t, Uint)
  1635   MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(float, Float)
  1636   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Size)
  1637   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntSize)
  1638   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntPoint)
  1639   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix)
  1640   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix5x4)
  1641   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Point3D)
  1642   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Color)
  1643   MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(AttributeMap)
  1645 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC
  1646 #undef MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS
  1648   FilterAttribute(const float* aValue, uint32_t aLength)
  1649    : mType(AttributeType::eFloats)
  1651     mFloats = new nsTArray<float>();
  1652     mFloats->AppendElements(aValue, aLength);
  1655   const nsTArray<float>& AsFloats() const {
  1656     MOZ_ASSERT(mType == AttributeType::eFloats);
  1657     return *mFloats;
  1660 private:
  1661   const AttributeType mType;
  1663   union {
  1664     bool mBool;
  1665     uint32_t mUint;
  1666     float mFloat;
  1667     Size* mSize;
  1668     IntSize* mIntSize;
  1669     IntPoint* mIntPoint;
  1670     Matrix* mMatrix;
  1671     Matrix5x4* mMatrix5x4;
  1672     Point3D* mPoint3D;
  1673     Color* mColor;
  1674     AttributeMap* mAttributeMap;
  1675     nsTArray<float>* mFloats;
  1676   };
  1677 };
  1679 FilterAttribute::FilterAttribute(const FilterAttribute& aOther)
  1680  : mType(aOther.mType)
  1682   switch (mType) {
  1683     case AttributeType::eBool:
  1684       mBool = aOther.mBool;
  1685       break;
  1686     case AttributeType::eUint:
  1687       mUint = aOther.mUint;
  1688       break;
  1689     case AttributeType::eFloat:
  1690       mFloat = aOther.mFloat;
  1691       break;
  1693 #define HANDLE_CLASS(className)                            \
  1694     case AttributeType::e##className:                      \
  1695       m##className = new className(*aOther.m##className);  \
  1696       break;
  1698     HANDLE_CLASS(Size)
  1699     HANDLE_CLASS(IntSize)
  1700     HANDLE_CLASS(IntPoint)
  1701     HANDLE_CLASS(Matrix)
  1702     HANDLE_CLASS(Matrix5x4)
  1703     HANDLE_CLASS(Point3D)
  1704     HANDLE_CLASS(Color)
  1705     HANDLE_CLASS(AttributeMap)
  1707 #undef HANDLE_CLASS
  1709     case AttributeType::eFloats:
  1710       mFloats = new nsTArray<float>(*aOther.mFloats);
  1711       break;
  1712     case AttributeType::Max:
  1713       break;
  1717 FilterAttribute::~FilterAttribute() {
  1718   switch (mType) {
  1719     case AttributeType::Max:
  1720     case AttributeType::eBool:
  1721     case AttributeType::eUint:
  1722     case AttributeType::eFloat:
  1723       break;
  1725 #define HANDLE_CLASS(className)                            \
  1726     case AttributeType::e##className:                      \
  1727       delete m##className;                                 \
  1728       break;
  1730     HANDLE_CLASS(Size)
  1731     HANDLE_CLASS(IntSize)
  1732     HANDLE_CLASS(IntPoint)
  1733     HANDLE_CLASS(Matrix)
  1734     HANDLE_CLASS(Matrix5x4)
  1735     HANDLE_CLASS(Point3D)
  1736     HANDLE_CLASS(Color)
  1737     HANDLE_CLASS(AttributeMap)
  1739 #undef HANDLE_CLASS
  1741     case AttributeType::eFloats:
  1742       delete mFloats;
  1743       break;
  1747 bool
  1748 FilterAttribute::operator==(const FilterAttribute& aOther) const
  1750   if (mType != aOther.mType) {
  1751     return false;
  1754   switch (mType) {
  1756 #define HANDLE_TYPE(typeName)                              \
  1757     case AttributeType::e##typeName:                       \
  1758       return m##typeName == aOther.m##typeName;
  1760     HANDLE_TYPE(Bool)
  1761     HANDLE_TYPE(Uint)
  1762     HANDLE_TYPE(Float)
  1763     HANDLE_TYPE(Size)
  1764     HANDLE_TYPE(IntSize)
  1765     HANDLE_TYPE(IntPoint)
  1766     HANDLE_TYPE(Matrix)
  1767     HANDLE_TYPE(Matrix5x4)
  1768     HANDLE_TYPE(Point3D)
  1769     HANDLE_TYPE(Color)
  1770     HANDLE_TYPE(AttributeMap)
  1771     HANDLE_TYPE(Floats)
  1773 #undef HANDLE_TYPE
  1775     default:
  1776       return false;
  1780 typedef FilterAttribute Attribute;
  1782 AttributeMap::AttributeMap()
  1786 AttributeMap::~AttributeMap()
  1790 static PLDHashOperator
  1791 CopyAttribute(const uint32_t& aAttributeName,
  1792               Attribute* aAttribute,
  1793               void* aAttributes)
  1795   typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
  1796   Map* map = static_cast<Map*>(aAttributes);
  1797   map->Put(aAttributeName, new Attribute(*aAttribute));
  1798   return PL_DHASH_NEXT;
  1801 AttributeMap::AttributeMap(const AttributeMap& aOther)
  1803   aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
  1806 AttributeMap&
  1807 AttributeMap::operator=(const AttributeMap& aOther)
  1809   if (this != &aOther) {
  1810     mMap.Clear();
  1811     aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
  1813   return *this;
  1816 namespace {
  1817   struct MatchingMap {
  1818     typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
  1819     const Map& map;
  1820     bool matches;
  1821   };
  1824 static PLDHashOperator
  1825 CheckAttributeEquality(const uint32_t& aAttributeName,
  1826                        Attribute* aAttribute,
  1827                        void* aMatchingMap)
  1829   MatchingMap& matchingMap = *static_cast<MatchingMap*>(aMatchingMap);
  1830   Attribute* matchingAttribute = matchingMap.map.Get(aAttributeName);
  1831   if (!matchingAttribute ||
  1832       *matchingAttribute != *aAttribute) {
  1833     matchingMap.matches = false;
  1834     return PL_DHASH_STOP;
  1836   return PL_DHASH_NEXT;
  1839 bool
  1840 AttributeMap::operator==(const AttributeMap& aOther) const
  1842   if (mMap.Count() != aOther.mMap.Count()) {
  1843     return false;
  1846   MatchingMap matchingMap = { mMap, true };
  1847   aOther.mMap.EnumerateRead(CheckAttributeEquality, &matchingMap);
  1848   return matchingMap.matches;
  1851 namespace {
  1852   struct HandlerWithUserData
  1854     AttributeMap::AttributeHandleCallback handler;
  1855     void* userData;
  1856   };
  1859 static PLDHashOperator
  1860 PassAttributeToHandleCallback(const uint32_t& aAttributeName,
  1861                               Attribute* aAttribute,
  1862                               void* aHandlerWithUserData)
  1864   HandlerWithUserData* handlerWithUserData =
  1865     static_cast<HandlerWithUserData*>(aHandlerWithUserData);
  1866   return handlerWithUserData->handler(AttributeName(aAttributeName),
  1867                                       aAttribute->Type(),
  1868                                       handlerWithUserData->userData) ?
  1869     PL_DHASH_NEXT : PL_DHASH_STOP;
  1872 void
  1873 AttributeMap::EnumerateRead(AttributeMap::AttributeHandleCallback aCallback, void* aUserData) const
  1875   HandlerWithUserData handlerWithUserData = { aCallback, aUserData };
  1876   mMap.EnumerateRead(PassAttributeToHandleCallback, &handlerWithUserData);
  1879 uint32_t
  1880 AttributeMap::Count() const
  1882   return mMap.Count();
  1885 #define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \
  1886   type                                                               \
  1887   AttributeMap::Get##typeLabel(AttributeName aName) const {          \
  1888     Attribute* value = mMap.Get(aName);                              \
  1889     return value ? value->As##typeLabel() : defaultValue;            \
  1890   }                                                                  \
  1891   void                                                               \
  1892   AttributeMap::Set(AttributeName aName, type aValue) {              \
  1893     mMap.Remove(aName);                                              \
  1894     mMap.Put(aName, new Attribute(aValue));                          \
  1897 #define MAKE_ATTRIBUTE_HANDLERS_CLASS(className)                     \
  1898   className                                                          \
  1899   AttributeMap::Get##className(AttributeName aName) const {          \
  1900     Attribute* value = mMap.Get(aName);                              \
  1901     return value ? value->As##className() : className();             \
  1902   }                                                                  \
  1903   void                                                               \
  1904   AttributeMap::Set(AttributeName aName, const className& aValue) {  \
  1905     mMap.Remove(aName);                                              \
  1906     mMap.Put(aName, new Attribute(aValue));                          \
  1909 MAKE_ATTRIBUTE_HANDLERS_BASIC(bool, Bool, false)
  1910 MAKE_ATTRIBUTE_HANDLERS_BASIC(uint32_t, Uint, 0)
  1911 MAKE_ATTRIBUTE_HANDLERS_BASIC(float, Float, 0)
  1912 MAKE_ATTRIBUTE_HANDLERS_CLASS(Size)
  1913 MAKE_ATTRIBUTE_HANDLERS_CLASS(IntSize)
  1914 MAKE_ATTRIBUTE_HANDLERS_CLASS(IntPoint)
  1915 MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix)
  1916 MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix5x4)
  1917 MAKE_ATTRIBUTE_HANDLERS_CLASS(Point3D)
  1918 MAKE_ATTRIBUTE_HANDLERS_CLASS(Color)
  1919 MAKE_ATTRIBUTE_HANDLERS_CLASS(AttributeMap)
  1921 #undef MAKE_ATTRIBUTE_HANDLERS_BASIC
  1922 #undef MAKE_ATTRIBUTE_HANDLERS_CLASS
  1924 const nsTArray<float>&
  1925 AttributeMap::GetFloats(AttributeName aName) const
  1927   Attribute* value = mMap.Get(aName);
  1928   if (!value) {
  1929     value = new Attribute(nullptr, 0);
  1930     mMap.Put(aName, value);
  1932   return value->AsFloats();
  1935 void
  1936 AttributeMap::Set(AttributeName aName, const float* aValues, int32_t aLength)
  1938   mMap.Remove(aName);
  1939   mMap.Put(aName, new Attribute(aValues, aLength));

mercurial