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 +}