gfx/src/FilterSupport.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/src/FilterSupport.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1943 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "FilterSupport.h"
    1.10 +
    1.11 +#include "mozilla/gfx/2D.h"
    1.12 +#include "mozilla/gfx/Filters.h"
    1.13 +#include "mozilla/PodOperations.h"
    1.14 +
    1.15 +#include "gfxContext.h"
    1.16 +#include "gfxPattern.h"
    1.17 +#include "gfxPlatform.h"
    1.18 +#include "gfx2DGlue.h"
    1.19 +
    1.20 +#include "nsMargin.h"
    1.21 +
    1.22 +// c = n / 255
    1.23 +// c <= 0.0031308f ? c * 12.92f : 1.055f * powf(c, 1 / 2.4f) - 0.055f
    1.24 +static const float glinearRGBTosRGBMap[256] = {
    1.25 +  0.000f, 0.050f, 0.085f, 0.111f, 0.132f, 0.150f, 0.166f, 0.181f,
    1.26 +  0.194f, 0.207f, 0.219f, 0.230f, 0.240f, 0.250f, 0.260f, 0.269f,
    1.27 +  0.278f, 0.286f, 0.295f, 0.303f, 0.310f, 0.318f, 0.325f, 0.332f,
    1.28 +  0.339f, 0.346f, 0.352f, 0.359f, 0.365f, 0.371f, 0.378f, 0.383f,
    1.29 +  0.389f, 0.395f, 0.401f, 0.406f, 0.412f, 0.417f, 0.422f, 0.427f,
    1.30 +  0.433f, 0.438f, 0.443f, 0.448f, 0.452f, 0.457f, 0.462f, 0.466f,
    1.31 +  0.471f, 0.476f, 0.480f, 0.485f, 0.489f, 0.493f, 0.498f, 0.502f,
    1.32 +  0.506f, 0.510f, 0.514f, 0.518f, 0.522f, 0.526f, 0.530f, 0.534f,
    1.33 +  0.538f, 0.542f, 0.546f, 0.549f, 0.553f, 0.557f, 0.561f, 0.564f,
    1.34 +  0.568f, 0.571f, 0.575f, 0.579f, 0.582f, 0.586f, 0.589f, 0.592f,
    1.35 +  0.596f, 0.599f, 0.603f, 0.606f, 0.609f, 0.613f, 0.616f, 0.619f,
    1.36 +  0.622f, 0.625f, 0.629f, 0.632f, 0.635f, 0.638f, 0.641f, 0.644f,
    1.37 +  0.647f, 0.650f, 0.653f, 0.656f, 0.659f, 0.662f, 0.665f, 0.668f,
    1.38 +  0.671f, 0.674f, 0.677f, 0.680f, 0.683f, 0.685f, 0.688f, 0.691f,
    1.39 +  0.694f, 0.697f, 0.699f, 0.702f, 0.705f, 0.708f, 0.710f, 0.713f,
    1.40 +  0.716f, 0.718f, 0.721f, 0.724f, 0.726f, 0.729f, 0.731f, 0.734f,
    1.41 +  0.737f, 0.739f, 0.742f, 0.744f, 0.747f, 0.749f, 0.752f, 0.754f,
    1.42 +  0.757f, 0.759f, 0.762f, 0.764f, 0.767f, 0.769f, 0.772f, 0.774f,
    1.43 +  0.776f, 0.779f, 0.781f, 0.784f, 0.786f, 0.788f, 0.791f, 0.793f,
    1.44 +  0.795f, 0.798f, 0.800f, 0.802f, 0.805f, 0.807f, 0.809f, 0.812f,
    1.45 +  0.814f, 0.816f, 0.818f, 0.821f, 0.823f, 0.825f, 0.827f, 0.829f,
    1.46 +  0.832f, 0.834f, 0.836f, 0.838f, 0.840f, 0.843f, 0.845f, 0.847f,
    1.47 +  0.849f, 0.851f, 0.853f, 0.855f, 0.857f, 0.860f, 0.862f, 0.864f,
    1.48 +  0.866f, 0.868f, 0.870f, 0.872f, 0.874f, 0.876f, 0.878f, 0.880f,
    1.49 +  0.882f, 0.884f, 0.886f, 0.888f, 0.890f, 0.892f, 0.894f, 0.896f,
    1.50 +  0.898f, 0.900f, 0.902f, 0.904f, 0.906f, 0.908f, 0.910f, 0.912f,
    1.51 +  0.914f, 0.916f, 0.918f, 0.920f, 0.922f, 0.924f, 0.926f, 0.928f,
    1.52 +  0.930f, 0.931f, 0.933f, 0.935f, 0.937f, 0.939f, 0.941f, 0.943f,
    1.53 +  0.945f, 0.946f, 0.948f, 0.950f, 0.952f, 0.954f, 0.956f, 0.957f,
    1.54 +  0.959f, 0.961f, 0.963f, 0.965f, 0.967f, 0.968f, 0.970f, 0.972f,
    1.55 +  0.974f, 0.975f, 0.977f, 0.979f, 0.981f, 0.983f, 0.984f, 0.986f,
    1.56 +  0.988f, 0.990f, 0.991f, 0.993f, 0.995f, 0.997f, 0.998f, 1.000f
    1.57 +};
    1.58 +
    1.59 +// c = n / 255
    1.60 +// c <= 0.04045f ? c / 12.92f : powf((c + 0.055f) / 1.055f, 2.4f)
    1.61 +static const float gsRGBToLinearRGBMap[256] = {
    1.62 +  0.000f, 0.000f, 0.001f, 0.001f, 0.001f, 0.002f, 0.002f, 0.002f,
    1.63 +  0.002f, 0.003f, 0.003f, 0.003f, 0.004f, 0.004f, 0.004f, 0.005f,
    1.64 +  0.005f, 0.006f, 0.006f, 0.007f, 0.007f, 0.007f, 0.008f, 0.009f,
    1.65 +  0.009f, 0.010f, 0.010f, 0.011f, 0.012f, 0.012f, 0.013f, 0.014f,
    1.66 +  0.014f, 0.015f, 0.016f, 0.017f, 0.018f, 0.019f, 0.019f, 0.020f,
    1.67 +  0.021f, 0.022f, 0.023f, 0.024f, 0.025f, 0.026f, 0.027f, 0.028f,
    1.68 +  0.030f, 0.031f, 0.032f, 0.033f, 0.034f, 0.036f, 0.037f, 0.038f,
    1.69 +  0.040f, 0.041f, 0.042f, 0.044f, 0.045f, 0.047f, 0.048f, 0.050f,
    1.70 +  0.051f, 0.053f, 0.054f, 0.056f, 0.058f, 0.060f, 0.061f, 0.063f,
    1.71 +  0.065f, 0.067f, 0.068f, 0.070f, 0.072f, 0.074f, 0.076f, 0.078f,
    1.72 +  0.080f, 0.082f, 0.084f, 0.087f, 0.089f, 0.091f, 0.093f, 0.095f,
    1.73 +  0.098f, 0.100f, 0.102f, 0.105f, 0.107f, 0.109f, 0.112f, 0.114f,
    1.74 +  0.117f, 0.120f, 0.122f, 0.125f, 0.127f, 0.130f, 0.133f, 0.136f,
    1.75 +  0.138f, 0.141f, 0.144f, 0.147f, 0.150f, 0.153f, 0.156f, 0.159f,
    1.76 +  0.162f, 0.165f, 0.168f, 0.171f, 0.175f, 0.178f, 0.181f, 0.184f,
    1.77 +  0.188f, 0.191f, 0.195f, 0.198f, 0.202f, 0.205f, 0.209f, 0.212f,
    1.78 +  0.216f, 0.220f, 0.223f, 0.227f, 0.231f, 0.235f, 0.238f, 0.242f,
    1.79 +  0.246f, 0.250f, 0.254f, 0.258f, 0.262f, 0.266f, 0.270f, 0.275f,
    1.80 +  0.279f, 0.283f, 0.287f, 0.292f, 0.296f, 0.301f, 0.305f, 0.309f,
    1.81 +  0.314f, 0.319f, 0.323f, 0.328f, 0.332f, 0.337f, 0.342f, 0.347f,
    1.82 +  0.352f, 0.356f, 0.361f, 0.366f, 0.371f, 0.376f, 0.381f, 0.386f,
    1.83 +  0.392f, 0.397f, 0.402f, 0.407f, 0.413f, 0.418f, 0.423f, 0.429f,
    1.84 +  0.434f, 0.440f, 0.445f, 0.451f, 0.456f, 0.462f, 0.468f, 0.474f,
    1.85 +  0.479f, 0.485f, 0.491f, 0.497f, 0.503f, 0.509f, 0.515f, 0.521f,
    1.86 +  0.527f, 0.533f, 0.539f, 0.546f, 0.552f, 0.558f, 0.565f, 0.571f,
    1.87 +  0.578f, 0.584f, 0.591f, 0.597f, 0.604f, 0.610f, 0.617f, 0.624f,
    1.88 +  0.631f, 0.638f, 0.644f, 0.651f, 0.658f, 0.665f, 0.672f, 0.680f,
    1.89 +  0.687f, 0.694f, 0.701f, 0.708f, 0.716f, 0.723f, 0.730f, 0.738f,
    1.90 +  0.745f, 0.753f, 0.761f, 0.768f, 0.776f, 0.784f, 0.791f, 0.799f,
    1.91 +  0.807f, 0.815f, 0.823f, 0.831f, 0.839f, 0.847f, 0.855f, 0.863f,
    1.92 +  0.871f, 0.880f, 0.888f, 0.896f, 0.905f, 0.913f, 0.922f, 0.930f,
    1.93 +  0.939f, 0.947f, 0.956f, 0.965f, 0.973f, 0.982f, 0.991f, 1.000f
    1.94 +};
    1.95 +
    1.96 +namespace mozilla {
    1.97 +namespace gfx {
    1.98 +
    1.99 +// Some convenience FilterNode creation functions.
   1.100 +
   1.101 +static const float kMaxStdDeviation = 500;
   1.102 +
   1.103 +namespace FilterWrappers {
   1.104 +
   1.105 +  static TemporaryRef<FilterNode>
   1.106 +  Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
   1.107 +  {
   1.108 +    RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
   1.109 +    filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
   1.110 +    return filter;
   1.111 +  }
   1.112 +
   1.113 +  static TemporaryRef<FilterNode>
   1.114 +  Premultiply(DrawTarget* aDT, FilterNode* aInput)
   1.115 +  {
   1.116 +    RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::PREMULTIPLY);
   1.117 +    filter->SetInput(IN_PREMULTIPLY_IN, aInput);
   1.118 +    return filter;
   1.119 +  }
   1.120 +
   1.121 +  static TemporaryRef<FilterNode>
   1.122 +  LinearRGBToSRGB(DrawTarget* aDT, FilterNode* aInput)
   1.123 +  {
   1.124 +    RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   1.125 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
   1.126 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
   1.127 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
   1.128 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
   1.129 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
   1.130 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
   1.131 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
   1.132 +    transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
   1.133 +    return transfer;
   1.134 +  }
   1.135 +
   1.136 +  static TemporaryRef<FilterNode>
   1.137 +  SRGBToLinearRGB(DrawTarget* aDT, FilterNode* aInput)
   1.138 +  {
   1.139 +    RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   1.140 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
   1.141 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
   1.142 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
   1.143 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
   1.144 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
   1.145 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
   1.146 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
   1.147 +    transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
   1.148 +    return transfer;
   1.149 +  }
   1.150 +
   1.151 +  static TemporaryRef<FilterNode>
   1.152 +  Crop(DrawTarget* aDT, FilterNode* aInputFilter, const IntRect& aRect)
   1.153 +  {
   1.154 +    RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CROP);
   1.155 +    filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
   1.156 +    filter->SetInput(IN_CROP_IN, aInputFilter);
   1.157 +    return filter;
   1.158 +  }
   1.159 +
   1.160 +  static TemporaryRef<FilterNode>
   1.161 +  Offset(DrawTarget* aDT, FilterNode* aInputFilter, const IntPoint& aOffset)
   1.162 +  {
   1.163 +    RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
   1.164 +    filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
   1.165 +    filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
   1.166 +    return filter;
   1.167 +  }
   1.168 +
   1.169 +  static TemporaryRef<FilterNode>
   1.170 +  GaussianBlur(DrawTarget* aDT, FilterNode* aInputFilter, const Size& aStdDeviation)
   1.171 +  {
   1.172 +    float stdX = float(std::min(aStdDeviation.width, kMaxStdDeviation));
   1.173 +    float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
   1.174 +    if (stdX == stdY) {
   1.175 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
   1.176 +      filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
   1.177 +      filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
   1.178 +      return filter;
   1.179 +    }
   1.180 +    RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
   1.181 +    RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
   1.182 +    filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
   1.183 +    filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
   1.184 +    filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
   1.185 +    filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
   1.186 +    filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
   1.187 +    filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
   1.188 +    return filterV;
   1.189 +  }
   1.190 +
   1.191 +  static TemporaryRef<FilterNode>
   1.192 +  Clear(DrawTarget* aDT)
   1.193 +  {
   1.194 +    RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
   1.195 +    filter->SetAttribute(ATT_FLOOD_COLOR, Color(0,0,0,0));
   1.196 +    return filter;
   1.197 +  }
   1.198 +
   1.199 +  static TemporaryRef<FilterNode>
   1.200 +  ForSurface(DrawTarget* aDT, SourceSurface* aSurface,
   1.201 +             const IntPoint& aSurfacePosition)
   1.202 +  {
   1.203 +    RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
   1.204 +    filter->SetAttribute(ATT_TRANSFORM_MATRIX,
   1.205 +      Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
   1.206 +    filter->SetInput(IN_TRANSFORM_IN, aSurface);
   1.207 +    return filter;
   1.208 +  }
   1.209 +
   1.210 +  static TemporaryRef<FilterNode>
   1.211 +  ToAlpha(DrawTarget* aDT, FilterNode* aInput)
   1.212 +  {
   1.213 +    float zero = 0.0f;
   1.214 +    RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   1.215 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
   1.216 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
   1.217 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
   1.218 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
   1.219 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
   1.220 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
   1.221 +    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
   1.222 +    transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
   1.223 +    return transfer;
   1.224 +  }
   1.225 +
   1.226 +}
   1.227 +
   1.228 +// A class that wraps a FilterNode and handles conversion between different
   1.229 +// color models. Create FilterCachedColorModels with your original filter and
   1.230 +// the color model that this filter outputs in natively, and then call
   1.231 +// ->ForColorModel(colorModel) in order to get a FilterNode which outputs to
   1.232 +// the specified colorModel.
   1.233 +// Internally, this is achieved by wrapping the original FilterNode with
   1.234 +// conversion FilterNodes. These filter nodes are cached in such a way that no
   1.235 +// repeated or back-and-forth conversions happen.
   1.236 +class FilterCachedColorModels
   1.237 +{
   1.238 +public:
   1.239 +  NS_INLINE_DECL_REFCOUNTING(FilterCachedColorModels)
   1.240 +  // aFilter can be null. In that case, ForColorModel will return a non-null
   1.241 +  // completely transparent filter for all color models.
   1.242 +  FilterCachedColorModels(DrawTarget* aDT,
   1.243 +                          FilterNode* aFilter,
   1.244 +                          ColorModel aOriginalColorModel);
   1.245 +
   1.246 +  // Get a FilterNode for the specified color model, guaranteed to be non-null.
   1.247 +  TemporaryRef<FilterNode> ForColorModel(ColorModel aColorModel);
   1.248 +
   1.249 +  AlphaModel OriginalAlphaModel() const { return mOriginalColorModel.mAlphaModel; }
   1.250 +
   1.251 +private:
   1.252 +  // Create the required FilterNode that will be cached by ForColorModel.
   1.253 +  TemporaryRef<FilterNode> WrapForColorModel(ColorModel aColorModel);
   1.254 +
   1.255 +  RefPtr<DrawTarget> mDT;
   1.256 +  ColorModel mOriginalColorModel;
   1.257 +
   1.258 +  // This array is indexed by ColorModel::ToIndex.
   1.259 +  RefPtr<FilterNode> mFilterForColorModel[4];
   1.260 +};
   1.261 +
   1.262 +FilterCachedColorModels::FilterCachedColorModels(DrawTarget* aDT,
   1.263 +                                                 FilterNode* aFilter,
   1.264 +                                                 ColorModel aOriginalColorModel)
   1.265 + : mDT(aDT)
   1.266 + , mOriginalColorModel(aOriginalColorModel)
   1.267 +{
   1.268 +  if (aFilter) {
   1.269 +    mFilterForColorModel[aOriginalColorModel.ToIndex()] = aFilter;
   1.270 +  } else {
   1.271 +    RefPtr<FilterNode> clear = FilterWrappers::Clear(aDT);
   1.272 +    mFilterForColorModel[0] = clear;
   1.273 +    mFilterForColorModel[1] = clear;
   1.274 +    mFilterForColorModel[2] = clear;
   1.275 +    mFilterForColorModel[3] = clear;
   1.276 +  }
   1.277 +}
   1.278 +
   1.279 +TemporaryRef<FilterNode>
   1.280 +FilterCachedColorModels::ForColorModel(ColorModel aColorModel)
   1.281 +{
   1.282 +  if (!mFilterForColorModel[aColorModel.ToIndex()]) {
   1.283 +    mFilterForColorModel[aColorModel.ToIndex()] = WrapForColorModel(aColorModel);
   1.284 +  }
   1.285 +  return mFilterForColorModel[aColorModel.ToIndex()];
   1.286 +}
   1.287 +
   1.288 +TemporaryRef<FilterNode>
   1.289 +FilterCachedColorModels::WrapForColorModel(ColorModel aColorModel)
   1.290 +{
   1.291 +  // Convert one aspect at a time and recurse.
   1.292 +  // Conversions between premultiplied / unpremultiplied color channels for the
   1.293 +  // same color space can happen directly.
   1.294 +  // Conversions between different color spaces can only happen on
   1.295 +  // unpremultiplied color channels.
   1.296 +
   1.297 +  if (aColorModel.mAlphaModel == AlphaModel::Premultiplied) {
   1.298 +    RefPtr<FilterNode> unpre =
   1.299 +      ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Unpremultiplied));
   1.300 +    return FilterWrappers::Premultiply(mDT, unpre);
   1.301 +  }
   1.302 +
   1.303 +  MOZ_ASSERT(aColorModel.mAlphaModel == AlphaModel::Unpremultiplied);
   1.304 +  if (aColorModel.mColorSpace == mOriginalColorModel.mColorSpace) {
   1.305 +    RefPtr<FilterNode> premultiplied =
   1.306 +      ForColorModel(ColorModel(aColorModel.mColorSpace, AlphaModel::Premultiplied));
   1.307 +    return FilterWrappers::Unpremultiply(mDT, premultiplied);
   1.308 +  }
   1.309 +
   1.310 +  RefPtr<FilterNode> unpremultipliedOriginal =
   1.311 +    ForColorModel(ColorModel(mOriginalColorModel.mColorSpace, AlphaModel::Unpremultiplied));
   1.312 +  if (aColorModel.mColorSpace == ColorSpace::LinearRGB) {
   1.313 +    return FilterWrappers::SRGBToLinearRGB(mDT, unpremultipliedOriginal);
   1.314 +  }
   1.315 +  return FilterWrappers::LinearRGBToSRGB(mDT, unpremultipliedOriginal);
   1.316 +}
   1.317 +
   1.318 +// Create a 4x5 color matrix for the different ways to specify color matrices
   1.319 +// in SVG.
   1.320 +static nsresult
   1.321 +ComputeColorMatrix(uint32_t aColorMatrixType, const nsTArray<float>& aValues,
   1.322 +                   float aOutMatrix[20])
   1.323 +{
   1.324 +  static const float identityMatrix[] =
   1.325 +    { 1, 0, 0, 0, 0,
   1.326 +      0, 1, 0, 0, 0,
   1.327 +      0, 0, 1, 0, 0,
   1.328 +      0, 0, 0, 1, 0 };
   1.329 +
   1.330 +  static const float luminanceToAlphaMatrix[] =
   1.331 +    { 0,       0,       0,       0, 0,
   1.332 +      0,       0,       0,       0, 0,
   1.333 +      0,       0,       0,       0, 0,
   1.334 +      0.2125f, 0.7154f, 0.0721f, 0, 0 };
   1.335 +
   1.336 +  switch (aColorMatrixType) {
   1.337 +
   1.338 +    case SVG_FECOLORMATRIX_TYPE_MATRIX:
   1.339 +    {
   1.340 +      if (aValues.Length() != 20)
   1.341 +        return NS_ERROR_FAILURE;
   1.342 +
   1.343 +      PodCopy(aOutMatrix, aValues.Elements(), 20);
   1.344 +      break;
   1.345 +    }
   1.346 +
   1.347 +    case SVG_FECOLORMATRIX_TYPE_SATURATE:
   1.348 +    {
   1.349 +      if (aValues.Length() != 1)
   1.350 +        return NS_ERROR_FAILURE;
   1.351 +
   1.352 +      float s = aValues[0];
   1.353 +
   1.354 +      if (s < 0)
   1.355 +        return NS_ERROR_FAILURE;
   1.356 +
   1.357 +      PodCopy(aOutMatrix, identityMatrix, 20);
   1.358 +
   1.359 +      aOutMatrix[0] = 0.213f + 0.787f * s;
   1.360 +      aOutMatrix[1] = 0.715f - 0.715f * s;
   1.361 +      aOutMatrix[2] = 0.072f - 0.072f * s;
   1.362 +
   1.363 +      aOutMatrix[5] = 0.213f - 0.213f * s;
   1.364 +      aOutMatrix[6] = 0.715f + 0.285f * s;
   1.365 +      aOutMatrix[7] = 0.072f - 0.072f * s;
   1.366 +
   1.367 +      aOutMatrix[10] = 0.213f - 0.213f * s;
   1.368 +      aOutMatrix[11] = 0.715f - 0.715f * s;
   1.369 +      aOutMatrix[12] = 0.072f + 0.928f * s;
   1.370 +
   1.371 +      break;
   1.372 +    }
   1.373 +
   1.374 +    case SVG_FECOLORMATRIX_TYPE_HUE_ROTATE:
   1.375 +    {
   1.376 +      if (aValues.Length() != 1)
   1.377 +        return NS_ERROR_FAILURE;
   1.378 +
   1.379 +      PodCopy(aOutMatrix, identityMatrix, 20);
   1.380 +
   1.381 +      float hueRotateValue = aValues[0];
   1.382 +
   1.383 +      float c = static_cast<float>(cos(hueRotateValue * M_PI / 180));
   1.384 +      float s = static_cast<float>(sin(hueRotateValue * M_PI / 180));
   1.385 +
   1.386 +      aOutMatrix[0] = 0.213f + 0.787f * c - 0.213f * s;
   1.387 +      aOutMatrix[1] = 0.715f - 0.715f * c - 0.715f * s;
   1.388 +      aOutMatrix[2] = 0.072f - 0.072f * c + 0.928f * s;
   1.389 +
   1.390 +      aOutMatrix[5] = 0.213f - 0.213f * c + 0.143f * s;
   1.391 +      aOutMatrix[6] = 0.715f + 0.285f * c + 0.140f * s;
   1.392 +      aOutMatrix[7] = 0.072f - 0.072f * c - 0.283f * s;
   1.393 +
   1.394 +      aOutMatrix[10] = 0.213f - 0.213f * c - 0.787f * s;
   1.395 +      aOutMatrix[11] = 0.715f - 0.715f * c + 0.715f * s;
   1.396 +      aOutMatrix[12] = 0.072f + 0.928f * c + 0.072f * s;
   1.397 +
   1.398 +      break;
   1.399 +    }
   1.400 +
   1.401 +    case SVG_FECOLORMATRIX_TYPE_LUMINANCE_TO_ALPHA:
   1.402 +    {
   1.403 +      PodCopy(aOutMatrix, luminanceToAlphaMatrix, 20);
   1.404 +      break;
   1.405 +    }
   1.406 +
   1.407 +    default:
   1.408 +      return NS_ERROR_FAILURE;
   1.409 +
   1.410 +  }
   1.411 +
   1.412 +  return NS_OK;
   1.413 +}
   1.414 +
   1.415 +static void
   1.416 +DisableAllTransfers(FilterNode* aTransferFilterNode)
   1.417 +{
   1.418 +  aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_R, true);
   1.419 +  aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_G, true);
   1.420 +  aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_B, true);
   1.421 +  aTransferFilterNode->SetAttribute(ATT_TRANSFER_DISABLE_A, true);
   1.422 +}
   1.423 +
   1.424 +// Called for one channel at a time.
   1.425 +// This function creates the required FilterNodes on demand and tries to
   1.426 +// merge conversions of different channels into the same FilterNode if
   1.427 +// possible.
   1.428 +// There's a mismatch between the way SVG and the Moz2D API handle transfer
   1.429 +// functions: In SVG, it's possible to specify a different transfer function
   1.430 +// type for each color channel, but in Moz2D, a given transfer function type
   1.431 +// applies to all color channels.
   1.432 +//
   1.433 +//  @param aFunctionAttributes The attributes of the transfer function for this
   1.434 +//                             channel.
   1.435 +//  @param aChannel The color channel that this function applies to, where
   1.436 +//                  0 = red, 1 = green, 2 = blue, 3 = alpha
   1.437 +//  @param aDT The DrawTarget that the FilterNodes should be created for.
   1.438 +//  @param aTableTransfer Existing FilterNode holders (which may still be
   1.439 +//                        null) that the resulting FilterNodes from this
   1.440 +//                        function will be stored in.
   1.441 +//           
   1.442 +static void
   1.443 +ConvertComponentTransferFunctionToFilter(const AttributeMap& aFunctionAttributes,
   1.444 +                                         int32_t aChannel,
   1.445 +                                         DrawTarget* aDT,
   1.446 +                                         RefPtr<FilterNode>& aTableTransfer,
   1.447 +                                         RefPtr<FilterNode>& aDiscreteTransfer,
   1.448 +                                         RefPtr<FilterNode>& aLinearTransfer,
   1.449 +                                         RefPtr<FilterNode>& aGammaTransfer)
   1.450 +{
   1.451 +  static const TransferAtts disableAtt[4] = {
   1.452 +    ATT_TRANSFER_DISABLE_R,
   1.453 +    ATT_TRANSFER_DISABLE_G,
   1.454 +    ATT_TRANSFER_DISABLE_B,
   1.455 +    ATT_TRANSFER_DISABLE_A
   1.456 +  };
   1.457 +
   1.458 +  RefPtr<FilterNode> filter;
   1.459 +
   1.460 +  uint32_t type = aFunctionAttributes.GetUint(eComponentTransferFunctionType);
   1.461 +
   1.462 +  switch (type) {
   1.463 +  case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
   1.464 +  {
   1.465 +    const nsTArray<float>& tableValues =
   1.466 +      aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
   1.467 +    if (tableValues.Length() < 2)
   1.468 +      return;
   1.469 +
   1.470 +    if (!aTableTransfer) {
   1.471 +      aTableTransfer = aDT->CreateFilter(FilterType::TABLE_TRANSFER);
   1.472 +      DisableAllTransfers(aTableTransfer);
   1.473 +    }
   1.474 +    filter = aTableTransfer;
   1.475 +    static const TableTransferAtts tableAtt[4] = {
   1.476 +      ATT_TABLE_TRANSFER_TABLE_R,
   1.477 +      ATT_TABLE_TRANSFER_TABLE_G,
   1.478 +      ATT_TABLE_TRANSFER_TABLE_B,
   1.479 +      ATT_TABLE_TRANSFER_TABLE_A
   1.480 +    };
   1.481 +    filter->SetAttribute(disableAtt[aChannel], false);
   1.482 +    filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
   1.483 +    break;
   1.484 +  }
   1.485 +
   1.486 +  case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
   1.487 +  {
   1.488 +    const nsTArray<float>& tableValues =
   1.489 +      aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
   1.490 +    if (tableValues.Length() < 1)
   1.491 +      return;
   1.492 +
   1.493 +    if (!aDiscreteTransfer) {
   1.494 +      aDiscreteTransfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
   1.495 +      DisableAllTransfers(aDiscreteTransfer);
   1.496 +    }
   1.497 +    filter = aDiscreteTransfer;
   1.498 +    static const DiscreteTransferAtts tableAtt[4] = {
   1.499 +      ATT_DISCRETE_TRANSFER_TABLE_R,
   1.500 +      ATT_DISCRETE_TRANSFER_TABLE_G,
   1.501 +      ATT_DISCRETE_TRANSFER_TABLE_B,
   1.502 +      ATT_DISCRETE_TRANSFER_TABLE_A
   1.503 +    };
   1.504 +    filter->SetAttribute(disableAtt[aChannel], false);
   1.505 +    filter->SetAttribute(tableAtt[aChannel], &tableValues[0], tableValues.Length());
   1.506 +
   1.507 +    break;
   1.508 +  }
   1.509 +
   1.510 +  case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
   1.511 +  {
   1.512 +    static const LinearTransferAtts slopeAtt[4] = {
   1.513 +      ATT_LINEAR_TRANSFER_SLOPE_R,
   1.514 +      ATT_LINEAR_TRANSFER_SLOPE_G,
   1.515 +      ATT_LINEAR_TRANSFER_SLOPE_B,
   1.516 +      ATT_LINEAR_TRANSFER_SLOPE_A
   1.517 +    };
   1.518 +    static const LinearTransferAtts interceptAtt[4] = {
   1.519 +      ATT_LINEAR_TRANSFER_INTERCEPT_R,
   1.520 +      ATT_LINEAR_TRANSFER_INTERCEPT_G,
   1.521 +      ATT_LINEAR_TRANSFER_INTERCEPT_B,
   1.522 +      ATT_LINEAR_TRANSFER_INTERCEPT_A
   1.523 +    };
   1.524 +    if (!aLinearTransfer) {
   1.525 +      aLinearTransfer = aDT->CreateFilter(FilterType::LINEAR_TRANSFER);
   1.526 +      DisableAllTransfers(aLinearTransfer);
   1.527 +    }
   1.528 +    filter = aLinearTransfer;
   1.529 +    filter->SetAttribute(disableAtt[aChannel], false);
   1.530 +    float slope = aFunctionAttributes.GetFloat(eComponentTransferFunctionSlope);
   1.531 +    float intercept = aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
   1.532 +    filter->SetAttribute(slopeAtt[aChannel], slope);
   1.533 +    filter->SetAttribute(interceptAtt[aChannel], intercept);
   1.534 +    break;
   1.535 +  }
   1.536 +
   1.537 +  case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
   1.538 +  {
   1.539 +    static const GammaTransferAtts amplitudeAtt[4] = {
   1.540 +      ATT_GAMMA_TRANSFER_AMPLITUDE_R,
   1.541 +      ATT_GAMMA_TRANSFER_AMPLITUDE_G,
   1.542 +      ATT_GAMMA_TRANSFER_AMPLITUDE_B,
   1.543 +      ATT_GAMMA_TRANSFER_AMPLITUDE_A
   1.544 +    };
   1.545 +    static const GammaTransferAtts exponentAtt[4] = {
   1.546 +      ATT_GAMMA_TRANSFER_EXPONENT_R,
   1.547 +      ATT_GAMMA_TRANSFER_EXPONENT_G,
   1.548 +      ATT_GAMMA_TRANSFER_EXPONENT_B,
   1.549 +      ATT_GAMMA_TRANSFER_EXPONENT_A
   1.550 +    };
   1.551 +    static const GammaTransferAtts offsetAtt[4] = {
   1.552 +      ATT_GAMMA_TRANSFER_OFFSET_R,
   1.553 +      ATT_GAMMA_TRANSFER_OFFSET_G,
   1.554 +      ATT_GAMMA_TRANSFER_OFFSET_B,
   1.555 +      ATT_GAMMA_TRANSFER_OFFSET_A
   1.556 +    };
   1.557 +    if (!aGammaTransfer) {
   1.558 +      aGammaTransfer = aDT->CreateFilter(FilterType::GAMMA_TRANSFER);
   1.559 +      DisableAllTransfers(aGammaTransfer);
   1.560 +    }
   1.561 +    filter = aGammaTransfer;
   1.562 +    filter->SetAttribute(disableAtt[aChannel], false);
   1.563 +    float amplitude = aFunctionAttributes.GetFloat(eComponentTransferFunctionAmplitude);
   1.564 +    float exponent = aFunctionAttributes.GetFloat(eComponentTransferFunctionExponent);
   1.565 +    float offset = aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
   1.566 +    filter->SetAttribute(amplitudeAtt[aChannel], amplitude);
   1.567 +    filter->SetAttribute(exponentAtt[aChannel], exponent);
   1.568 +    filter->SetAttribute(offsetAtt[aChannel], offset);
   1.569 +    break;
   1.570 +  }
   1.571 +
   1.572 +  case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
   1.573 +  default:
   1.574 +    break;
   1.575 +  }
   1.576 +}
   1.577 +
   1.578 +const int32_t kMorphologyMaxRadius = 100000;
   1.579 +
   1.580 +// Handle the different primitive description types and create the necessary
   1.581 +// FilterNode(s) for each.
   1.582 +// Returns nullptr for invalid filter primitives. This should be interpreted as
   1.583 +// transparent black by the caller.
   1.584 +// aSourceRegions contains the filter primitive subregions of the source
   1.585 +// primitives; only needed for eTile primitives.
   1.586 +// aInputImages carries additional surfaces that are used by eImage primitives.
   1.587 +static TemporaryRef<FilterNode>
   1.588 +FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescription,
   1.589 +                                   DrawTarget* aDT,
   1.590 +                                   nsTArray<RefPtr<FilterNode> >& aSources,
   1.591 +                                   nsTArray<IntRect>& aSourceRegions,
   1.592 +                                   nsTArray<RefPtr<SourceSurface>>& aInputImages)
   1.593 +{
   1.594 +  const AttributeMap& atts = aDescription.Attributes();
   1.595 +  switch (aDescription.Type()) {
   1.596 +
   1.597 +    case PrimitiveType::Empty:
   1.598 +      return nullptr;
   1.599 +
   1.600 +    case PrimitiveType::Blend:
   1.601 +    {
   1.602 +      uint32_t mode = atts.GetUint(eBlendBlendmode);
   1.603 +      RefPtr<FilterNode> filter;
   1.604 +      if (mode == SVG_FEBLEND_MODE_UNKNOWN) {
   1.605 +        return nullptr;
   1.606 +      }
   1.607 +      if (mode == SVG_FEBLEND_MODE_NORMAL) {
   1.608 +        filter = aDT->CreateFilter(FilterType::COMPOSITE);
   1.609 +        filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
   1.610 +        filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
   1.611 +      } else {
   1.612 +        filter = aDT->CreateFilter(FilterType::BLEND);
   1.613 +        static const uint8_t blendModes[SVG_FEBLEND_MODE_LIGHTEN + 1] = {
   1.614 +          0,
   1.615 +          0,
   1.616 +          BLEND_MODE_MULTIPLY,
   1.617 +          BLEND_MODE_SCREEN,
   1.618 +          BLEND_MODE_DARKEN,
   1.619 +          BLEND_MODE_LIGHTEN
   1.620 +        };
   1.621 +        filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)blendModes[mode]);
   1.622 +        filter->SetInput(IN_BLEND_IN, aSources[0]);
   1.623 +        filter->SetInput(IN_BLEND_IN2, aSources[1]);
   1.624 +      }
   1.625 +      return filter;
   1.626 +    }
   1.627 +
   1.628 +    case PrimitiveType::ColorMatrix:
   1.629 +    {
   1.630 +      float colorMatrix[20];
   1.631 +      uint32_t type = atts.GetUint(eColorMatrixType);
   1.632 +      const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
   1.633 +      if (NS_FAILED(ComputeColorMatrix(type, values, colorMatrix))) {
   1.634 +        return aSources[0];
   1.635 +      }
   1.636 +      Matrix5x4 matrix(colorMatrix[0], colorMatrix[5], colorMatrix[10],  colorMatrix[15],
   1.637 +                       colorMatrix[1], colorMatrix[6], colorMatrix[11],  colorMatrix[16],
   1.638 +                       colorMatrix[2], colorMatrix[7], colorMatrix[12],  colorMatrix[17],
   1.639 +                       colorMatrix[3], colorMatrix[8], colorMatrix[13],  colorMatrix[18],
   1.640 +                       colorMatrix[4], colorMatrix[9], colorMatrix[14],  colorMatrix[19]);
   1.641 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COLOR_MATRIX);
   1.642 +      filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
   1.643 +      filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
   1.644 +      filter->SetInput(IN_COLOR_MATRIX_IN, aSources[0]);
   1.645 +      return filter;
   1.646 +    }
   1.647 +
   1.648 +    case PrimitiveType::Morphology:
   1.649 +    {
   1.650 +      Size radii = atts.GetSize(eMorphologyRadii);
   1.651 +      int32_t rx = radii.width;
   1.652 +      int32_t ry = radii.height;
   1.653 +      if (rx < 0 || ry < 0) {
   1.654 +        // XXX SVGContentUtils::ReportToConsole()
   1.655 +        return nullptr;
   1.656 +      }
   1.657 +      if (rx == 0 && ry == 0) {
   1.658 +        return nullptr;
   1.659 +      }
   1.660 +
   1.661 +      // Clamp radii to prevent completely insane values:
   1.662 +      rx = std::min(rx, kMorphologyMaxRadius);
   1.663 +      ry = std::min(ry, kMorphologyMaxRadius);
   1.664 +
   1.665 +      MorphologyOperator op = atts.GetUint(eMorphologyOperator) == SVG_OPERATOR_ERODE ?
   1.666 +        MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE;
   1.667 +
   1.668 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::MORPHOLOGY);
   1.669 +      filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
   1.670 +      filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
   1.671 +      filter->SetInput(IN_MORPHOLOGY_IN, aSources[0]);
   1.672 +      return filter;
   1.673 +    }
   1.674 +
   1.675 +    case PrimitiveType::Flood:
   1.676 +    {
   1.677 +      Color color = atts.GetColor(eFloodColor);
   1.678 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
   1.679 +      filter->SetAttribute(ATT_FLOOD_COLOR, color);
   1.680 +      return filter;
   1.681 +    }
   1.682 +
   1.683 +    case PrimitiveType::Tile:
   1.684 +    {
   1.685 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TILE);
   1.686 +      filter->SetAttribute(ATT_TILE_SOURCE_RECT, aSourceRegions[0]);
   1.687 +      filter->SetInput(IN_TILE_IN, aSources[0]);
   1.688 +      return filter;
   1.689 +    }
   1.690 +
   1.691 +    case PrimitiveType::ComponentTransfer:
   1.692 +    {
   1.693 +      RefPtr<FilterNode> filters[4]; // one for each FILTER_*_TRANSFER type
   1.694 +      static const AttributeName componentFunctionNames[4] = {
   1.695 +        eComponentTransferFunctionR,
   1.696 +        eComponentTransferFunctionG,
   1.697 +        eComponentTransferFunctionB,
   1.698 +        eComponentTransferFunctionA
   1.699 +      };
   1.700 +      for (int32_t i = 0; i < 4; i++) {
   1.701 +        AttributeMap functionAttributes =
   1.702 +          atts.GetAttributeMap(componentFunctionNames[i]);
   1.703 +        ConvertComponentTransferFunctionToFilter(functionAttributes, i, aDT,
   1.704 +          filters[0], filters[1], filters[2], filters[3]);
   1.705 +      }
   1.706 +
   1.707 +      // Connect all used filters nodes.
   1.708 +      RefPtr<FilterNode> lastFilter = aSources[0];
   1.709 +      for (int32_t i = 0; i < 4; i++) {
   1.710 +        if (filters[i]) {
   1.711 +          filters[i]->SetInput(0, lastFilter);
   1.712 +          lastFilter = filters[i];
   1.713 +        }
   1.714 +      }
   1.715 +
   1.716 +      return lastFilter;
   1.717 +    }
   1.718 +
   1.719 +    case PrimitiveType::ConvolveMatrix:
   1.720 +    {
   1.721 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
   1.722 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, atts.GetIntSize(eConvolveMatrixKernelSize));
   1.723 +      const nsTArray<float>& matrix = atts.GetFloats(eConvolveMatrixKernelMatrix);
   1.724 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,
   1.725 +                           matrix.Elements(), matrix.Length());
   1.726 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR,
   1.727 +                           atts.GetFloat(eConvolveMatrixDivisor));
   1.728 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS,
   1.729 +                           atts.GetFloat(eConvolveMatrixBias));
   1.730 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET,
   1.731 +                           atts.GetIntPoint(eConvolveMatrixTarget));
   1.732 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT,
   1.733 +                           aSourceRegions[0]);
   1.734 +      uint32_t edgeMode = atts.GetUint(eConvolveMatrixEdgeMode);
   1.735 +      static const uint8_t edgeModes[SVG_EDGEMODE_NONE+1] = {
   1.736 +        EDGE_MODE_NONE,      // SVG_EDGEMODE_UNKNOWN
   1.737 +        EDGE_MODE_DUPLICATE, // SVG_EDGEMODE_DUPLICATE
   1.738 +        EDGE_MODE_WRAP,      // SVG_EDGEMODE_WRAP
   1.739 +        EDGE_MODE_NONE       // SVG_EDGEMODE_NONE
   1.740 +      };
   1.741 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)edgeModes[edgeMode]);
   1.742 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH,
   1.743 +                           atts.GetSize(eConvolveMatrixKernelUnitLength));
   1.744 +      filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA,
   1.745 +                           atts.GetBool(eConvolveMatrixPreserveAlpha));
   1.746 +      filter->SetInput(IN_CONVOLVE_MATRIX_IN, aSources[0]);
   1.747 +      return filter;
   1.748 +    }
   1.749 +
   1.750 +    case PrimitiveType::Offset:
   1.751 +    {
   1.752 +      return FilterWrappers::Offset(aDT, aSources[0],
   1.753 +                                    atts.GetIntPoint(eOffsetOffset));
   1.754 +    }
   1.755 +
   1.756 +    case PrimitiveType::DisplacementMap:
   1.757 +    {
   1.758 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
   1.759 +      filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE,
   1.760 +                           atts.GetFloat(eDisplacementMapScale));
   1.761 +      static const uint8_t channel[SVG_CHANNEL_A+1] = {
   1.762 +        COLOR_CHANNEL_R, // SVG_CHANNEL_UNKNOWN
   1.763 +        COLOR_CHANNEL_R, // SVG_CHANNEL_R
   1.764 +        COLOR_CHANNEL_G, // SVG_CHANNEL_G
   1.765 +        COLOR_CHANNEL_B, // SVG_CHANNEL_B
   1.766 +        COLOR_CHANNEL_A  // SVG_CHANNEL_A
   1.767 +      };
   1.768 +      filter->SetAttribute(ATT_DISPLACEMENT_MAP_X_CHANNEL,
   1.769 +                           (uint32_t)channel[atts.GetUint(eDisplacementMapXChannel)]);
   1.770 +      filter->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL,
   1.771 +                           (uint32_t)channel[atts.GetUint(eDisplacementMapYChannel)]);
   1.772 +      filter->SetInput(IN_DISPLACEMENT_MAP_IN, aSources[0]);
   1.773 +      filter->SetInput(IN_DISPLACEMENT_MAP_IN2, aSources[1]);
   1.774 +      return filter;
   1.775 +    }
   1.776 +
   1.777 +    case PrimitiveType::Turbulence:
   1.778 +    {
   1.779 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TURBULENCE);
   1.780 +      filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
   1.781 +                           atts.GetSize(eTurbulenceBaseFrequency));
   1.782 +      filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES,
   1.783 +                           atts.GetUint(eTurbulenceNumOctaves));
   1.784 +      filter->SetAttribute(ATT_TURBULENCE_STITCHABLE,
   1.785 +                           atts.GetBool(eTurbulenceStitchable));
   1.786 +      filter->SetAttribute(ATT_TURBULENCE_SEED,
   1.787 +                           (uint32_t)atts.GetFloat(eTurbulenceSeed));
   1.788 +      static const uint8_t type[SVG_TURBULENCE_TYPE_TURBULENCE+1] = {
   1.789 +        TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_UNKNOWN
   1.790 +        TURBULENCE_TYPE_FRACTAL_NOISE, // SVG_TURBULENCE_TYPE_FRACTALNOISE
   1.791 +        TURBULENCE_TYPE_TURBULENCE     // SVG_TURBULENCE_TYPE_TURBULENCE
   1.792 +      };
   1.793 +      filter->SetAttribute(ATT_TURBULENCE_TYPE,
   1.794 +                           (uint32_t)type[atts.GetUint(eTurbulenceType)]);
   1.795 +      filter->SetAttribute(ATT_TURBULENCE_RECT,
   1.796 +                           aDescription.PrimitiveSubregion() - atts.GetIntPoint(eTurbulenceOffset));
   1.797 +      return FilterWrappers::Offset(aDT, filter, atts.GetIntPoint(eTurbulenceOffset));
   1.798 +    }
   1.799 +
   1.800 +    case PrimitiveType::Composite:
   1.801 +    {
   1.802 +      RefPtr<FilterNode> filter;
   1.803 +      uint32_t op = atts.GetUint(eCompositeOperator);
   1.804 +      if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
   1.805 +        filter = aDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
   1.806 +        const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
   1.807 +        filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS,
   1.808 +                             coefficients.Elements(), coefficients.Length());
   1.809 +        filter->SetInput(IN_ARITHMETIC_COMBINE_IN, aSources[0]);
   1.810 +        filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, aSources[1]);
   1.811 +      } else {
   1.812 +        filter = aDT->CreateFilter(FilterType::COMPOSITE);
   1.813 +        static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
   1.814 +          COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
   1.815 +          COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
   1.816 +          COMPOSITE_OPERATOR_IN,   // SVG_FECOMPOSITE_OPERATOR_IN
   1.817 +          COMPOSITE_OPERATOR_OUT,  // SVG_FECOMPOSITE_OPERATOR_OUT
   1.818 +          COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
   1.819 +          COMPOSITE_OPERATOR_XOR   // SVG_FECOMPOSITE_OPERATOR_XOR
   1.820 +        };
   1.821 +        filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)operators[op]);
   1.822 +        filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
   1.823 +        filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
   1.824 +      }
   1.825 +      return filter;
   1.826 +    }
   1.827 +
   1.828 +    case PrimitiveType::Merge:
   1.829 +    {
   1.830 +      if (aSources.Length() == 0) {
   1.831 +        return nullptr;
   1.832 +      }
   1.833 +      if (aSources.Length() == 1) {
   1.834 +        return aSources[0];
   1.835 +      }
   1.836 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
   1.837 +      filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
   1.838 +      for (size_t i = 0; i < aSources.Length(); i++) {
   1.839 +        filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
   1.840 +      }
   1.841 +      return filter;
   1.842 +    }
   1.843 +
   1.844 +    case PrimitiveType::GaussianBlur:
   1.845 +    {
   1.846 +      return FilterWrappers::GaussianBlur(aDT, aSources[0],
   1.847 +                                          atts.GetSize(eGaussianBlurStdDeviation));
   1.848 +    }
   1.849 +
   1.850 +    case PrimitiveType::DropShadow:
   1.851 +    {
   1.852 +      RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(aDT, aSources[0]);
   1.853 +      RefPtr<FilterNode> blur = FilterWrappers::GaussianBlur(aDT, alpha,
   1.854 +                                  atts.GetSize(eDropShadowStdDeviation));
   1.855 +      RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
   1.856 +                                        atts.GetIntPoint(eDropShadowOffset));
   1.857 +      RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
   1.858 +      Color color = atts.GetColor(eDropShadowColor);
   1.859 +      if (aDescription.InputColorSpace(0) == ColorSpace::LinearRGB) {
   1.860 +        color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
   1.861 +                      gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
   1.862 +                      gsRGBToLinearRGBMap[uint8_t(color.b * 255)],
   1.863 +                      color.a);
   1.864 +      }
   1.865 +      flood->SetAttribute(ATT_FLOOD_COLOR, color);
   1.866 +
   1.867 +      RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
   1.868 +      composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
   1.869 +      composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
   1.870 +      composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
   1.871 +
   1.872 +      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
   1.873 +      filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
   1.874 +      filter->SetInput(IN_COMPOSITE_IN_START, composite);
   1.875 +      filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
   1.876 +      return filter;
   1.877 +    }
   1.878 +
   1.879 +    case PrimitiveType::DiffuseLighting:
   1.880 +    case PrimitiveType::SpecularLighting:
   1.881 +    {
   1.882 +      bool isSpecular =
   1.883 +        aDescription.Type() == PrimitiveType::SpecularLighting;
   1.884 +
   1.885 +      AttributeMap lightAttributes = atts.GetAttributeMap(eLightingLight);
   1.886 +
   1.887 +      if (lightAttributes.GetUint(eLightType) == eLightTypeNone) {
   1.888 +        return nullptr;
   1.889 +      }
   1.890 +
   1.891 +      enum { POINT = 0, SPOT, DISTANT } lightType = POINT;
   1.892 +
   1.893 +      switch (lightAttributes.GetUint(eLightType)) {
   1.894 +        case eLightTypePoint:   lightType = POINT;   break;
   1.895 +        case eLightTypeSpot:    lightType = SPOT;    break;
   1.896 +        case eLightTypeDistant: lightType = DISTANT; break;
   1.897 +      }
   1.898 +
   1.899 +      static const FilterType filterType[2][DISTANT+1] = {
   1.900 +        { FilterType::POINT_DIFFUSE, FilterType::SPOT_DIFFUSE, FilterType::DISTANT_DIFFUSE },
   1.901 +        { FilterType::POINT_SPECULAR, FilterType::SPOT_SPECULAR, FilterType::DISTANT_SPECULAR }
   1.902 +      };
   1.903 +      RefPtr<FilterNode> filter =
   1.904 +        aDT->CreateFilter(filterType[isSpecular][lightType]);
   1.905 +
   1.906 +      filter->SetAttribute(ATT_LIGHTING_COLOR,
   1.907 +                           atts.GetColor(eLightingColor));
   1.908 +      filter->SetAttribute(ATT_LIGHTING_SURFACE_SCALE,
   1.909 +                           atts.GetFloat(eLightingSurfaceScale));
   1.910 +      filter->SetAttribute(ATT_LIGHTING_KERNEL_UNIT_LENGTH,
   1.911 +                           atts.GetSize(eLightingKernelUnitLength));
   1.912 +
   1.913 +      if (isSpecular) {
   1.914 +        filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
   1.915 +                             atts.GetFloat(eSpecularLightingSpecularConstant));
   1.916 +        filter->SetAttribute(ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT,
   1.917 +                             atts.GetFloat(eSpecularLightingSpecularExponent));
   1.918 +      } else {
   1.919 +        filter->SetAttribute(ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT,
   1.920 +                             atts.GetFloat(eDiffuseLightingDiffuseConstant));
   1.921 +      }
   1.922 +
   1.923 +      switch (lightType) {
   1.924 +        case POINT:
   1.925 +          filter->SetAttribute(ATT_POINT_LIGHT_POSITION,
   1.926 +                               lightAttributes.GetPoint3D(ePointLightPosition));
   1.927 +          break;
   1.928 +        case SPOT:
   1.929 +          filter->SetAttribute(ATT_SPOT_LIGHT_POSITION,
   1.930 +                               lightAttributes.GetPoint3D(eSpotLightPosition));
   1.931 +          filter->SetAttribute(ATT_SPOT_LIGHT_POINTS_AT,
   1.932 +                               lightAttributes.GetPoint3D(eSpotLightPointsAt));
   1.933 +          filter->SetAttribute(ATT_SPOT_LIGHT_FOCUS,
   1.934 +                               lightAttributes.GetFloat(eSpotLightFocus));
   1.935 +          filter->SetAttribute(ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,
   1.936 +                               lightAttributes.GetFloat(eSpotLightLimitingConeAngle));
   1.937 +          break;
   1.938 +        case DISTANT:
   1.939 +          filter->SetAttribute(ATT_DISTANT_LIGHT_AZIMUTH,
   1.940 +                               lightAttributes.GetFloat(eDistantLightAzimuth));
   1.941 +          filter->SetAttribute(ATT_DISTANT_LIGHT_ELEVATION,
   1.942 +                               lightAttributes.GetFloat(eDistantLightElevation));
   1.943 +          break;
   1.944 +      }
   1.945 +
   1.946 +      filter->SetInput(IN_LIGHTING_IN, aSources[0]);
   1.947 +
   1.948 +      return filter;
   1.949 +    }
   1.950 +
   1.951 +    case PrimitiveType::Image:
   1.952 +    {
   1.953 +      Matrix TM = atts.GetMatrix(eImageTransform);
   1.954 +      if (!TM.Determinant()) {
   1.955 +        return nullptr;
   1.956 +      }
   1.957 +
   1.958 +      // Pull the image from the additional image list using the index that's
   1.959 +      // stored in the primitive description.
   1.960 +      RefPtr<SourceSurface> inputImage =
   1.961 +        aInputImages[atts.GetUint(eImageInputIndex)];
   1.962 +
   1.963 +      RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
   1.964 +      transform->SetInput(IN_TRANSFORM_IN, inputImage);
   1.965 +      transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
   1.966 +      transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
   1.967 +      return transform;
   1.968 +    }
   1.969 +
   1.970 +    default:
   1.971 +      return nullptr;
   1.972 +  }
   1.973 +}
   1.974 +
   1.975 +template<typename T>
   1.976 +static const T&
   1.977 +ElementForIndex(int32_t aIndex,
   1.978 +                const nsTArray<T>& aPrimitiveElements,
   1.979 +                const T& aSourceGraphicElement,
   1.980 +                const T& aFillPaintElement,
   1.981 +                const T& aStrokePaintElement)
   1.982 +{
   1.983 +  switch (aIndex) {
   1.984 +    case FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic:
   1.985 +    case FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha:
   1.986 +      return aSourceGraphicElement;
   1.987 +    case FilterPrimitiveDescription::kPrimitiveIndexFillPaint:
   1.988 +      return aFillPaintElement;
   1.989 +    case FilterPrimitiveDescription::kPrimitiveIndexStrokePaint:
   1.990 +      return aStrokePaintElement;
   1.991 +    default:
   1.992 +      MOZ_ASSERT(aIndex >= 0, "bad index");
   1.993 +      return aPrimitiveElements[aIndex];
   1.994 +  }
   1.995 +}
   1.996 +
   1.997 +static AlphaModel
   1.998 +InputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
   1.999 +                            int32_t aInputIndex,
  1.1000 +                            AlphaModel aOriginalAlphaModel)
  1.1001 +{
  1.1002 +  switch (aDescr.Type()) {
  1.1003 +    case PrimitiveType::Tile:
  1.1004 +    case PrimitiveType::Offset:
  1.1005 +      return aOriginalAlphaModel;
  1.1006 +
  1.1007 +    case PrimitiveType::ColorMatrix:
  1.1008 +    case PrimitiveType::ComponentTransfer:
  1.1009 +      return AlphaModel::Unpremultiplied;
  1.1010 +
  1.1011 +    case PrimitiveType::DisplacementMap:
  1.1012 +      return aInputIndex == 0 ?
  1.1013 +        AlphaModel::Premultiplied : AlphaModel::Unpremultiplied;
  1.1014 +
  1.1015 +    case PrimitiveType::ConvolveMatrix:
  1.1016 +      return aDescr.Attributes().GetBool(eConvolveMatrixPreserveAlpha) ?
  1.1017 +        AlphaModel::Unpremultiplied : AlphaModel::Premultiplied;
  1.1018 +
  1.1019 +    default:
  1.1020 +      return AlphaModel::Premultiplied;
  1.1021 +  }
  1.1022 +}
  1.1023 +
  1.1024 +static AlphaModel
  1.1025 +OutputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
  1.1026 +                             const nsTArray<AlphaModel>& aInputAlphaModels)
  1.1027 +{
  1.1028 +  if (aInputAlphaModels.Length()) {
  1.1029 +    // For filters with inputs, the output is premultiplied if and only if the
  1.1030 +    // first input is premultiplied.
  1.1031 +    return InputAlphaModelForPrimitive(aDescr, 0, aInputAlphaModels[0]);
  1.1032 +  }
  1.1033 +
  1.1034 +  // All filters without inputs produce premultiplied alpha.
  1.1035 +  return AlphaModel::Premultiplied;
  1.1036 +}
  1.1037 +
  1.1038 +// Returns the output FilterNode, in premultiplied sRGB space.
  1.1039 +static TemporaryRef<FilterNode>
  1.1040 +FilterNodeGraphFromDescription(DrawTarget* aDT,
  1.1041 +                               const FilterDescription& aFilter,
  1.1042 +                               const Rect& aResultNeededRect,
  1.1043 +                               SourceSurface* aSourceGraphic,
  1.1044 +                               const IntRect& aSourceGraphicRect,
  1.1045 +                               SourceSurface* aFillPaint,
  1.1046 +                               const IntRect& aFillPaintRect,
  1.1047 +                               SourceSurface* aStrokePaint,
  1.1048 +                               const IntRect& aStrokePaintRect,
  1.1049 +                               nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
  1.1050 +{
  1.1051 +  const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1.1052 +  const IntRect& filterSpaceBounds = aFilter.mFilterSpaceBounds;
  1.1053 +
  1.1054 +  Rect resultNeededRect(aResultNeededRect);
  1.1055 +  resultNeededRect.RoundOut();
  1.1056 +
  1.1057 +  RefPtr<FilterCachedColorModels> sourceFilters[4];
  1.1058 +  nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters;
  1.1059 +
  1.1060 +  for (size_t i = 0; i < primitives.Length(); ++i) {
  1.1061 +    const FilterPrimitiveDescription& descr = primitives[i];
  1.1062 +
  1.1063 +    nsTArray<RefPtr<FilterNode> > inputFilterNodes;
  1.1064 +    nsTArray<IntRect> inputSourceRects;
  1.1065 +    nsTArray<AlphaModel> inputAlphaModels;
  1.1066 +
  1.1067 +    for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1.1068 +
  1.1069 +      int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1.1070 +      if (inputIndex < 0) {
  1.1071 +        inputSourceRects.AppendElement(filterSpaceBounds);
  1.1072 +      } else {
  1.1073 +        inputSourceRects.AppendElement(filterSpaceBounds.Intersect(
  1.1074 +          primitives[inputIndex].PrimitiveSubregion()));
  1.1075 +      }
  1.1076 +
  1.1077 +      RefPtr<FilterCachedColorModels> inputFilter;
  1.1078 +      if (inputIndex >= 0) {
  1.1079 +        MOZ_ASSERT(inputIndex < (int64_t)primitiveFilters.Length(), "out-of-bounds input index!");
  1.1080 +        inputFilter = primitiveFilters[inputIndex];
  1.1081 +        MOZ_ASSERT(inputFilter, "Referred to input filter that comes after the current one?");
  1.1082 +      } else {
  1.1083 +        int32_t sourceIndex = -inputIndex - 1;
  1.1084 +        MOZ_ASSERT(sourceIndex >= 0, "invalid source index");
  1.1085 +        MOZ_ASSERT(sourceIndex < 4, "invalid source index");
  1.1086 +        inputFilter = sourceFilters[sourceIndex];
  1.1087 +        if (!inputFilter) {
  1.1088 +          RefPtr<FilterNode> sourceFilterNode;
  1.1089 +
  1.1090 +          nsTArray<SourceSurface*> primitiveSurfaces;
  1.1091 +          nsTArray<IntRect> primitiveSurfaceRects;
  1.1092 +          RefPtr<SourceSurface> surf =
  1.1093 +            ElementForIndex(inputIndex, primitiveSurfaces,
  1.1094 +                            aSourceGraphic, aFillPaint, aStrokePaint);
  1.1095 +          IntRect surfaceRect =
  1.1096 +            ElementForIndex(inputIndex, primitiveSurfaceRects,
  1.1097 +                            aSourceGraphicRect, aFillPaintRect, aStrokePaintRect);
  1.1098 +          if (surf) {
  1.1099 +            IntPoint offset = surfaceRect.TopLeft();
  1.1100 +            sourceFilterNode = FilterWrappers::ForSurface(aDT, surf, offset);
  1.1101 +
  1.1102 +            if (inputIndex == FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha) {
  1.1103 +              sourceFilterNode = FilterWrappers::ToAlpha(aDT, sourceFilterNode);
  1.1104 +            }
  1.1105 +          }
  1.1106 +
  1.1107 +          inputFilter = new FilterCachedColorModels(aDT, sourceFilterNode,
  1.1108 +                                                    ColorModel::PremulSRGB());
  1.1109 +          sourceFilters[sourceIndex] = inputFilter;
  1.1110 +        }
  1.1111 +      }
  1.1112 +      MOZ_ASSERT(inputFilter);
  1.1113 +
  1.1114 +      AlphaModel inputAlphaModel =
  1.1115 +        InputAlphaModelForPrimitive(descr, j, inputFilter->OriginalAlphaModel());
  1.1116 +      inputAlphaModels.AppendElement(inputAlphaModel);
  1.1117 +      ColorModel inputColorModel(descr.InputColorSpace(j), inputAlphaModel);
  1.1118 +      inputFilterNodes.AppendElement(inputFilter->ForColorModel(inputColorModel));
  1.1119 +    }
  1.1120 +
  1.1121 +    RefPtr<FilterNode> primitiveFilterNode =
  1.1122 +      FilterNodeFromPrimitiveDescription(descr, aDT, inputFilterNodes,
  1.1123 +                                         inputSourceRects, aAdditionalImages);
  1.1124 +
  1.1125 +    if (primitiveFilterNode) {
  1.1126 +      IntRect cropRect = filterSpaceBounds.Intersect(descr.PrimitiveSubregion());
  1.1127 +      primitiveFilterNode = FilterWrappers::Crop(aDT, primitiveFilterNode, cropRect);
  1.1128 +    }
  1.1129 +
  1.1130 +    ColorModel outputColorModel(descr.OutputColorSpace(),
  1.1131 +      OutputAlphaModelForPrimitive(descr, inputAlphaModels));
  1.1132 +    RefPtr<FilterCachedColorModels> primitiveFilter =
  1.1133 +      new FilterCachedColorModels(aDT, primitiveFilterNode, outputColorModel);
  1.1134 +
  1.1135 +    primitiveFilters.AppendElement(primitiveFilter);
  1.1136 +  }
  1.1137 +
  1.1138 +  return primitiveFilters.LastElement()->ForColorModel(ColorModel::PremulSRGB());
  1.1139 +}
  1.1140 +
  1.1141 +// FilterSupport
  1.1142 +
  1.1143 +void
  1.1144 +FilterSupport::RenderFilterDescription(DrawTarget* aDT,
  1.1145 +                                       const FilterDescription& aFilter,
  1.1146 +                                       const Rect& aRenderRect,
  1.1147 +                                       SourceSurface* aSourceGraphic,
  1.1148 +                                       const IntRect& aSourceGraphicRect,
  1.1149 +                                       SourceSurface* aFillPaint,
  1.1150 +                                       const IntRect& aFillPaintRect,
  1.1151 +                                       SourceSurface* aStrokePaint,
  1.1152 +                                       const IntRect& aStrokePaintRect,
  1.1153 +                                       nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
  1.1154 +{
  1.1155 +  RefPtr<FilterNode> resultFilter =
  1.1156 +    FilterNodeGraphFromDescription(aDT, aFilter, aRenderRect,
  1.1157 +                                   aSourceGraphic, aSourceGraphicRect, aFillPaint, aFillPaintRect,
  1.1158 +                                   aStrokePaint, aStrokePaintRect, aAdditionalImages);
  1.1159 +
  1.1160 +  aDT->DrawFilter(resultFilter, aRenderRect, Point(0, 0));
  1.1161 +}
  1.1162 +
  1.1163 +static nsIntRegion
  1.1164 +UnionOfRegions(const nsTArray<nsIntRegion>& aRegions)
  1.1165 +{
  1.1166 +  nsIntRegion result;
  1.1167 +  for (size_t i = 0; i < aRegions.Length(); i++) {
  1.1168 +    result.Or(result, aRegions[i]);
  1.1169 +  }
  1.1170 +  return result;
  1.1171 +}
  1.1172 +
  1.1173 +static int32_t
  1.1174 +InflateSizeForBlurStdDev(float aStdDev)
  1.1175 +{
  1.1176 +  double size = std::min(aStdDev, kMaxStdDeviation) * (3 * sqrt(2 * M_PI) / 4) * 1.5;
  1.1177 +  return uint32_t(floor(size + 0.5));
  1.1178 +}
  1.1179 +
  1.1180 +static nsIntRegion
  1.1181 +ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
  1.1182 +                               const nsTArray<nsIntRegion>& aInputChangeRegions)
  1.1183 +{
  1.1184 +  const AttributeMap& atts = aDescription.Attributes();
  1.1185 +  switch (aDescription.Type()) {
  1.1186 +
  1.1187 +    case PrimitiveType::Empty:
  1.1188 +    case PrimitiveType::Flood:
  1.1189 +    case PrimitiveType::Turbulence:
  1.1190 +    case PrimitiveType::Image:
  1.1191 +      return nsIntRegion();
  1.1192 +
  1.1193 +    case PrimitiveType::Blend:
  1.1194 +    case PrimitiveType::Composite:
  1.1195 +    case PrimitiveType::Merge:
  1.1196 +      return UnionOfRegions(aInputChangeRegions);
  1.1197 +
  1.1198 +    case PrimitiveType::ColorMatrix:
  1.1199 +    case PrimitiveType::ComponentTransfer:
  1.1200 +      return aInputChangeRegions[0];
  1.1201 +
  1.1202 +    case PrimitiveType::Morphology:
  1.1203 +    {
  1.1204 +      Size radii = atts.GetSize(eMorphologyRadii);
  1.1205 +      int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
  1.1206 +      int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
  1.1207 +      return aInputChangeRegions[0].Inflated(nsIntMargin(ry, rx, ry, rx));
  1.1208 +    }
  1.1209 +
  1.1210 +    case PrimitiveType::Tile:
  1.1211 +      return ThebesIntRect(aDescription.PrimitiveSubregion());
  1.1212 +
  1.1213 +    case PrimitiveType::ConvolveMatrix:
  1.1214 +    {
  1.1215 +      Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
  1.1216 +      IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
  1.1217 +      IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
  1.1218 +      nsIntMargin m(ceil(kernelUnitLength.width * (target.x)),
  1.1219 +                    ceil(kernelUnitLength.height * (target.y)),
  1.1220 +                    ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
  1.1221 +                    ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)));
  1.1222 +      return aInputChangeRegions[0].Inflated(m);
  1.1223 +    }
  1.1224 +
  1.1225 +    case PrimitiveType::Offset:
  1.1226 +    {
  1.1227 +      IntPoint offset = atts.GetIntPoint(eOffsetOffset);
  1.1228 +      return aInputChangeRegions[0].MovedBy(offset.x, offset.y);
  1.1229 +    }
  1.1230 +
  1.1231 +    case PrimitiveType::DisplacementMap:
  1.1232 +    {
  1.1233 +      int32_t scale = ceil(abs(atts.GetFloat(eDisplacementMapScale)));
  1.1234 +      return aInputChangeRegions[0].Inflated(nsIntMargin(scale, scale, scale, scale));
  1.1235 +    }
  1.1236 +
  1.1237 +    case PrimitiveType::GaussianBlur:
  1.1238 +    {
  1.1239 +      Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
  1.1240 +      int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1.1241 +      int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1.1242 +      return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
  1.1243 +    }
  1.1244 +
  1.1245 +    case PrimitiveType::DropShadow:
  1.1246 +    {
  1.1247 +      IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
  1.1248 +      nsIntRegion offsetRegion = aInputChangeRegions[0].MovedBy(offset.x, offset.y);
  1.1249 +      Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
  1.1250 +      int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1.1251 +      int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1.1252 +      nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1.1253 +      blurRegion.Or(blurRegion, aInputChangeRegions[0]);
  1.1254 +      return blurRegion;
  1.1255 +    }
  1.1256 +
  1.1257 +    case PrimitiveType::DiffuseLighting:
  1.1258 +    case PrimitiveType::SpecularLighting:
  1.1259 +    {
  1.1260 +      Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
  1.1261 +      int32_t dx = ceil(kernelUnitLength.width);
  1.1262 +      int32_t dy = ceil(kernelUnitLength.height);
  1.1263 +      return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
  1.1264 +    }
  1.1265 +
  1.1266 +    default:
  1.1267 +      return nsIntRegion();
  1.1268 +  }
  1.1269 +}
  1.1270 +
  1.1271 +/* static */ nsIntRegion
  1.1272 +FilterSupport::ComputeResultChangeRegion(const FilterDescription& aFilter,
  1.1273 +                                         const nsIntRegion& aSourceGraphicChange,
  1.1274 +                                         const nsIntRegion& aFillPaintChange,
  1.1275 +                                         const nsIntRegion& aStrokePaintChange)
  1.1276 +{
  1.1277 +  const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1.1278 +  nsTArray<nsIntRegion> resultChangeRegions;
  1.1279 +
  1.1280 +  for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
  1.1281 +    const FilterPrimitiveDescription& descr = primitives[i];
  1.1282 +
  1.1283 +    nsTArray<nsIntRegion> inputChangeRegions;
  1.1284 +    for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1.1285 +      int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1.1286 +      MOZ_ASSERT(inputIndex < i, "bad input index");
  1.1287 +      nsIntRegion inputChangeRegion =
  1.1288 +        ElementForIndex(inputIndex, resultChangeRegions,
  1.1289 +                        aSourceGraphicChange, aFillPaintChange,
  1.1290 +                        aStrokePaintChange);
  1.1291 +      inputChangeRegions.AppendElement(inputChangeRegion);
  1.1292 +    }
  1.1293 +    nsIntRegion changeRegion =
  1.1294 +      ResultChangeRegionForPrimitive(descr, inputChangeRegions);
  1.1295 +    IntRect cropRect =
  1.1296 +      descr.PrimitiveSubregion().Intersect(aFilter.mFilterSpaceBounds);
  1.1297 +    changeRegion.And(changeRegion, ThebesIntRect(cropRect));
  1.1298 +    resultChangeRegions.AppendElement(changeRegion);
  1.1299 +  }
  1.1300 +
  1.1301 +  return resultChangeRegions[resultChangeRegions.Length() - 1];
  1.1302 +}
  1.1303 +
  1.1304 +static nsIntRegion
  1.1305 +PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& aDescription,
  1.1306 +                              const nsTArray<nsIntRegion>& aInputExtents)
  1.1307 +{
  1.1308 +  const AttributeMap& atts = aDescription.Attributes();
  1.1309 +  switch (aDescription.Type()) {
  1.1310 +
  1.1311 +    case PrimitiveType::Empty:
  1.1312 +      return nsIntRect();
  1.1313 +
  1.1314 +    case PrimitiveType::Composite:
  1.1315 +    {
  1.1316 +      uint32_t op = atts.GetUint(eCompositeOperator);
  1.1317 +      if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
  1.1318 +        // The arithmetic composite primitive can draw outside the bounding
  1.1319 +        // box of its source images.
  1.1320 +        const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
  1.1321 +        MOZ_ASSERT(coefficients.Length() == 4);
  1.1322 +
  1.1323 +        // The calculation is:
  1.1324 +        // r = c[0] * in[0] * in[1] + c[1] * in[0] + c[2] * in[1] + c[3]
  1.1325 +        nsIntRegion region;
  1.1326 +        if (coefficients[0] > 0.0f) {
  1.1327 +          region = aInputExtents[0].Intersect(aInputExtents[1]);
  1.1328 +        }
  1.1329 +        if (coefficients[1] > 0.0f) {
  1.1330 +          region.Or(region, aInputExtents[0]);
  1.1331 +        }
  1.1332 +        if (coefficients[2] > 0.0f) {
  1.1333 +          region.Or(region, aInputExtents[1]);
  1.1334 +        }
  1.1335 +        if (coefficients[3] > 0.0f) {
  1.1336 +          region = ThebesIntRect(aDescription.PrimitiveSubregion());
  1.1337 +        }
  1.1338 +        return region;
  1.1339 +      }
  1.1340 +      if (op == SVG_FECOMPOSITE_OPERATOR_IN) {
  1.1341 +        return aInputExtents[0].Intersect(aInputExtents[1]);
  1.1342 +      }
  1.1343 +      return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
  1.1344 +    }
  1.1345 +
  1.1346 +    case PrimitiveType::Flood:
  1.1347 +    {
  1.1348 +      if (atts.GetColor(eFloodColor).a == 0.0f) {
  1.1349 +        return nsIntRect();
  1.1350 +      }
  1.1351 +      return ThebesIntRect(aDescription.PrimitiveSubregion());
  1.1352 +    }
  1.1353 +
  1.1354 +    case PrimitiveType::Turbulence:
  1.1355 +    case PrimitiveType::Image:
  1.1356 +    {
  1.1357 +      return ThebesIntRect(aDescription.PrimitiveSubregion());
  1.1358 +    }
  1.1359 +
  1.1360 +    case PrimitiveType::Morphology:
  1.1361 +    {
  1.1362 +      uint32_t op = atts.GetUint(eMorphologyOperator);
  1.1363 +      if (op == SVG_OPERATOR_ERODE) {
  1.1364 +        return aInputExtents[0];
  1.1365 +      }
  1.1366 +      Size radii = atts.GetSize(eMorphologyRadii);
  1.1367 +      int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
  1.1368 +      int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
  1.1369 +      return aInputExtents[0].Inflated(nsIntMargin(ry, rx, ry, rx));
  1.1370 +    }
  1.1371 +
  1.1372 +    default:
  1.1373 +      return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
  1.1374 +  }
  1.1375 +}
  1.1376 +
  1.1377 +/* static */ nsIntRegion
  1.1378 +FilterSupport::ComputePostFilterExtents(const FilterDescription& aFilter,
  1.1379 +                                        const nsIntRegion& aSourceGraphicExtents)
  1.1380 +{
  1.1381 +  const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1.1382 +  nsIntRegion filterSpace = ThebesIntRect(aFilter.mFilterSpaceBounds);
  1.1383 +  nsTArray<nsIntRegion> postFilterExtents;
  1.1384 +
  1.1385 +  for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
  1.1386 +    const FilterPrimitiveDescription& descr = primitives[i];
  1.1387 +
  1.1388 +    nsTArray<nsIntRegion> inputExtents;
  1.1389 +    for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1.1390 +      int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1.1391 +      MOZ_ASSERT(inputIndex < i, "bad input index");
  1.1392 +      nsIntRegion inputExtent =
  1.1393 +        ElementForIndex(inputIndex, postFilterExtents,
  1.1394 +                        aSourceGraphicExtents, filterSpace, filterSpace);
  1.1395 +      inputExtents.AppendElement(inputExtent);
  1.1396 +    }
  1.1397 +    nsIntRegion extent = PostFilterExtentsForPrimitive(descr, inputExtents);
  1.1398 +    IntRect cropRect =
  1.1399 +      descr.PrimitiveSubregion().Intersect(aFilter.mFilterSpaceBounds);
  1.1400 +    extent.And(extent, ThebesIntRect(cropRect));
  1.1401 +    postFilterExtents.AppendElement(extent);
  1.1402 +  }
  1.1403 +
  1.1404 +  return postFilterExtents[postFilterExtents.Length() - 1];
  1.1405 +}
  1.1406 +
  1.1407 +static nsIntRegion
  1.1408 +SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
  1.1409 +                               const nsIntRegion& aResultNeededRegion,
  1.1410 +                               int32_t aInputIndex)
  1.1411 +{
  1.1412 +  const AttributeMap& atts = aDescription.Attributes();
  1.1413 +  switch (aDescription.Type()) {
  1.1414 +
  1.1415 +    case PrimitiveType::Flood:
  1.1416 +    case PrimitiveType::Turbulence:
  1.1417 +    case PrimitiveType::Image:
  1.1418 +      MOZ_CRASH("this shouldn't be called for filters without inputs");
  1.1419 +      return nsIntRegion();
  1.1420 +
  1.1421 +    case PrimitiveType::Empty:
  1.1422 +      return nsIntRegion();
  1.1423 +
  1.1424 +    case PrimitiveType::Blend:
  1.1425 +    case PrimitiveType::Composite:
  1.1426 +    case PrimitiveType::Merge:
  1.1427 +    case PrimitiveType::ColorMatrix:
  1.1428 +    case PrimitiveType::ComponentTransfer:
  1.1429 +      return aResultNeededRegion;
  1.1430 +
  1.1431 +    case PrimitiveType::Morphology:
  1.1432 +    {
  1.1433 +      Size radii = atts.GetSize(eMorphologyRadii);
  1.1434 +      int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
  1.1435 +      int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
  1.1436 +      return aResultNeededRegion.Inflated(nsIntMargin(ry, rx, ry, rx));
  1.1437 +    }
  1.1438 +
  1.1439 +    case PrimitiveType::Tile:
  1.1440 +      return nsIntRect(INT32_MIN/2, INT32_MIN/2, INT32_MAX, INT32_MAX);
  1.1441 +
  1.1442 +    case PrimitiveType::ConvolveMatrix:
  1.1443 +    {
  1.1444 +      Size kernelUnitLength = atts.GetSize(eConvolveMatrixKernelUnitLength);
  1.1445 +      IntSize kernelSize = atts.GetIntSize(eConvolveMatrixKernelSize);
  1.1446 +      IntPoint target = atts.GetIntPoint(eConvolveMatrixTarget);
  1.1447 +      nsIntMargin m(ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
  1.1448 +                    ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)),
  1.1449 +                    ceil(kernelUnitLength.width * (target.x)),
  1.1450 +                    ceil(kernelUnitLength.height * (target.y)));
  1.1451 +      return aResultNeededRegion.Inflated(m);
  1.1452 +    }
  1.1453 +
  1.1454 +    case PrimitiveType::Offset:
  1.1455 +    {
  1.1456 +      IntPoint offset = atts.GetIntPoint(eOffsetOffset);
  1.1457 +      return aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
  1.1458 +    }
  1.1459 +
  1.1460 +    case PrimitiveType::DisplacementMap:
  1.1461 +    {
  1.1462 +      if (aInputIndex == 1) {
  1.1463 +        return aResultNeededRegion;
  1.1464 +      }
  1.1465 +      int32_t scale = ceil(abs(atts.GetFloat(eDisplacementMapScale)));
  1.1466 +      return aResultNeededRegion.Inflated(nsIntMargin(scale, scale, scale, scale));
  1.1467 +    }
  1.1468 +
  1.1469 +    case PrimitiveType::GaussianBlur:
  1.1470 +    {
  1.1471 +      Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
  1.1472 +      int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1.1473 +      int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1.1474 +      return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1.1475 +    }
  1.1476 +
  1.1477 +    case PrimitiveType::DropShadow:
  1.1478 +    {
  1.1479 +      IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
  1.1480 +      nsIntRegion offsetRegion =
  1.1481 +        aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
  1.1482 +      Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
  1.1483 +      int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
  1.1484 +      int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
  1.1485 +      nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1.1486 +      blurRegion.Or(blurRegion, aResultNeededRegion);
  1.1487 +      return blurRegion;
  1.1488 +    }
  1.1489 +
  1.1490 +    case PrimitiveType::DiffuseLighting:
  1.1491 +    case PrimitiveType::SpecularLighting:
  1.1492 +    {
  1.1493 +      Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
  1.1494 +      int32_t dx = ceil(kernelUnitLength.width);
  1.1495 +      int32_t dy = ceil(kernelUnitLength.height);
  1.1496 +      return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
  1.1497 +    }
  1.1498 +
  1.1499 +    default:
  1.1500 +      return nsIntRegion();
  1.1501 +  }
  1.1502 +
  1.1503 +}
  1.1504 +
  1.1505 +/* static */ void
  1.1506 +FilterSupport::ComputeSourceNeededRegions(const FilterDescription& aFilter,
  1.1507 +                                          const nsIntRegion& aResultNeededRegion,
  1.1508 +                                          nsIntRegion& aSourceGraphicNeededRegion,
  1.1509 +                                          nsIntRegion& aFillPaintNeededRegion,
  1.1510 +                                          nsIntRegion& aStrokePaintNeededRegion)
  1.1511 +{
  1.1512 +  const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
  1.1513 +  nsTArray<nsIntRegion> primitiveNeededRegions;
  1.1514 +  primitiveNeededRegions.AppendElements(primitives.Length());
  1.1515 +
  1.1516 +  primitiveNeededRegions[primitives.Length() - 1] = aResultNeededRegion;
  1.1517 +
  1.1518 +  for (int32_t i = primitives.Length() - 1; i >= 0; --i) {
  1.1519 +    const FilterPrimitiveDescription& descr = primitives[i];
  1.1520 +    nsIntRegion neededRegion = primitiveNeededRegions[i];
  1.1521 +    neededRegion.And(neededRegion, ThebesIntRect(descr.PrimitiveSubregion()));
  1.1522 +
  1.1523 +    for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
  1.1524 +      int32_t inputIndex = descr.InputPrimitiveIndex(j);
  1.1525 +      MOZ_ASSERT(inputIndex < i, "bad input index");
  1.1526 +      nsIntRegion* inputNeededRegion = const_cast<nsIntRegion*>(
  1.1527 +        &ElementForIndex(inputIndex, primitiveNeededRegions,
  1.1528 +                         aSourceGraphicNeededRegion,
  1.1529 +                         aFillPaintNeededRegion, aStrokePaintNeededRegion));
  1.1530 +      inputNeededRegion->Or(*inputNeededRegion,
  1.1531 +        SourceNeededRegionForPrimitive(descr, neededRegion, j));
  1.1532 +    }
  1.1533 +  }
  1.1534 +
  1.1535 +  aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
  1.1536 +                                 ThebesIntRect(aFilter.mFilterSpaceBounds));
  1.1537 +}
  1.1538 +
  1.1539 +// FilterPrimitiveDescription
  1.1540 +
  1.1541 +FilterPrimitiveDescription::FilterPrimitiveDescription()
  1.1542 + : mType(PrimitiveType::Empty)
  1.1543 + , mOutputColorSpace(ColorSpace::SRGB)
  1.1544 + , mIsTainted(false)
  1.1545 +{
  1.1546 +}
  1.1547 +
  1.1548 +FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType)
  1.1549 + : mType(aType)
  1.1550 + , mOutputColorSpace(ColorSpace::SRGB)
  1.1551 + , mIsTainted(false)
  1.1552 +{
  1.1553 +}
  1.1554 +
  1.1555 +FilterPrimitiveDescription::FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther)
  1.1556 + : mType(aOther.mType)
  1.1557 + , mAttributes(aOther.mAttributes)
  1.1558 + , mInputPrimitives(aOther.mInputPrimitives)
  1.1559 + , mFilterPrimitiveSubregion(aOther.mFilterPrimitiveSubregion)
  1.1560 + , mInputColorSpaces(aOther.mInputColorSpaces)
  1.1561 + , mOutputColorSpace(aOther.mOutputColorSpace)
  1.1562 + , mIsTainted(aOther.mIsTainted)
  1.1563 +{
  1.1564 +}
  1.1565 +
  1.1566 +FilterPrimitiveDescription&
  1.1567 +FilterPrimitiveDescription::operator=(const FilterPrimitiveDescription& aOther)
  1.1568 +{
  1.1569 +  if (this != &aOther) {
  1.1570 +    mType = aOther.mType;
  1.1571 +    mAttributes = aOther.mAttributes;
  1.1572 +    mInputPrimitives = aOther.mInputPrimitives;
  1.1573 +    mFilterPrimitiveSubregion = aOther.mFilterPrimitiveSubregion;
  1.1574 +    mInputColorSpaces = aOther.mInputColorSpaces;
  1.1575 +    mOutputColorSpace = aOther.mOutputColorSpace;
  1.1576 +    mIsTainted = aOther.mIsTainted;
  1.1577 +  }
  1.1578 +  return *this;
  1.1579 +}
  1.1580 +
  1.1581 +bool
  1.1582 +FilterPrimitiveDescription::operator==(const FilterPrimitiveDescription& aOther) const
  1.1583 +{
  1.1584 +  return mType == aOther.mType &&
  1.1585 +    mFilterPrimitiveSubregion.IsEqualInterior(aOther.mFilterPrimitiveSubregion) &&
  1.1586 +    mOutputColorSpace == aOther.mOutputColorSpace &&
  1.1587 +    mIsTainted == aOther.mIsTainted &&
  1.1588 +    mInputPrimitives == aOther.mInputPrimitives &&
  1.1589 +    mInputColorSpaces == aOther.mInputColorSpaces &&
  1.1590 +    mAttributes == aOther.mAttributes;
  1.1591 +}
  1.1592 +
  1.1593 +// FilterDescription
  1.1594 +
  1.1595 +bool
  1.1596 +FilterDescription::operator==(const FilterDescription& aOther) const
  1.1597 +{
  1.1598 +  return mFilterSpaceBounds.IsEqualInterior(aOther.mFilterSpaceBounds) &&
  1.1599 +    mPrimitives == aOther.mPrimitives;
  1.1600 +}
  1.1601 +
  1.1602 +// AttributeMap
  1.1603 +
  1.1604 +// A class that wraps different types for easy storage in a hashtable. Only
  1.1605 +// used by AttributeMap.
  1.1606 +struct FilterAttribute {
  1.1607 +  FilterAttribute(const FilterAttribute& aOther);
  1.1608 +  ~FilterAttribute();
  1.1609 +
  1.1610 +  bool operator==(const FilterAttribute& aOther) const;
  1.1611 +  bool operator!=(const FilterAttribute& aOther) const
  1.1612 +  {
  1.1613 +    return !(*this == aOther);
  1.1614 +  }
  1.1615 +
  1.1616 +  AttributeType Type() const { return mType; }
  1.1617 +
  1.1618 +#define MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(type, typeLabel)   \
  1.1619 +  FilterAttribute(type aValue)                                 \
  1.1620 +   : mType(AttributeType::e##typeLabel), m##typeLabel(aValue)  \
  1.1621 +  {}                                                           \
  1.1622 +  type As##typeLabel() {                                       \
  1.1623 +    MOZ_ASSERT(mType == AttributeType::e##typeLabel);          \
  1.1624 +    return m##typeLabel;                                       \
  1.1625 +  }
  1.1626 +
  1.1627 +#define MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(className)         \
  1.1628 +  FilterAttribute(const className& aValue)                     \
  1.1629 +   : mType(AttributeType::e##className), m##className(new className(aValue)) \
  1.1630 +  {}                                                           \
  1.1631 +  className As##className() {                                  \
  1.1632 +    MOZ_ASSERT(mType == AttributeType::e##className);          \
  1.1633 +    return *m##className;                                      \
  1.1634 +  }
  1.1635 +
  1.1636 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(bool, Bool)
  1.1637 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(uint32_t, Uint)
  1.1638 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC(float, Float)
  1.1639 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Size)
  1.1640 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntSize)
  1.1641 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(IntPoint)
  1.1642 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix)
  1.1643 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Matrix5x4)
  1.1644 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Point3D)
  1.1645 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(Color)
  1.1646 +  MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS(AttributeMap)
  1.1647 +
  1.1648 +#undef MAKE_CONSTRUCTOR_AND_ACCESSOR_BASIC
  1.1649 +#undef MAKE_CONSTRUCTOR_AND_ACCESSOR_CLASS
  1.1650 +
  1.1651 +  FilterAttribute(const float* aValue, uint32_t aLength)
  1.1652 +   : mType(AttributeType::eFloats)
  1.1653 +  {
  1.1654 +    mFloats = new nsTArray<float>();
  1.1655 +    mFloats->AppendElements(aValue, aLength);
  1.1656 +  }
  1.1657 +
  1.1658 +  const nsTArray<float>& AsFloats() const {
  1.1659 +    MOZ_ASSERT(mType == AttributeType::eFloats);
  1.1660 +    return *mFloats;
  1.1661 +  }
  1.1662 +
  1.1663 +private:
  1.1664 +  const AttributeType mType;
  1.1665 +
  1.1666 +  union {
  1.1667 +    bool mBool;
  1.1668 +    uint32_t mUint;
  1.1669 +    float mFloat;
  1.1670 +    Size* mSize;
  1.1671 +    IntSize* mIntSize;
  1.1672 +    IntPoint* mIntPoint;
  1.1673 +    Matrix* mMatrix;
  1.1674 +    Matrix5x4* mMatrix5x4;
  1.1675 +    Point3D* mPoint3D;
  1.1676 +    Color* mColor;
  1.1677 +    AttributeMap* mAttributeMap;
  1.1678 +    nsTArray<float>* mFloats;
  1.1679 +  };
  1.1680 +};
  1.1681 +
  1.1682 +FilterAttribute::FilterAttribute(const FilterAttribute& aOther)
  1.1683 + : mType(aOther.mType)
  1.1684 +{
  1.1685 +  switch (mType) {
  1.1686 +    case AttributeType::eBool:
  1.1687 +      mBool = aOther.mBool;
  1.1688 +      break;
  1.1689 +    case AttributeType::eUint:
  1.1690 +      mUint = aOther.mUint;
  1.1691 +      break;
  1.1692 +    case AttributeType::eFloat:
  1.1693 +      mFloat = aOther.mFloat;
  1.1694 +      break;
  1.1695 +
  1.1696 +#define HANDLE_CLASS(className)                            \
  1.1697 +    case AttributeType::e##className:                      \
  1.1698 +      m##className = new className(*aOther.m##className);  \
  1.1699 +      break;
  1.1700 +
  1.1701 +    HANDLE_CLASS(Size)
  1.1702 +    HANDLE_CLASS(IntSize)
  1.1703 +    HANDLE_CLASS(IntPoint)
  1.1704 +    HANDLE_CLASS(Matrix)
  1.1705 +    HANDLE_CLASS(Matrix5x4)
  1.1706 +    HANDLE_CLASS(Point3D)
  1.1707 +    HANDLE_CLASS(Color)
  1.1708 +    HANDLE_CLASS(AttributeMap)
  1.1709 +
  1.1710 +#undef HANDLE_CLASS
  1.1711 +
  1.1712 +    case AttributeType::eFloats:
  1.1713 +      mFloats = new nsTArray<float>(*aOther.mFloats);
  1.1714 +      break;
  1.1715 +    case AttributeType::Max:
  1.1716 +      break;
  1.1717 +  }
  1.1718 +}
  1.1719 +
  1.1720 +FilterAttribute::~FilterAttribute() {
  1.1721 +  switch (mType) {
  1.1722 +    case AttributeType::Max:
  1.1723 +    case AttributeType::eBool:
  1.1724 +    case AttributeType::eUint:
  1.1725 +    case AttributeType::eFloat:
  1.1726 +      break;
  1.1727 +
  1.1728 +#define HANDLE_CLASS(className)                            \
  1.1729 +    case AttributeType::e##className:                      \
  1.1730 +      delete m##className;                                 \
  1.1731 +      break;
  1.1732 +
  1.1733 +    HANDLE_CLASS(Size)
  1.1734 +    HANDLE_CLASS(IntSize)
  1.1735 +    HANDLE_CLASS(IntPoint)
  1.1736 +    HANDLE_CLASS(Matrix)
  1.1737 +    HANDLE_CLASS(Matrix5x4)
  1.1738 +    HANDLE_CLASS(Point3D)
  1.1739 +    HANDLE_CLASS(Color)
  1.1740 +    HANDLE_CLASS(AttributeMap)
  1.1741 +
  1.1742 +#undef HANDLE_CLASS
  1.1743 +
  1.1744 +    case AttributeType::eFloats:
  1.1745 +      delete mFloats;
  1.1746 +      break;
  1.1747 +  }
  1.1748 +}
  1.1749 +
  1.1750 +bool
  1.1751 +FilterAttribute::operator==(const FilterAttribute& aOther) const
  1.1752 +{
  1.1753 +  if (mType != aOther.mType) {
  1.1754 +    return false;
  1.1755 +  }
  1.1756 +
  1.1757 +  switch (mType) {
  1.1758 +
  1.1759 +#define HANDLE_TYPE(typeName)                              \
  1.1760 +    case AttributeType::e##typeName:                       \
  1.1761 +      return m##typeName == aOther.m##typeName;
  1.1762 +
  1.1763 +    HANDLE_TYPE(Bool)
  1.1764 +    HANDLE_TYPE(Uint)
  1.1765 +    HANDLE_TYPE(Float)
  1.1766 +    HANDLE_TYPE(Size)
  1.1767 +    HANDLE_TYPE(IntSize)
  1.1768 +    HANDLE_TYPE(IntPoint)
  1.1769 +    HANDLE_TYPE(Matrix)
  1.1770 +    HANDLE_TYPE(Matrix5x4)
  1.1771 +    HANDLE_TYPE(Point3D)
  1.1772 +    HANDLE_TYPE(Color)
  1.1773 +    HANDLE_TYPE(AttributeMap)
  1.1774 +    HANDLE_TYPE(Floats)
  1.1775 +
  1.1776 +#undef HANDLE_TYPE
  1.1777 +
  1.1778 +    default:
  1.1779 +      return false;
  1.1780 +  }
  1.1781 +}
  1.1782 +
  1.1783 +typedef FilterAttribute Attribute;
  1.1784 +
  1.1785 +AttributeMap::AttributeMap()
  1.1786 +{
  1.1787 +}
  1.1788 +
  1.1789 +AttributeMap::~AttributeMap()
  1.1790 +{
  1.1791 +}
  1.1792 +
  1.1793 +static PLDHashOperator
  1.1794 +CopyAttribute(const uint32_t& aAttributeName,
  1.1795 +              Attribute* aAttribute,
  1.1796 +              void* aAttributes)
  1.1797 +{
  1.1798 +  typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
  1.1799 +  Map* map = static_cast<Map*>(aAttributes);
  1.1800 +  map->Put(aAttributeName, new Attribute(*aAttribute));
  1.1801 +  return PL_DHASH_NEXT;
  1.1802 +}
  1.1803 +
  1.1804 +AttributeMap::AttributeMap(const AttributeMap& aOther)
  1.1805 +{
  1.1806 +  aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
  1.1807 +}
  1.1808 +
  1.1809 +AttributeMap&
  1.1810 +AttributeMap::operator=(const AttributeMap& aOther)
  1.1811 +{
  1.1812 +  if (this != &aOther) {
  1.1813 +    mMap.Clear();
  1.1814 +    aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
  1.1815 +  }
  1.1816 +  return *this;
  1.1817 +}
  1.1818 +
  1.1819 +namespace {
  1.1820 +  struct MatchingMap {
  1.1821 +    typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
  1.1822 +    const Map& map;
  1.1823 +    bool matches;
  1.1824 +  };
  1.1825 +}
  1.1826 +
  1.1827 +static PLDHashOperator
  1.1828 +CheckAttributeEquality(const uint32_t& aAttributeName,
  1.1829 +                       Attribute* aAttribute,
  1.1830 +                       void* aMatchingMap)
  1.1831 +{
  1.1832 +  MatchingMap& matchingMap = *static_cast<MatchingMap*>(aMatchingMap);
  1.1833 +  Attribute* matchingAttribute = matchingMap.map.Get(aAttributeName);
  1.1834 +  if (!matchingAttribute ||
  1.1835 +      *matchingAttribute != *aAttribute) {
  1.1836 +    matchingMap.matches = false;
  1.1837 +    return PL_DHASH_STOP;
  1.1838 +  }
  1.1839 +  return PL_DHASH_NEXT;
  1.1840 +}
  1.1841 +
  1.1842 +bool
  1.1843 +AttributeMap::operator==(const AttributeMap& aOther) const
  1.1844 +{
  1.1845 +  if (mMap.Count() != aOther.mMap.Count()) {
  1.1846 +    return false;
  1.1847 +  }
  1.1848 +
  1.1849 +  MatchingMap matchingMap = { mMap, true };
  1.1850 +  aOther.mMap.EnumerateRead(CheckAttributeEquality, &matchingMap);
  1.1851 +  return matchingMap.matches;
  1.1852 +}
  1.1853 +
  1.1854 +namespace {
  1.1855 +  struct HandlerWithUserData
  1.1856 +  {
  1.1857 +    AttributeMap::AttributeHandleCallback handler;
  1.1858 +    void* userData;
  1.1859 +  };
  1.1860 +}
  1.1861 +
  1.1862 +static PLDHashOperator
  1.1863 +PassAttributeToHandleCallback(const uint32_t& aAttributeName,
  1.1864 +                              Attribute* aAttribute,
  1.1865 +                              void* aHandlerWithUserData)
  1.1866 +{
  1.1867 +  HandlerWithUserData* handlerWithUserData =
  1.1868 +    static_cast<HandlerWithUserData*>(aHandlerWithUserData);
  1.1869 +  return handlerWithUserData->handler(AttributeName(aAttributeName),
  1.1870 +                                      aAttribute->Type(),
  1.1871 +                                      handlerWithUserData->userData) ?
  1.1872 +    PL_DHASH_NEXT : PL_DHASH_STOP;
  1.1873 +}
  1.1874 +
  1.1875 +void
  1.1876 +AttributeMap::EnumerateRead(AttributeMap::AttributeHandleCallback aCallback, void* aUserData) const
  1.1877 +{
  1.1878 +  HandlerWithUserData handlerWithUserData = { aCallback, aUserData };
  1.1879 +  mMap.EnumerateRead(PassAttributeToHandleCallback, &handlerWithUserData);
  1.1880 +}
  1.1881 +
  1.1882 +uint32_t
  1.1883 +AttributeMap::Count() const
  1.1884 +{
  1.1885 +  return mMap.Count();
  1.1886 +}
  1.1887 +
  1.1888 +#define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \
  1.1889 +  type                                                               \
  1.1890 +  AttributeMap::Get##typeLabel(AttributeName aName) const {          \
  1.1891 +    Attribute* value = mMap.Get(aName);                              \
  1.1892 +    return value ? value->As##typeLabel() : defaultValue;            \
  1.1893 +  }                                                                  \
  1.1894 +  void                                                               \
  1.1895 +  AttributeMap::Set(AttributeName aName, type aValue) {              \
  1.1896 +    mMap.Remove(aName);                                              \
  1.1897 +    mMap.Put(aName, new Attribute(aValue));                          \
  1.1898 +  }
  1.1899 +
  1.1900 +#define MAKE_ATTRIBUTE_HANDLERS_CLASS(className)                     \
  1.1901 +  className                                                          \
  1.1902 +  AttributeMap::Get##className(AttributeName aName) const {          \
  1.1903 +    Attribute* value = mMap.Get(aName);                              \
  1.1904 +    return value ? value->As##className() : className();             \
  1.1905 +  }                                                                  \
  1.1906 +  void                                                               \
  1.1907 +  AttributeMap::Set(AttributeName aName, const className& aValue) {  \
  1.1908 +    mMap.Remove(aName);                                              \
  1.1909 +    mMap.Put(aName, new Attribute(aValue));                          \
  1.1910 +  }
  1.1911 +
  1.1912 +MAKE_ATTRIBUTE_HANDLERS_BASIC(bool, Bool, false)
  1.1913 +MAKE_ATTRIBUTE_HANDLERS_BASIC(uint32_t, Uint, 0)
  1.1914 +MAKE_ATTRIBUTE_HANDLERS_BASIC(float, Float, 0)
  1.1915 +MAKE_ATTRIBUTE_HANDLERS_CLASS(Size)
  1.1916 +MAKE_ATTRIBUTE_HANDLERS_CLASS(IntSize)
  1.1917 +MAKE_ATTRIBUTE_HANDLERS_CLASS(IntPoint)
  1.1918 +MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix)
  1.1919 +MAKE_ATTRIBUTE_HANDLERS_CLASS(Matrix5x4)
  1.1920 +MAKE_ATTRIBUTE_HANDLERS_CLASS(Point3D)
  1.1921 +MAKE_ATTRIBUTE_HANDLERS_CLASS(Color)
  1.1922 +MAKE_ATTRIBUTE_HANDLERS_CLASS(AttributeMap)
  1.1923 +
  1.1924 +#undef MAKE_ATTRIBUTE_HANDLERS_BASIC
  1.1925 +#undef MAKE_ATTRIBUTE_HANDLERS_CLASS
  1.1926 +
  1.1927 +const nsTArray<float>&
  1.1928 +AttributeMap::GetFloats(AttributeName aName) const
  1.1929 +{
  1.1930 +  Attribute* value = mMap.Get(aName);
  1.1931 +  if (!value) {
  1.1932 +    value = new Attribute(nullptr, 0);
  1.1933 +    mMap.Put(aName, value);
  1.1934 +  }
  1.1935 +  return value->AsFloats();
  1.1936 +}
  1.1937 +
  1.1938 +void
  1.1939 +AttributeMap::Set(AttributeName aName, const float* aValues, int32_t aLength)
  1.1940 +{
  1.1941 +  mMap.Remove(aName);
  1.1942 +  mMap.Put(aName, new Attribute(aValues, aLength));
  1.1943 +}
  1.1944 +
  1.1945 +}
  1.1946 +}

mercurial