gfx/2d/FilterNodeSoftware.cpp

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

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

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

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #define _USE_MATH_DEFINES
     8 #include <cmath>
     9 #include "FilterNodeSoftware.h"
    10 #include "2D.h"
    11 #include "Tools.h"
    12 #include "Blur.h"
    13 #include <map>
    14 #include "FilterProcessing.h"
    15 #include "mozilla/PodOperations.h"
    16 #include "mozilla/DebugOnly.h"
    18 // #define DEBUG_DUMP_SURFACES
    20 #ifdef DEBUG_DUMP_SURFACES
    21 #include "gfxImageSurface.h"
    22 namespace mozilla {
    23 namespace gfx {
    24 static void
    25 DumpAsPNG(SourceSurface* aSurface)
    26 {
    27   RefPtr<DataSourceSurface> dataSource = aSurface->GetDataSurface();
    28   IntSize size = dataSource->GetSize();
    29   nsRefPtr<gfxImageSurface> imageSurface =
    30     new gfxImageSurface(dataSource->GetData(), gfxIntSize(size.width, size.height),
    31                         dataSource->Stride(),
    32                         aSurface->GetFormat() == SurfaceFormat::A8 ? gfxImageFormat::A8 : gfxImageFormat::ARGB32);
    33   imageSurface->PrintAsDataURL();
    34 }
    35 } // namespace gfx
    36 } // namespace mozilla
    37 #endif
    39 namespace mozilla {
    40 namespace gfx {
    42 namespace {
    44 /**
    45  * This class provides a way to get a pow() results in constant-time. It works
    46  * by caching 256 values for bases between 0 and 1 and a fixed exponent.
    47  **/
    48 class PowCache
    49 {
    50 public:
    51   PowCache()
    52   {
    53     CacheForExponent(0.0f);
    54   }
    56   void CacheForExponent(Float aExponent)
    57   {
    58     mExponent = aExponent;
    59     int numPreSquares = 0;
    60     while (numPreSquares < 5 && mExponent > (1 << (numPreSquares + 2))) {
    61       numPreSquares++;
    62     }
    63     mNumPowTablePreSquares = numPreSquares;
    64     for (size_t i = 0; i < sCacheSize; i++) {
    65       // sCacheSize is chosen in such a way that a takes values
    66       // from 0.0 to 1.0 inclusive.
    67       Float a = i / Float(1 << sCacheIndexPrecisionBits);
    68       MOZ_ASSERT(0.0f <= a && a <= 1.0f, "We only want to cache for bases between 0 and 1.");
    70       for (int j = 0; j < mNumPowTablePreSquares; j++) {
    71         a = sqrt(a);
    72       }
    73       uint32_t cachedInt = pow(a, mExponent) * (1 << sOutputIntPrecisionBits);
    74       MOZ_ASSERT(cachedInt < (1 << (sizeof(mPowTable[i]) * 8)), "mPowCache integer type too small");
    76       mPowTable[i] = cachedInt;
    77     }
    78   }
    80   uint16_t Pow(uint16_t aBase)
    81   {
    82     // Results should be similar to what the following code would produce:
    83     // Float x = Float(aBase) / (1 << sInputIntPrecisionBits);
    84     // return uint16_t(pow(x, mExponent) * (1 << sOutputIntPrecisionBits));
    86     MOZ_ASSERT(aBase <= (1 << sInputIntPrecisionBits), "aBase needs to be between 0 and 1!");
    88     uint32_t a = aBase;
    89     for (int j = 0; j < mNumPowTablePreSquares; j++) {
    90       a = a * a >> sInputIntPrecisionBits;
    91     }
    92     uint32_t i = a >> (sInputIntPrecisionBits - sCacheIndexPrecisionBits);
    93     MOZ_ASSERT(i < sCacheSize, "out-of-bounds mPowTable access");
    94     return mPowTable[i];
    95   }
    97   static const int sInputIntPrecisionBits = 15;
    98   static const int sOutputIntPrecisionBits = 15;
    99   static const int sCacheIndexPrecisionBits = 7;
   101 private:
   102   static const size_t sCacheSize = (1 << sCacheIndexPrecisionBits) + 1;
   104   Float mExponent;
   105   int mNumPowTablePreSquares;
   106   uint16_t mPowTable[sCacheSize];
   107 };
   109 class PointLightSoftware
   110 {
   111 public:
   112   bool SetAttribute(uint32_t aIndex, Float) { return false; }
   113   bool SetAttribute(uint32_t aIndex, const Point3D &);
   114   void Prepare() {}
   115   Point3D GetVectorToLight(const Point3D &aTargetPoint);
   116   uint32_t GetColor(uint32_t aLightColor, const Point3D &aVectorToLight);
   118 private:
   119   Point3D mPosition;
   120 };
   122 class SpotLightSoftware
   123 {
   124 public:
   125   SpotLightSoftware();
   126   bool SetAttribute(uint32_t aIndex, Float);
   127   bool SetAttribute(uint32_t aIndex, const Point3D &);
   128   void Prepare();
   129   Point3D GetVectorToLight(const Point3D &aTargetPoint);
   130   uint32_t GetColor(uint32_t aLightColor, const Point3D &aVectorToLight);
   132 private:
   133   Point3D mPosition;
   134   Point3D mPointsAt;
   135   Point3D mVectorFromFocusPointToLight;
   136   Float mSpecularFocus;
   137   Float mLimitingConeAngle;
   138   Float mLimitingConeCos;
   139   PowCache mPowCache;
   140 };
   142 class DistantLightSoftware
   143 {
   144 public:
   145   DistantLightSoftware();
   146   bool SetAttribute(uint32_t aIndex, Float);
   147   bool SetAttribute(uint32_t aIndex, const Point3D &) { return false; }
   148   void Prepare();
   149   Point3D GetVectorToLight(const Point3D &aTargetPoint);
   150   uint32_t GetColor(uint32_t aLightColor, const Point3D &aVectorToLight);
   152 private:
   153   Float mAzimuth;
   154   Float mElevation;
   155   Point3D mVectorToLight;
   156 };
   158 class DiffuseLightingSoftware
   159 {
   160 public:
   161   DiffuseLightingSoftware();
   162   bool SetAttribute(uint32_t aIndex, Float);
   163   void Prepare() {}
   164   uint32_t LightPixel(const Point3D &aNormal, const Point3D &aVectorToLight,
   165                       uint32_t aColor);
   167 private:
   168   Float mDiffuseConstant;
   169 };
   171 class SpecularLightingSoftware
   172 {
   173 public:
   174   SpecularLightingSoftware();
   175   bool SetAttribute(uint32_t aIndex, Float);
   176   void Prepare();
   177   uint32_t LightPixel(const Point3D &aNormal, const Point3D &aVectorToLight,
   178                       uint32_t aColor);
   180 private:
   181   Float mSpecularConstant;
   182   Float mSpecularExponent;
   183   uint32_t mSpecularConstantInt;
   184   PowCache mPowCache;
   185 };
   187 } // unnamed namespace
   189 // from xpcom/ds/nsMathUtils.h
   190 static int32_t
   191 NS_lround(double x)
   192 {
   193   return x >= 0.0 ? int32_t(x + 0.5) : int32_t(x - 0.5);
   194 }
   196 void
   197 ClearDataSourceSurface(DataSourceSurface *aSurface)
   198 {
   199   size_t numBytes = aSurface->GetSize().height * aSurface->Stride();
   200   uint8_t* data = aSurface->GetData();
   201   PodZero(data, numBytes);
   202 }
   204 // This check is safe against integer overflow.
   205 static bool
   206 SurfaceContainsPoint(SourceSurface* aSurface, const IntPoint& aPoint)
   207 {
   208   IntSize size = aSurface->GetSize();
   209   return aPoint.x >= 0 && aPoint.x < size.width &&
   210          aPoint.y >= 0 && aPoint.y < size.height;
   211 }
   213 static uint8_t*
   214 DataAtOffset(DataSourceSurface* aSurface, IntPoint aPoint)
   215 {
   216   if (!SurfaceContainsPoint(aSurface, aPoint)) {
   217     MOZ_CRASH("sample position needs to be inside surface!");
   218   }
   220   MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface->GetSize()),
   221              "surface size overflows - this should have been prevented when the surface was created");
   223   uint8_t* data = aSurface->GetData() + aPoint.y * aSurface->Stride() +
   224     aPoint.x * BytesPerPixel(aSurface->GetFormat());
   226   if (data < aSurface->GetData()) {
   227     MOZ_CRASH("out-of-range data access");
   228   }
   230   return data;
   231 }
   233 static bool
   234 IntRectOverflows(const IntRect& aRect)
   235 {
   236   CheckedInt<int32_t> xMost = aRect.x;
   237   xMost += aRect.width;
   238   CheckedInt<int32_t> yMost = aRect.y;
   239   yMost += aRect.height;
   240   return !xMost.isValid() || !yMost.isValid();
   241 }
   243 /**
   244  * aSrcRect: Rect relative to the aSrc surface
   245  * aDestPoint: Point inside aDest surface
   246  */
   247 static void
   248 CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest,
   249          IntRect aSrcRect, IntPoint aDestPoint)
   250 {
   251   if (IntRectOverflows(aSrcRect) ||
   252       IntRectOverflows(IntRect(aDestPoint, aSrcRect.Size()))) {
   253     MOZ_CRASH("we should never be getting invalid rects at this point");
   254   }
   256   MOZ_ASSERT(aSrc->GetFormat() == aDest->GetFormat(), "different surface formats");
   257   MOZ_ASSERT(IntRect(IntPoint(), aSrc->GetSize()).Contains(aSrcRect), "source rect too big for source surface");
   258   MOZ_ASSERT(IntRect(IntPoint(), aDest->GetSize()).Contains(aSrcRect - aSrcRect.TopLeft() + aDestPoint), "dest surface too small");
   260   if (aSrcRect.IsEmpty()) {
   261     return;
   262   }
   264   uint8_t* sourceData = DataAtOffset(aSrc, aSrcRect.TopLeft());
   265   uint32_t sourceStride = aSrc->Stride();
   266   uint8_t* destData = DataAtOffset(aDest, aDestPoint);
   267   uint32_t destStride = aDest->Stride();
   269   if (BytesPerPixel(aSrc->GetFormat()) == 4) {
   270     for (int32_t y = 0; y < aSrcRect.height; y++) {
   271       PodCopy((int32_t*)destData, (int32_t*)sourceData, aSrcRect.width);
   272       sourceData += sourceStride;
   273       destData += destStride;
   274     }
   275   } else if (BytesPerPixel(aSrc->GetFormat()) == 1) {
   276     for (int32_t y = 0; y < aSrcRect.height; y++) {
   277       PodCopy(destData, sourceData, aSrcRect.width);
   278       sourceData += sourceStride;
   279       destData += destStride;
   280     }
   281   }
   282 }
   284 TemporaryRef<DataSourceSurface>
   285 CloneAligned(DataSourceSurface* aSource)
   286 {
   287   RefPtr<DataSourceSurface> copy =
   288     Factory::CreateDataSourceSurface(aSource->GetSize(), aSource->GetFormat());
   289   if (copy) {
   290     CopyRect(aSource, copy, IntRect(IntPoint(), aSource->GetSize()), IntPoint());
   291   }
   292   return copy;
   293 }
   295 static void
   296 FillRectWithPixel(DataSourceSurface *aSurface, const IntRect &aFillRect, IntPoint aPixelPos)
   297 {
   298   MOZ_ASSERT(!IntRectOverflows(aFillRect));
   299   MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect),
   300              "aFillRect needs to be completely inside the surface");
   301   MOZ_ASSERT(SurfaceContainsPoint(aSurface, aPixelPos),
   302              "aPixelPos needs to be inside the surface");
   304   int32_t stride = aSurface->Stride();
   305   uint8_t* sourcePixelData = DataAtOffset(aSurface, aPixelPos);
   306   uint8_t* data = DataAtOffset(aSurface, aFillRect.TopLeft());
   307   int bpp = BytesPerPixel(aSurface->GetFormat());
   309   // Fill the first row by hand.
   310   if (bpp == 4) {
   311     uint32_t sourcePixel = *(uint32_t*)sourcePixelData;
   312     for (int32_t x = 0; x < aFillRect.width; x++) {
   313       *((uint32_t*)data + x) = sourcePixel;
   314     }
   315   } else if (BytesPerPixel(aSurface->GetFormat()) == 1) {
   316     uint8_t sourcePixel = *sourcePixelData;
   317     memset(data, sourcePixel, aFillRect.width);
   318   }
   320   // Copy the first row into the other rows.
   321   for (int32_t y = 1; y < aFillRect.height; y++) {
   322     PodCopy(data + y * stride, data, aFillRect.width * bpp);
   323   }
   324 }
   326 static void
   327 FillRectWithVerticallyRepeatingHorizontalStrip(DataSourceSurface *aSurface,
   328                                                const IntRect &aFillRect,
   329                                                const IntRect &aSampleRect)
   330 {
   331   MOZ_ASSERT(!IntRectOverflows(aFillRect));
   332   MOZ_ASSERT(!IntRectOverflows(aSampleRect));
   333   MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect),
   334              "aFillRect needs to be completely inside the surface");
   335   MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aSampleRect),
   336              "aSampleRect needs to be completely inside the surface");
   338   int32_t stride = aSurface->Stride();
   339   uint8_t* sampleData = DataAtOffset(aSurface, aSampleRect.TopLeft());
   340   uint8_t* data = DataAtOffset(aSurface, aFillRect.TopLeft());
   341   if (BytesPerPixel(aSurface->GetFormat()) == 4) {
   342     for (int32_t y = 0; y < aFillRect.height; y++) {
   343       PodCopy((uint32_t*)data, (uint32_t*)sampleData, aFillRect.width);
   344       data += stride;
   345     }
   346   } else if (BytesPerPixel(aSurface->GetFormat()) == 1) {
   347     for (int32_t y = 0; y < aFillRect.height; y++) {
   348       PodCopy(data, sampleData, aFillRect.width);
   349       data += stride;
   350     }
   351   }
   352 }
   354 static void
   355 FillRectWithHorizontallyRepeatingVerticalStrip(DataSourceSurface *aSurface,
   356                                                const IntRect &aFillRect,
   357                                                const IntRect &aSampleRect)
   358 {
   359   MOZ_ASSERT(!IntRectOverflows(aFillRect));
   360   MOZ_ASSERT(!IntRectOverflows(aSampleRect));
   361   MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect),
   362              "aFillRect needs to be completely inside the surface");
   363   MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aSampleRect),
   364              "aSampleRect needs to be completely inside the surface");
   366   int32_t stride = aSurface->Stride();
   367   uint8_t* sampleData = DataAtOffset(aSurface, aSampleRect.TopLeft());
   368   uint8_t* data = DataAtOffset(aSurface, aFillRect.TopLeft());
   369   if (BytesPerPixel(aSurface->GetFormat()) == 4) {
   370     for (int32_t y = 0; y < aFillRect.height; y++) {
   371       int32_t sampleColor = *((uint32_t*)sampleData);
   372       for (int32_t x = 0; x < aFillRect.width; x++) {
   373         *((uint32_t*)data + x) = sampleColor;
   374       }
   375       data += stride;
   376       sampleData += stride;
   377     }
   378   } else if (BytesPerPixel(aSurface->GetFormat()) == 1) {
   379     for (int32_t y = 0; y < aFillRect.height; y++) {
   380       uint8_t sampleColor = *sampleData;
   381       memset(data, sampleColor, aFillRect.width);
   382       data += stride;
   383       sampleData += stride;
   384     }
   385   }
   386 }
   388 static void
   389 DuplicateEdges(DataSourceSurface* aSurface, const IntRect &aFromRect)
   390 {
   391   MOZ_ASSERT(!IntRectOverflows(aFromRect));
   392   MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFromRect),
   393              "aFromRect needs to be completely inside the surface");
   395   IntSize size = aSurface->GetSize();
   396   IntRect fill;
   397   IntRect sampleRect;
   398   for (int32_t ix = 0; ix < 3; ix++) {
   399     switch (ix) {
   400       case 0:
   401         fill.x = 0;
   402         fill.width = aFromRect.x;
   403         sampleRect.x = fill.XMost();
   404         sampleRect.width = 1;
   405         break;
   406       case 1:
   407         fill.x = aFromRect.x;
   408         fill.width = aFromRect.width;
   409         sampleRect.x = fill.x;
   410         sampleRect.width = fill.width;
   411         break;
   412       case 2:
   413         fill.x = aFromRect.XMost();
   414         fill.width = size.width - fill.x;
   415         sampleRect.x = fill.x - 1;
   416         sampleRect.width = 1;
   417         break;
   418     }
   419     if (fill.width <= 0) {
   420       continue;
   421     }
   422     bool xIsMiddle = (ix == 1);
   423     for (int32_t iy = 0; iy < 3; iy++) {
   424       switch (iy) {
   425         case 0:
   426           fill.y = 0;
   427           fill.height = aFromRect.y;
   428           sampleRect.y = fill.YMost();
   429           sampleRect.height = 1;
   430           break;
   431         case 1:
   432           fill.y = aFromRect.y;
   433           fill.height = aFromRect.height;
   434           sampleRect.y = fill.y;
   435           sampleRect.height = fill.height;
   436           break;
   437         case 2:
   438           fill.y = aFromRect.YMost();
   439           fill.height = size.height - fill.y;
   440           sampleRect.y = fill.y - 1;
   441           sampleRect.height = 1;
   442           break;
   443       }
   444       if (fill.height <= 0) {
   445         continue;
   446       }
   447       bool yIsMiddle = (iy == 1);
   448       if (!xIsMiddle && !yIsMiddle) {
   449         // Corner
   450         FillRectWithPixel(aSurface, fill, sampleRect.TopLeft());
   451       }
   452       if (xIsMiddle && !yIsMiddle) {
   453         // Top middle or bottom middle
   454         FillRectWithVerticallyRepeatingHorizontalStrip(aSurface, fill, sampleRect);
   455       }
   456       if (!xIsMiddle && yIsMiddle) {
   457         // Left middle or right middle
   458         FillRectWithHorizontallyRepeatingVerticalStrip(aSurface, fill, sampleRect);
   459       }
   460     }
   461   }
   462 }
   464 static IntPoint
   465 TileIndex(const IntRect &aFirstTileRect, const IntPoint &aPoint)
   466 {
   467   return IntPoint(int32_t(floor(double(aPoint.x - aFirstTileRect.x) / aFirstTileRect.width)),
   468                   int32_t(floor(double(aPoint.y - aFirstTileRect.y) / aFirstTileRect.height)));
   469 }
   471 static void
   472 TileSurface(DataSourceSurface* aSource, DataSourceSurface* aTarget, const IntPoint &aOffset)
   473 {
   474   IntRect sourceRect(aOffset, aSource->GetSize());
   475   IntRect targetRect(IntPoint(0, 0), aTarget->GetSize());
   476   IntPoint startIndex = TileIndex(sourceRect, targetRect.TopLeft());
   477   IntPoint endIndex = TileIndex(sourceRect, targetRect.BottomRight());
   479   for (int32_t ix = startIndex.x; ix <= endIndex.x; ix++) {
   480     for (int32_t iy = startIndex.y; iy <= endIndex.y; iy++) {
   481       IntPoint destPoint(sourceRect.x + ix * sourceRect.width,
   482                          sourceRect.y + iy * sourceRect.height);
   483       IntRect destRect(destPoint, sourceRect.Size());
   484       destRect = destRect.Intersect(targetRect);
   485       IntRect srcRect = destRect - destPoint;
   486       CopyRect(aSource, aTarget, srcRect, destRect.TopLeft());
   487     }
   488   }
   489 }
   491 static TemporaryRef<DataSourceSurface>
   492 GetDataSurfaceInRect(SourceSurface *aSurface,
   493                      const IntRect &aSurfaceRect,
   494                      const IntRect &aDestRect,
   495                      ConvolveMatrixEdgeMode aEdgeMode)
   496 {
   497   MOZ_ASSERT(aSurface ? aSurfaceRect.Size() == aSurface->GetSize() : aSurfaceRect.IsEmpty());
   499   if (IntRectOverflows(aSurfaceRect) || IntRectOverflows(aDestRect)) {
   500     // We can't rely on the intersection calculations below to make sense when
   501     // XMost() or YMost() overflow. Bail out.
   502     return nullptr;
   503   }
   505   IntRect sourceRect = aSurfaceRect;
   507   if (sourceRect.IsEqualEdges(aDestRect)) {
   508     return aSurface ? aSurface->GetDataSurface() : nullptr;
   509   }
   511   IntRect intersect = sourceRect.Intersect(aDestRect);
   512   IntRect intersectInSourceSpace = intersect - sourceRect.TopLeft();
   513   IntRect intersectInDestSpace = intersect - aDestRect.TopLeft();
   514   SurfaceFormat format = aSurface ? aSurface->GetFormat() : SurfaceFormat(SurfaceFormat::B8G8R8A8);
   516   RefPtr<DataSourceSurface> target =
   517     Factory::CreateDataSourceSurface(aDestRect.Size(), format);
   519   if (!target) {
   520     return nullptr;
   521   }
   523   if (aEdgeMode == EDGE_MODE_NONE && !aSurfaceRect.Contains(aDestRect)) {
   524     ClearDataSourceSurface(target);
   525   }
   527   if (!aSurface) {
   528     return target;
   529   }
   531   RefPtr<DataSourceSurface> dataSource = aSurface->GetDataSurface();
   532   MOZ_ASSERT(dataSource);
   534   if (aEdgeMode == EDGE_MODE_WRAP) {
   535     TileSurface(dataSource, target, intersectInDestSpace.TopLeft());
   536     return target;
   537   }
   539   CopyRect(dataSource, target, intersectInSourceSpace,
   540            intersectInDestSpace.TopLeft());
   542   if (aEdgeMode == EDGE_MODE_DUPLICATE) {
   543     DuplicateEdges(target, intersectInDestSpace);
   544   }
   546   return target;
   547 }
   549 /* static */ TemporaryRef<FilterNode>
   550 FilterNodeSoftware::Create(FilterType aType)
   551 {
   552   RefPtr<FilterNodeSoftware> filter;
   553   switch (aType) {
   554     case FilterType::BLEND:
   555       filter = new FilterNodeBlendSoftware();
   556       break;
   557     case FilterType::TRANSFORM:
   558       filter = new FilterNodeTransformSoftware();
   559       break;
   560     case FilterType::MORPHOLOGY:
   561       filter = new FilterNodeMorphologySoftware();
   562       break;
   563     case FilterType::COLOR_MATRIX:
   564       filter = new FilterNodeColorMatrixSoftware();
   565       break;
   566     case FilterType::FLOOD:
   567       filter = new FilterNodeFloodSoftware();
   568       break;
   569     case FilterType::TILE:
   570       filter = new FilterNodeTileSoftware();
   571       break;
   572     case FilterType::TABLE_TRANSFER:
   573       filter = new FilterNodeTableTransferSoftware();
   574       break;
   575     case FilterType::DISCRETE_TRANSFER:
   576       filter = new FilterNodeDiscreteTransferSoftware();
   577       break;
   578     case FilterType::LINEAR_TRANSFER:
   579       filter = new FilterNodeLinearTransferSoftware();
   580       break;
   581     case FilterType::GAMMA_TRANSFER:
   582       filter = new FilterNodeGammaTransferSoftware();
   583       break;
   584     case FilterType::CONVOLVE_MATRIX:
   585       filter = new FilterNodeConvolveMatrixSoftware();
   586       break;
   587     case FilterType::DISPLACEMENT_MAP:
   588       filter = new FilterNodeDisplacementMapSoftware();
   589       break;
   590     case FilterType::TURBULENCE:
   591       filter = new FilterNodeTurbulenceSoftware();
   592       break;
   593     case FilterType::ARITHMETIC_COMBINE:
   594       filter = new FilterNodeArithmeticCombineSoftware();
   595       break;
   596     case FilterType::COMPOSITE:
   597       filter = new FilterNodeCompositeSoftware();
   598       break;
   599     case FilterType::GAUSSIAN_BLUR:
   600       filter = new FilterNodeGaussianBlurSoftware();
   601       break;
   602     case FilterType::DIRECTIONAL_BLUR:
   603       filter = new FilterNodeDirectionalBlurSoftware();
   604       break;
   605     case FilterType::CROP:
   606       filter = new FilterNodeCropSoftware();
   607       break;
   608     case FilterType::PREMULTIPLY:
   609       filter = new FilterNodePremultiplySoftware();
   610       break;
   611     case FilterType::UNPREMULTIPLY:
   612       filter = new FilterNodeUnpremultiplySoftware();
   613       break;
   614     case FilterType::POINT_DIFFUSE:
   615       filter = new FilterNodeLightingSoftware<PointLightSoftware, DiffuseLightingSoftware>("FilterNodeLightingSoftware<PointLight, DiffuseLighting>");
   616       break;
   617     case FilterType::POINT_SPECULAR:
   618       filter = new FilterNodeLightingSoftware<PointLightSoftware, SpecularLightingSoftware>("FilterNodeLightingSoftware<PointLight, SpecularLighting>");
   619       break;
   620     case FilterType::SPOT_DIFFUSE:
   621       filter = new FilterNodeLightingSoftware<SpotLightSoftware, DiffuseLightingSoftware>("FilterNodeLightingSoftware<SpotLight, DiffuseLighting>");
   622       break;
   623     case FilterType::SPOT_SPECULAR:
   624       filter = new FilterNodeLightingSoftware<SpotLightSoftware, SpecularLightingSoftware>("FilterNodeLightingSoftware<SpotLight, SpecularLighting>");
   625       break;
   626     case FilterType::DISTANT_DIFFUSE:
   627       filter = new FilterNodeLightingSoftware<DistantLightSoftware, DiffuseLightingSoftware>("FilterNodeLightingSoftware<DistantLight, DiffuseLighting>");
   628       break;
   629     case FilterType::DISTANT_SPECULAR:
   630       filter = new FilterNodeLightingSoftware<DistantLightSoftware, SpecularLightingSoftware>("FilterNodeLightingSoftware<DistantLight, SpecularLighting>");
   631       break;
   632   }
   633   return filter;
   634 }
   636 void
   637 FilterNodeSoftware::Draw(DrawTarget* aDrawTarget,
   638                          const Rect &aSourceRect,
   639                          const Point &aDestPoint,
   640                          const DrawOptions &aOptions)
   641 {
   642 #ifdef DEBUG_DUMP_SURFACES
   643   printf("<style>section{margin:10px;}</style><pre>\nRendering filter %s...\n", GetName());
   644 #endif
   646   Rect renderRect = aSourceRect;
   647   renderRect.RoundOut();
   648   IntRect renderIntRect;
   649   if (!renderRect.ToIntRect(&renderIntRect)) {
   650 #ifdef DEBUG_DUMP_SURFACES
   651     printf("render rect overflowed, not painting anything\n");
   652     printf("</pre>\n");
   653 #endif
   654     return;
   655   }
   657   IntRect outputRect = GetOutputRectInRect(renderIntRect);
   658   if (IntRectOverflows(outputRect)) {
   659 #ifdef DEBUG_DUMP_SURFACES
   660     printf("output rect overflowed, not painting anything\n");
   661     printf("</pre>\n");
   662 #endif
   663     return;
   664   }
   666   RefPtr<DataSourceSurface> result;
   667   if (!outputRect.IsEmpty()) {
   668     result = GetOutput(outputRect);
   669   }
   671   if (!result) {
   672     // Null results are allowed and treated as transparent. Don't draw anything.
   673 #ifdef DEBUG_DUMP_SURFACES
   674     printf("output returned null\n");
   675     printf("</pre>\n");
   676 #endif
   677     return;
   678   }
   680 #ifdef DEBUG_DUMP_SURFACES
   681   printf("output from %s:\n", GetName());
   682   printf("<img src='"); DumpAsPNG(result); printf("'>\n");
   683   printf("</pre>\n");
   684 #endif
   686   Point sourceToDestOffset = aDestPoint - aSourceRect.TopLeft();
   687   Rect renderedSourceRect = Rect(outputRect).Intersect(aSourceRect);
   688   Rect renderedDestRect = renderedSourceRect + sourceToDestOffset;
   689   if (result->GetFormat() == SurfaceFormat::A8) {
   690     // Interpret the result as having implicitly black color channels.
   691     aDrawTarget->PushClipRect(renderedDestRect);
   692     aDrawTarget->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)),
   693                              result,
   694                              Point(outputRect.TopLeft()) + sourceToDestOffset,
   695                              aOptions);
   696     aDrawTarget->PopClip();
   697   } else {
   698     aDrawTarget->DrawSurface(result, renderedDestRect,
   699                              renderedSourceRect - Point(outputRect.TopLeft()),
   700                              DrawSurfaceOptions(), aOptions);
   701   }
   702 }
   704 TemporaryRef<DataSourceSurface>
   705 FilterNodeSoftware::GetOutput(const IntRect &aRect)
   706 {
   707   MOZ_ASSERT(GetOutputRectInRect(aRect).Contains(aRect));
   709   if (IntRectOverflows(aRect)) {
   710     return nullptr;
   711   }
   713   if (!mCachedRect.Contains(aRect)) {
   714     RequestRect(aRect);
   715     mCachedOutput = Render(mRequestedRect);
   716     if (!mCachedOutput) {
   717       mCachedRect = IntRect();
   718       mRequestedRect = IntRect();
   719       return nullptr;
   720     }
   721     mCachedRect = mRequestedRect;
   722     mRequestedRect = IntRect();
   723   } else {
   724     MOZ_ASSERT(mCachedOutput, "cached rect but no cached output?");
   725   }
   726   return GetDataSurfaceInRect(mCachedOutput, mCachedRect, aRect, EDGE_MODE_NONE);
   727 }
   729 void
   730 FilterNodeSoftware::RequestRect(const IntRect &aRect)
   731 {
   732   mRequestedRect = mRequestedRect.Union(aRect);
   733   RequestFromInputsForRect(aRect);
   734 }
   736 void
   737 FilterNodeSoftware::RequestInputRect(uint32_t aInputEnumIndex, const IntRect &aRect)
   738 {
   739   if (IntRectOverflows(aRect)) {
   740     return;
   741   }
   743   int32_t inputIndex = InputIndex(aInputEnumIndex);
   744   if (inputIndex < 0 || (uint32_t)inputIndex >= NumberOfSetInputs()) {
   745     MOZ_CRASH();
   746   }
   747   if (mInputSurfaces[inputIndex]) {
   748     return;
   749   }
   750   RefPtr<FilterNodeSoftware> filter = mInputFilters[inputIndex];
   751   MOZ_ASSERT(filter, "missing input");
   752   filter->RequestRect(filter->GetOutputRectInRect(aRect));
   753 }
   755 SurfaceFormat
   756 FilterNodeSoftware::DesiredFormat(SurfaceFormat aCurrentFormat,
   757                                   FormatHint aFormatHint)
   758 {
   759   if (aCurrentFormat == SurfaceFormat::A8 && aFormatHint == CAN_HANDLE_A8) {
   760     return SurfaceFormat::A8;
   761   }
   762   return SurfaceFormat::B8G8R8A8;
   763 }
   765 TemporaryRef<DataSourceSurface>
   766 FilterNodeSoftware::GetInputDataSourceSurface(uint32_t aInputEnumIndex,
   767                                               const IntRect& aRect,
   768                                               FormatHint aFormatHint,
   769                                               ConvolveMatrixEdgeMode aEdgeMode,
   770                                               const IntRect *aTransparencyPaddedSourceRect)
   771 {
   772   if (IntRectOverflows(aRect)) {
   773     return nullptr;
   774   }
   776 #ifdef DEBUG_DUMP_SURFACES
   777   printf("<section><h1>GetInputDataSourceSurface with aRect: %d, %d, %d, %d</h1>\n",
   778          aRect.x, aRect.y, aRect.width, aRect.height);
   779 #endif
   780   int32_t inputIndex = InputIndex(aInputEnumIndex);
   781   if (inputIndex < 0 || (uint32_t)inputIndex >= NumberOfSetInputs()) {
   782     MOZ_CRASH();
   783     return nullptr;
   784   }
   786   if (aRect.IsEmpty()) {
   787     return nullptr;
   788   }
   790   RefPtr<SourceSurface> surface;
   791   IntRect surfaceRect;
   793   if (mInputSurfaces[inputIndex]) {
   794     // Input from input surface
   795     surface = mInputSurfaces[inputIndex];
   796 #ifdef DEBUG_DUMP_SURFACES
   797     printf("input from input surface:\n");
   798 #endif
   799     surfaceRect = IntRect(IntPoint(0, 0), surface->GetSize());
   800   } else {
   801     // Input from input filter
   802 #ifdef DEBUG_DUMP_SURFACES
   803     printf("getting input from input filter %s...\n", mInputFilters[inputIndex]->GetName());
   804 #endif
   805     RefPtr<FilterNodeSoftware> filter = mInputFilters[inputIndex];
   806     MOZ_ASSERT(filter, "missing input");
   807     IntRect inputFilterOutput = filter->GetOutputRectInRect(aRect);
   808     if (!inputFilterOutput.IsEmpty()) {
   809       surface = filter->GetOutput(inputFilterOutput);
   810     }
   811 #ifdef DEBUG_DUMP_SURFACES
   812     printf("input from input filter %s:\n", mInputFilters[inputIndex]->GetName());
   813 #endif
   814     surfaceRect = inputFilterOutput;
   815     MOZ_ASSERT(!surface || surfaceRect.Size() == surface->GetSize());
   816   }
   818   if (surface && surface->GetFormat() == SurfaceFormat::UNKNOWN) {
   819 #ifdef DEBUG_DUMP_SURFACES
   820     printf("wrong input format</section>\n\n");
   821 #endif
   822     return nullptr;
   823   }
   825   if (!surfaceRect.IsEmpty() && !surface) {
   826 #ifdef DEBUG_DUMP_SURFACES
   827     printf(" -- no input --</section>\n\n");
   828 #endif
   829     return nullptr;
   830   }
   832   if (aTransparencyPaddedSourceRect && !aTransparencyPaddedSourceRect->IsEmpty()) {
   833     IntRect srcRect = aTransparencyPaddedSourceRect->Intersect(aRect);
   834     surface = GetDataSurfaceInRect(surface, surfaceRect, srcRect, EDGE_MODE_NONE);
   835     surfaceRect = srcRect;
   836   }
   838   RefPtr<DataSourceSurface> result =
   839     GetDataSurfaceInRect(surface, surfaceRect, aRect, aEdgeMode);
   841   if (result &&
   842       (result->Stride() != GetAlignedStride<16>(result->Stride()) ||
   843        reinterpret_cast<uintptr_t>(result->GetData()) % 16 != 0)) {
   844     // Align unaligned surface.
   845     result = CloneAligned(result);
   846   }
   848   if (!result) {
   849 #ifdef DEBUG_DUMP_SURFACES
   850     printf(" -- no input --</section>\n\n");
   851 #endif
   852     return nullptr;
   853   }
   855   SurfaceFormat currentFormat = result->GetFormat();
   856   if (DesiredFormat(currentFormat, aFormatHint) == SurfaceFormat::B8G8R8A8 &&
   857       currentFormat != SurfaceFormat::B8G8R8A8) {
   858     result = FilterProcessing::ConvertToB8G8R8A8(result);
   859   }
   861 #ifdef DEBUG_DUMP_SURFACES
   862   printf("<img src='"); DumpAsPNG(result); printf("'></section>");
   863 #endif
   865   MOZ_ASSERT(!result || result->GetSize() == aRect.Size(), "wrong surface size");
   867   return result;
   868 }
   870 IntRect
   871 FilterNodeSoftware::GetInputRectInRect(uint32_t aInputEnumIndex,
   872                                        const IntRect &aInRect)
   873 {
   874   if (IntRectOverflows(aInRect)) {
   875     return IntRect();
   876   }
   878   int32_t inputIndex = InputIndex(aInputEnumIndex);
   879   if (inputIndex < 0 || (uint32_t)inputIndex >= NumberOfSetInputs()) {
   880     MOZ_CRASH();
   881     return IntRect();
   882   }
   883   if (mInputSurfaces[inputIndex]) {
   884     return aInRect.Intersect(IntRect(IntPoint(0, 0),
   885                                      mInputSurfaces[inputIndex]->GetSize()));
   886   }
   887   RefPtr<FilterNodeSoftware> filter = mInputFilters[inputIndex];
   888   MOZ_ASSERT(filter, "missing input");
   889   return filter->GetOutputRectInRect(aInRect);
   890 }
   892 size_t
   893 FilterNodeSoftware::NumberOfSetInputs()
   894 {
   895   return std::max(mInputSurfaces.size(), mInputFilters.size());
   896 }
   898 void
   899 FilterNodeSoftware::AddInvalidationListener(FilterInvalidationListener* aListener)
   900 {
   901   MOZ_ASSERT(aListener, "null listener");
   902   mInvalidationListeners.push_back(aListener);
   903 }
   905 void
   906 FilterNodeSoftware::RemoveInvalidationListener(FilterInvalidationListener* aListener)
   907 {
   908   MOZ_ASSERT(aListener, "null listener");
   909   std::vector<FilterInvalidationListener*>::iterator it =
   910     std::find(mInvalidationListeners.begin(), mInvalidationListeners.end(), aListener);
   911   mInvalidationListeners.erase(it);
   912 }
   914 void
   915 FilterNodeSoftware::FilterInvalidated(FilterNodeSoftware* aFilter)
   916 {
   917   Invalidate();
   918 }
   920 void
   921 FilterNodeSoftware::Invalidate()
   922 {
   923   mCachedOutput = nullptr;
   924   mCachedRect = IntRect();
   925   for (std::vector<FilterInvalidationListener*>::iterator it = mInvalidationListeners.begin();
   926        it != mInvalidationListeners.end(); it++) {
   927     (*it)->FilterInvalidated(this);
   928   }
   929 }
   931 FilterNodeSoftware::~FilterNodeSoftware()
   932 {
   933   MOZ_ASSERT(!mInvalidationListeners.size(),
   934              "All invalidation listeners should have unsubscribed themselves by now!");
   936   for (std::vector<RefPtr<FilterNodeSoftware> >::iterator it = mInputFilters.begin();
   937        it != mInputFilters.end(); it++) {
   938     if (*it) {
   939       (*it)->RemoveInvalidationListener(this);
   940     }
   941   }
   942 }
   944 void
   945 FilterNodeSoftware::SetInput(uint32_t aIndex, FilterNode *aFilter)
   946 {
   947   if (aFilter->GetBackendType() != FILTER_BACKEND_SOFTWARE) {
   948     MOZ_ASSERT(false, "can only take software filters as inputs");
   949     return;
   950   }
   951   SetInput(aIndex, nullptr, static_cast<FilterNodeSoftware*>(aFilter));
   952 }
   954 void
   955 FilterNodeSoftware::SetInput(uint32_t aIndex, SourceSurface *aSurface)
   956 {
   957   SetInput(aIndex, aSurface, nullptr);
   958 }
   960 void
   961 FilterNodeSoftware::SetInput(uint32_t aInputEnumIndex,
   962                              SourceSurface *aSurface,
   963                              FilterNodeSoftware *aFilter)
   964 {
   965   int32_t inputIndex = InputIndex(aInputEnumIndex);
   966   if (inputIndex < 0) {
   967     MOZ_CRASH();
   968     return;
   969   }
   970   if ((uint32_t)inputIndex >= mInputSurfaces.size()) {
   971     mInputSurfaces.resize(inputIndex + 1);
   972   }
   973   if ((uint32_t)inputIndex >= mInputFilters.size()) {
   974     mInputFilters.resize(inputIndex + 1);
   975   }
   976   mInputSurfaces[inputIndex] = aSurface;
   977   if (mInputFilters[inputIndex]) {
   978     mInputFilters[inputIndex]->RemoveInvalidationListener(this);
   979   }
   980   if (aFilter) {
   981     aFilter->AddInvalidationListener(this);
   982   }
   983   mInputFilters[inputIndex] = aFilter;
   984   Invalidate();
   985 }
   987 FilterNodeBlendSoftware::FilterNodeBlendSoftware()
   988  : mBlendMode(BLEND_MODE_MULTIPLY)
   989 {}
   991 int32_t
   992 FilterNodeBlendSoftware::InputIndex(uint32_t aInputEnumIndex)
   993 {
   994   switch (aInputEnumIndex) {
   995     case IN_BLEND_IN: return 0;
   996     case IN_BLEND_IN2: return 1;
   997     default: return -1;
   998   }
   999 }
  1001 void
  1002 FilterNodeBlendSoftware::SetAttribute(uint32_t aIndex, uint32_t aBlendMode)
  1004   MOZ_ASSERT(aIndex == ATT_BLEND_BLENDMODE);
  1005   mBlendMode = static_cast<BlendMode>(aBlendMode);
  1006   Invalidate();
  1009 TemporaryRef<DataSourceSurface>
  1010 FilterNodeBlendSoftware::Render(const IntRect& aRect)
  1012   RefPtr<DataSourceSurface> input1 =
  1013     GetInputDataSourceSurface(IN_BLEND_IN, aRect, NEED_COLOR_CHANNELS);
  1014   RefPtr<DataSourceSurface> input2 =
  1015     GetInputDataSourceSurface(IN_BLEND_IN2, aRect, NEED_COLOR_CHANNELS);
  1017   // Null inputs need to be treated as transparent.
  1019   // First case: both are transparent.
  1020   if (!input1 && !input2) {
  1021     // Then the result is transparent, too.
  1022     return nullptr;
  1025   // Second case: both are non-transparent.
  1026   if (input1 && input2) {
  1027     // Apply normal filtering.
  1028     return FilterProcessing::ApplyBlending(input1, input2, mBlendMode);
  1031   // Third case: one of them is transparent. Return the non-transparent one.
  1032   return input1 ? input1 : input2;
  1035 void
  1036 FilterNodeBlendSoftware::RequestFromInputsForRect(const IntRect &aRect)
  1038   RequestInputRect(IN_BLEND_IN, aRect);
  1039   RequestInputRect(IN_BLEND_IN2, aRect);
  1042 IntRect
  1043 FilterNodeBlendSoftware::GetOutputRectInRect(const IntRect& aRect)
  1045   return GetInputRectInRect(IN_BLEND_IN, aRect).Union(
  1046     GetInputRectInRect(IN_BLEND_IN2, aRect)).Intersect(aRect);
  1049 FilterNodeTransformSoftware::FilterNodeTransformSoftware()
  1050  : mFilter(Filter::GOOD)
  1051 {}
  1053 int32_t
  1054 FilterNodeTransformSoftware::InputIndex(uint32_t aInputEnumIndex)
  1056   switch (aInputEnumIndex) {
  1057     case IN_TRANSFORM_IN: return 0;
  1058     default: return -1;
  1062 void
  1063 FilterNodeTransformSoftware::SetAttribute(uint32_t aIndex, uint32_t aFilter)
  1065   MOZ_ASSERT(aIndex == ATT_TRANSFORM_FILTER);
  1066   mFilter = static_cast<Filter>(aFilter);
  1067   Invalidate();
  1070 void
  1071 FilterNodeTransformSoftware::SetAttribute(uint32_t aIndex, const Matrix &aMatrix)
  1073   MOZ_ASSERT(aIndex == ATT_TRANSFORM_MATRIX);
  1074   mMatrix = aMatrix;
  1075   Invalidate();
  1078 IntRect
  1079 FilterNodeTransformSoftware::SourceRectForOutputRect(const IntRect &aRect)
  1081   if (aRect.IsEmpty()) {
  1082     return IntRect();
  1085   Matrix inverted(mMatrix);
  1086   if (!inverted.Invert()) {
  1087     return IntRect();
  1090   Rect neededRect = inverted.TransformBounds(Rect(aRect));
  1091   neededRect.RoundOut();
  1092   IntRect neededIntRect;
  1093   if (!neededRect.ToIntRect(&neededIntRect)) {
  1094     return IntRect();
  1096   return GetInputRectInRect(IN_TRANSFORM_IN, neededIntRect);
  1099 TemporaryRef<DataSourceSurface>
  1100 FilterNodeTransformSoftware::Render(const IntRect& aRect)
  1102   IntRect srcRect = SourceRectForOutputRect(aRect);
  1104   RefPtr<DataSourceSurface> input =
  1105     GetInputDataSourceSurface(IN_TRANSFORM_IN, srcRect, NEED_COLOR_CHANNELS);
  1107   if (!input) {
  1108     return nullptr;
  1111   Matrix transform = Matrix::Translation(srcRect.x, srcRect.y) * mMatrix *
  1112                      Matrix::Translation(-aRect.x, -aRect.y);
  1113   if (transform.IsIdentity() && srcRect.Size() == aRect.Size()) {
  1114     return input;
  1117   RefPtr<DrawTarget> dt =
  1118     Factory::CreateDrawTarget(BackendType::CAIRO, aRect.Size(), input->GetFormat());
  1119   if (!dt) {
  1120     return nullptr;
  1123   Rect r(0, 0, srcRect.width, srcRect.height);
  1124   dt->SetTransform(transform);
  1125   dt->DrawSurface(input, r, r, DrawSurfaceOptions(mFilter));
  1127   RefPtr<SourceSurface> result = dt->Snapshot();
  1128   RefPtr<DataSourceSurface> resultData = result->GetDataSurface();
  1129   return resultData;
  1132 void
  1133 FilterNodeTransformSoftware::RequestFromInputsForRect(const IntRect &aRect)
  1135   RequestInputRect(IN_TRANSFORM_IN, SourceRectForOutputRect(aRect));
  1138 IntRect
  1139 FilterNodeTransformSoftware::GetOutputRectInRect(const IntRect& aRect)
  1141   IntRect srcRect = SourceRectForOutputRect(aRect);
  1142   if (srcRect.IsEmpty()) {
  1143     return IntRect();
  1146   Rect outRect = mMatrix.TransformBounds(Rect(srcRect));
  1147   outRect.RoundOut();
  1148   IntRect outIntRect;
  1149   if (!outRect.ToIntRect(&outIntRect)) {
  1150     return IntRect();
  1152   return outIntRect.Intersect(aRect);
  1155 FilterNodeMorphologySoftware::FilterNodeMorphologySoftware()
  1156  : mOperator(MORPHOLOGY_OPERATOR_ERODE)
  1157 {}
  1159 int32_t
  1160 FilterNodeMorphologySoftware::InputIndex(uint32_t aInputEnumIndex)
  1162   switch (aInputEnumIndex) {
  1163     case IN_MORPHOLOGY_IN: return 0;
  1164     default: return -1;
  1168 void
  1169 FilterNodeMorphologySoftware::SetAttribute(uint32_t aIndex,
  1170                                            const IntSize &aRadii)
  1172   MOZ_ASSERT(aIndex == ATT_MORPHOLOGY_RADII);
  1173   mRadii.width = std::min(std::max(aRadii.width, 0), 100000);
  1174   mRadii.height = std::min(std::max(aRadii.height, 0), 100000);
  1175   Invalidate();
  1178 void
  1179 FilterNodeMorphologySoftware::SetAttribute(uint32_t aIndex,
  1180                                            uint32_t aOperator)
  1182   MOZ_ASSERT(aIndex == ATT_MORPHOLOGY_OPERATOR);
  1183   mOperator = static_cast<MorphologyOperator>(aOperator);
  1184   Invalidate();
  1187 static TemporaryRef<DataSourceSurface>
  1188 ApplyMorphology(const IntRect& aSourceRect, DataSourceSurface* aInput,
  1189                 const IntRect& aDestRect, int32_t rx, int32_t ry,
  1190                 MorphologyOperator aOperator)
  1192   IntRect srcRect = aSourceRect - aDestRect.TopLeft();
  1193   IntRect destRect = aDestRect - aDestRect.TopLeft();
  1194   IntRect tmpRect(destRect.x, srcRect.y, destRect.width, srcRect.height);
  1195 #ifdef DEBUG
  1196   IntMargin margin = srcRect - destRect;
  1197   MOZ_ASSERT(margin.top >= ry && margin.right >= rx &&
  1198              margin.bottom >= ry && margin.left >= rx, "insufficient margin");
  1199 #endif
  1201   RefPtr<DataSourceSurface> tmp;
  1202   if (rx == 0) {
  1203     tmp = aInput;
  1204   } else {
  1205     tmp = Factory::CreateDataSourceSurface(tmpRect.Size(), SurfaceFormat::B8G8R8A8);
  1206     if (!tmp) {
  1207       return nullptr;
  1210     int32_t sourceStride = aInput->Stride();
  1211     uint8_t* sourceData = DataAtOffset(aInput, destRect.TopLeft() - srcRect.TopLeft());
  1213     int32_t tmpStride = tmp->Stride();
  1214     uint8_t* tmpData = DataAtOffset(tmp, destRect.TopLeft() - tmpRect.TopLeft());
  1216     FilterProcessing::ApplyMorphologyHorizontal(
  1217       sourceData, sourceStride, tmpData, tmpStride, tmpRect, rx, aOperator);
  1220   RefPtr<DataSourceSurface> dest;
  1221   if (ry == 0) {
  1222     dest = tmp;
  1223   } else {
  1224     dest = Factory::CreateDataSourceSurface(destRect.Size(), SurfaceFormat::B8G8R8A8);
  1225     if (!dest) {
  1226       return nullptr;
  1229     int32_t tmpStride = tmp->Stride();
  1230     uint8_t* tmpData = DataAtOffset(tmp, destRect.TopLeft() - tmpRect.TopLeft());
  1232     int32_t destStride = dest->Stride();
  1233     uint8_t* destData = dest->GetData();
  1235     FilterProcessing::ApplyMorphologyVertical(
  1236       tmpData, tmpStride, destData, destStride, destRect, ry, aOperator);
  1239   return dest;
  1242 TemporaryRef<DataSourceSurface>
  1243 FilterNodeMorphologySoftware::Render(const IntRect& aRect)
  1245   IntRect srcRect = aRect;
  1246   srcRect.Inflate(mRadii);
  1248   RefPtr<DataSourceSurface> input =
  1249     GetInputDataSourceSurface(IN_MORPHOLOGY_IN, srcRect, NEED_COLOR_CHANNELS);
  1250   if (!input) {
  1251     return nullptr;
  1254   int32_t rx = mRadii.width;
  1255   int32_t ry = mRadii.height;
  1257   if (rx == 0 && ry == 0) {
  1258     return input;
  1261   return ApplyMorphology(srcRect, input, aRect, rx, ry, mOperator);
  1264 void
  1265 FilterNodeMorphologySoftware::RequestFromInputsForRect(const IntRect &aRect)
  1267   IntRect srcRect = aRect;
  1268   srcRect.Inflate(mRadii);
  1269   RequestInputRect(IN_MORPHOLOGY_IN, srcRect);
  1272 IntRect
  1273 FilterNodeMorphologySoftware::GetOutputRectInRect(const IntRect& aRect)
  1275   IntRect inflatedSourceRect = aRect;
  1276   inflatedSourceRect.Inflate(mRadii);
  1277   IntRect inputRect = GetInputRectInRect(IN_MORPHOLOGY_IN, inflatedSourceRect);
  1278   if (mOperator == MORPHOLOGY_OPERATOR_ERODE) {
  1279     inputRect.Deflate(mRadii);
  1280   } else {
  1281     inputRect.Inflate(mRadii);
  1283   return inputRect.Intersect(aRect);
  1286 int32_t
  1287 FilterNodeColorMatrixSoftware::InputIndex(uint32_t aInputEnumIndex)
  1289   switch (aInputEnumIndex) {
  1290     case IN_COLOR_MATRIX_IN: return 0;
  1291     default: return -1;
  1295 void
  1296 FilterNodeColorMatrixSoftware::SetAttribute(uint32_t aIndex,
  1297                                             const Matrix5x4 &aMatrix)
  1299   MOZ_ASSERT(aIndex == ATT_COLOR_MATRIX_MATRIX);
  1300   mMatrix = aMatrix;
  1301   Invalidate();
  1304 void
  1305 FilterNodeColorMatrixSoftware::SetAttribute(uint32_t aIndex,
  1306                                             uint32_t aAlphaMode)
  1308   MOZ_ASSERT(aIndex == ATT_COLOR_MATRIX_ALPHA_MODE);
  1309   mAlphaMode = (AlphaMode)aAlphaMode;
  1310   Invalidate();
  1313 static TemporaryRef<DataSourceSurface>
  1314 Premultiply(DataSourceSurface* aSurface)
  1316   if (aSurface->GetFormat() == SurfaceFormat::A8) {
  1317     return aSurface;
  1320   IntSize size = aSurface->GetSize();
  1321   RefPtr<DataSourceSurface> target =
  1322     Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
  1323   if (!target) {
  1324     return nullptr;
  1327   uint8_t* inputData = aSurface->GetData();
  1328   int32_t inputStride = aSurface->Stride();
  1329   uint8_t* targetData = target->GetData();
  1330   int32_t targetStride = target->Stride();
  1332   FilterProcessing::DoPremultiplicationCalculation(
  1333     size, targetData, targetStride, inputData, inputStride);
  1335   return target;
  1338 static TemporaryRef<DataSourceSurface>
  1339 Unpremultiply(DataSourceSurface* aSurface)
  1341   if (aSurface->GetFormat() == SurfaceFormat::A8) {
  1342     return aSurface;
  1345   IntSize size = aSurface->GetSize();
  1346   RefPtr<DataSourceSurface> target =
  1347     Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
  1348   if (!target) {
  1349     return nullptr;
  1352   uint8_t* inputData = aSurface->GetData();
  1353   int32_t inputStride = aSurface->Stride();
  1354   uint8_t* targetData = target->GetData();
  1355   int32_t targetStride = target->Stride();
  1357   FilterProcessing::DoUnpremultiplicationCalculation(
  1358     size, targetData, targetStride, inputData, inputStride);
  1360   return target;
  1363 TemporaryRef<DataSourceSurface>
  1364 FilterNodeColorMatrixSoftware::Render(const IntRect& aRect)
  1366   RefPtr<DataSourceSurface> input =
  1367     GetInputDataSourceSurface(IN_COLOR_MATRIX_IN, aRect, NEED_COLOR_CHANNELS);
  1368   if (!input) {
  1369     return nullptr;
  1372   if (mAlphaMode == ALPHA_MODE_PREMULTIPLIED) {
  1373     input = Unpremultiply(input);
  1376   RefPtr<DataSourceSurface> result =
  1377     FilterProcessing::ApplyColorMatrix(input, mMatrix);
  1379   if (mAlphaMode == ALPHA_MODE_PREMULTIPLIED) {
  1380     result = Premultiply(result);
  1383   return result;
  1386 void
  1387 FilterNodeColorMatrixSoftware::RequestFromInputsForRect(const IntRect &aRect)
  1389   RequestInputRect(IN_COLOR_MATRIX_IN, aRect);
  1392 IntRect
  1393 FilterNodeColorMatrixSoftware::GetOutputRectInRect(const IntRect& aRect)
  1395   return GetInputRectInRect(IN_COLOR_MATRIX_IN, aRect);
  1398 void
  1399 FilterNodeFloodSoftware::SetAttribute(uint32_t aIndex, const Color &aColor)
  1401   MOZ_ASSERT(aIndex == ATT_FLOOD_COLOR);
  1402   mColor = aColor;
  1403   Invalidate();
  1406 static uint32_t
  1407 ColorToBGRA(const Color& aColor)
  1409   union {
  1410     uint32_t color;
  1411     uint8_t components[4];
  1412   };
  1413   components[B8G8R8A8_COMPONENT_BYTEOFFSET_R] = NS_lround(aColor.r * aColor.a * 255.0f);
  1414   components[B8G8R8A8_COMPONENT_BYTEOFFSET_G] = NS_lround(aColor.g * aColor.a * 255.0f);
  1415   components[B8G8R8A8_COMPONENT_BYTEOFFSET_B] = NS_lround(aColor.b * aColor.a * 255.0f);
  1416   components[B8G8R8A8_COMPONENT_BYTEOFFSET_A] = NS_lround(aColor.a * 255.0f);
  1417   return color;
  1420 static SurfaceFormat
  1421 FormatForColor(Color aColor)
  1423   if (aColor.r == 0 && aColor.g == 0 && aColor.b == 0) {
  1424     return SurfaceFormat::A8;
  1426   return SurfaceFormat::B8G8R8A8;
  1429 TemporaryRef<DataSourceSurface>
  1430 FilterNodeFloodSoftware::Render(const IntRect& aRect)
  1432   SurfaceFormat format = FormatForColor(mColor);
  1433   RefPtr<DataSourceSurface> target =
  1434     Factory::CreateDataSourceSurface(aRect.Size(), format);
  1435   if (!target) {
  1436     return nullptr;
  1439   uint8_t* targetData = target->GetData();
  1440   uint32_t stride = target->Stride();
  1442   if (format == SurfaceFormat::B8G8R8A8) {
  1443     uint32_t color = ColorToBGRA(mColor);
  1444     for (int32_t y = 0; y < aRect.height; y++) {
  1445       for (int32_t x = 0; x < aRect.width; x++) {
  1446         *((uint32_t*)targetData + x) = color;
  1448       targetData += stride;
  1450   } else if (format == SurfaceFormat::A8) {
  1451     uint8_t alpha = NS_lround(mColor.a * 255.0f);
  1452     for (int32_t y = 0; y < aRect.height; y++) {
  1453       for (int32_t x = 0; x < aRect.width; x++) {
  1454         targetData[x] = alpha;
  1456       targetData += stride;
  1458   } else {
  1459     MOZ_CRASH();
  1462   return target;
  1465 // Override GetOutput to get around caching. Rendering simple floods is
  1466 // comparatively fast.
  1467 TemporaryRef<DataSourceSurface>
  1468 FilterNodeFloodSoftware::GetOutput(const IntRect& aRect)
  1470   return Render(aRect);
  1473 IntRect
  1474 FilterNodeFloodSoftware::GetOutputRectInRect(const IntRect& aRect)
  1476   if (mColor.a == 0.0f) {
  1477     return IntRect();
  1479   return aRect;
  1482 int32_t
  1483 FilterNodeTileSoftware::InputIndex(uint32_t aInputEnumIndex)
  1485   switch (aInputEnumIndex) {
  1486     case IN_TILE_IN: return 0;
  1487     default: return -1;
  1491 void
  1492 FilterNodeTileSoftware::SetAttribute(uint32_t aIndex,
  1493                                      const IntRect &aSourceRect)
  1495   MOZ_ASSERT(aIndex == ATT_TILE_SOURCE_RECT);
  1496   mSourceRect = IntRect(int32_t(aSourceRect.x), int32_t(aSourceRect.y),
  1497                         int32_t(aSourceRect.width), int32_t(aSourceRect.height));
  1498   Invalidate();
  1501 namespace {
  1502 struct CompareIntRects
  1504   bool operator()(const IntRect& a, const IntRect& b) const
  1506     if (a.x != b.x) {
  1507       return a.x < b.x;
  1509     if (a.y != b.y) {
  1510       return a.y < b.y;
  1512     if (a.width != b.width) {
  1513       return a.width < b.width;
  1515     return a.height < b.height;
  1517 };
  1520 TemporaryRef<DataSourceSurface>
  1521 FilterNodeTileSoftware::Render(const IntRect& aRect)
  1523   if (mSourceRect.IsEmpty()) {
  1524     return nullptr;
  1527   if (mSourceRect.Contains(aRect)) {
  1528     return GetInputDataSourceSurface(IN_TILE_IN, aRect);
  1531   RefPtr<DataSourceSurface> target;
  1533   typedef std::map<IntRect, RefPtr<DataSourceSurface>, CompareIntRects> InputMap;
  1534   InputMap inputs;
  1536   IntPoint startIndex = TileIndex(mSourceRect, aRect.TopLeft());
  1537   IntPoint endIndex = TileIndex(mSourceRect, aRect.BottomRight());
  1538   for (int32_t ix = startIndex.x; ix <= endIndex.x; ix++) {
  1539     for (int32_t iy = startIndex.y; iy <= endIndex.y; iy++) {
  1540       IntPoint sourceToDestOffset(ix * mSourceRect.width,
  1541                                   iy * mSourceRect.height);
  1542       IntRect destRect = aRect.Intersect(mSourceRect + sourceToDestOffset);
  1543       IntRect srcRect = destRect - sourceToDestOffset;
  1544       if (srcRect.IsEmpty()) {
  1545         continue;
  1548       RefPtr<DataSourceSurface> input;
  1549       InputMap::iterator it = inputs.find(srcRect);
  1550       if (it == inputs.end()) {
  1551         input = GetInputDataSourceSurface(IN_TILE_IN, srcRect);
  1552         inputs[srcRect] = input;
  1553       } else {
  1554         input = it->second;
  1556       if (!input) {
  1557         return nullptr;
  1559       if (!target) {
  1560         // We delay creating the target until now because we want to use the
  1561         // same format as our input filter, and we do not actually know the
  1562         // input format before we call GetInputDataSourceSurface.
  1563         target = Factory::CreateDataSourceSurface(aRect.Size(), input->GetFormat());
  1564         if (!target) {
  1565           return nullptr;
  1568       MOZ_ASSERT(input->GetFormat() == target->GetFormat(), "different surface formats from the same input?");
  1570       CopyRect(input, target, srcRect - srcRect.TopLeft(), destRect.TopLeft() - aRect.TopLeft());
  1574   return target;
  1577 void
  1578 FilterNodeTileSoftware::RequestFromInputsForRect(const IntRect &aRect)
  1580   // Do not request anything.
  1581   // Source rects for the tile filter can be discontinuous with large gaps
  1582   // between them. Requesting those from our input filter might cause it to
  1583   // render the whole bounding box of all of them, which would be wasteful.
  1586 IntRect
  1587 FilterNodeTileSoftware::GetOutputRectInRect(const IntRect& aRect)
  1589   return aRect;
  1592 FilterNodeComponentTransferSoftware::FilterNodeComponentTransferSoftware()
  1593  : mDisableR(true)
  1594  , mDisableG(true)
  1595  , mDisableB(true)
  1596  , mDisableA(true)
  1597 {}
  1599 void
  1600 FilterNodeComponentTransferSoftware::SetAttribute(uint32_t aIndex,
  1601                                                   bool aDisable)
  1603   switch (aIndex) {
  1604     case ATT_TRANSFER_DISABLE_R:
  1605       mDisableR = aDisable;
  1606       break;
  1607     case ATT_TRANSFER_DISABLE_G:
  1608       mDisableG = aDisable;
  1609       break;
  1610     case ATT_TRANSFER_DISABLE_B:
  1611       mDisableB = aDisable;
  1612       break;
  1613     case ATT_TRANSFER_DISABLE_A:
  1614       mDisableA = aDisable;
  1615       break;
  1616     default:
  1617       MOZ_CRASH();
  1619   Invalidate();
  1622 void
  1623 FilterNodeComponentTransferSoftware::GenerateLookupTable(ptrdiff_t aComponent,
  1624                                                          uint8_t aTables[4][256],
  1625                                                          bool aDisabled)
  1627   if (aDisabled) {
  1628     static uint8_t sIdentityLookupTable[256];
  1629     static bool sInitializedIdentityLookupTable = false;
  1630     if (!sInitializedIdentityLookupTable) {
  1631       for (int32_t i = 0; i < 256; i++) {
  1632         sIdentityLookupTable[i] = i;
  1634       sInitializedIdentityLookupTable = true;
  1636     memcpy(aTables[aComponent], sIdentityLookupTable, 256);
  1637   } else {
  1638     FillLookupTable(aComponent, aTables[aComponent]);
  1642 template<uint32_t BytesPerPixel>
  1643 static void TransferComponents(DataSourceSurface* aInput,
  1644                                DataSourceSurface* aTarget,
  1645                                const uint8_t aLookupTables[BytesPerPixel][256])
  1647   MOZ_ASSERT(aInput->GetFormat() == aTarget->GetFormat(), "different formats");
  1648   IntSize size = aInput->GetSize();
  1650   uint8_t* sourceData = aInput->GetData();
  1651   uint8_t* targetData = aTarget->GetData();
  1652   uint32_t sourceStride = aInput->Stride();
  1653   uint32_t targetStride = aTarget->Stride();
  1655   for (int32_t y = 0; y < size.height; y++) {
  1656     for (int32_t x = 0; x < size.width; x++) {
  1657       uint32_t sourceIndex = y * sourceStride + x * BytesPerPixel;
  1658       uint32_t targetIndex = y * targetStride + x * BytesPerPixel;
  1659       for (uint32_t i = 0; i < BytesPerPixel; i++) {
  1660         targetData[targetIndex + i] = aLookupTables[i][sourceData[sourceIndex + i]];
  1666 bool
  1667 IsAllZero(uint8_t aLookupTable[256])
  1669   for (int32_t i = 0; i < 256; i++) {
  1670     if (aLookupTable[i] != 0) {
  1671       return false;
  1674   return true;
  1677 TemporaryRef<DataSourceSurface>
  1678 FilterNodeComponentTransferSoftware::Render(const IntRect& aRect)
  1680   if (mDisableR && mDisableG && mDisableB && mDisableA) {
  1681     return GetInputDataSourceSurface(IN_TRANSFER_IN, aRect);
  1684   uint8_t lookupTables[4][256];
  1685   GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_R, lookupTables, mDisableR);
  1686   GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_G, lookupTables, mDisableG);
  1687   GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_B, lookupTables, mDisableB);
  1688   GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_A, lookupTables, mDisableA);
  1690   bool needColorChannels =
  1691     lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_R][0] != 0 ||
  1692     lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_G][0] != 0 ||
  1693     lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_B][0] != 0;
  1695   FormatHint pref = needColorChannels ? NEED_COLOR_CHANNELS : CAN_HANDLE_A8;
  1697   RefPtr<DataSourceSurface> input =
  1698     GetInputDataSourceSurface(IN_TRANSFER_IN, aRect, pref);
  1699   if (!input) {
  1700     return nullptr;
  1703   if (input->GetFormat() == SurfaceFormat::B8G8R8A8 && !needColorChannels) {
  1704     bool colorChannelsBecomeBlack =
  1705       IsAllZero(lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_R]) &&
  1706       IsAllZero(lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_G]) &&
  1707       IsAllZero(lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_B]);
  1709     if (colorChannelsBecomeBlack) {
  1710       input = FilterProcessing::ExtractAlpha(input);
  1714   SurfaceFormat format = input->GetFormat();
  1715   if (format == SurfaceFormat::A8 && mDisableA) {
  1716     return input;
  1719   RefPtr<DataSourceSurface> target =
  1720     Factory::CreateDataSourceSurface(aRect.Size(), format);
  1721   if (!target) {
  1722     return nullptr;
  1725   if (format == SurfaceFormat::A8) {
  1726     TransferComponents<1>(input, target, &lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_A]);
  1727   } else {
  1728     TransferComponents<4>(input, target, lookupTables);
  1731   return target;
  1734 void
  1735 FilterNodeComponentTransferSoftware::RequestFromInputsForRect(const IntRect &aRect)
  1737   RequestInputRect(IN_TRANSFER_IN, aRect);
  1740 IntRect
  1741 FilterNodeComponentTransferSoftware::GetOutputRectInRect(const IntRect& aRect)
  1743   return GetInputRectInRect(IN_TRANSFER_IN, aRect);
  1746 int32_t
  1747 FilterNodeComponentTransferSoftware::InputIndex(uint32_t aInputEnumIndex)
  1749   switch (aInputEnumIndex) {
  1750     case IN_TRANSFER_IN: return 0;
  1751     default: return -1;
  1755 void
  1756 FilterNodeTableTransferSoftware::SetAttribute(uint32_t aIndex,
  1757                                               const Float* aFloat,
  1758                                               uint32_t aSize)
  1760   std::vector<Float> table(aFloat, aFloat + aSize);
  1761   switch (aIndex) {
  1762     case ATT_TABLE_TRANSFER_TABLE_R:
  1763       mTableR = table;
  1764       break;
  1765     case ATT_TABLE_TRANSFER_TABLE_G:
  1766       mTableG = table;
  1767       break;
  1768     case ATT_TABLE_TRANSFER_TABLE_B:
  1769       mTableB = table;
  1770       break;
  1771     case ATT_TABLE_TRANSFER_TABLE_A:
  1772       mTableA = table;
  1773       break;
  1774     default:
  1775       MOZ_CRASH();
  1777   Invalidate();
  1780 void
  1781 FilterNodeTableTransferSoftware::FillLookupTable(ptrdiff_t aComponent,
  1782                                                  uint8_t aTable[256])
  1784   switch (aComponent) {
  1785     case B8G8R8A8_COMPONENT_BYTEOFFSET_R:
  1786       FillLookupTableImpl(mTableR, aTable);
  1787       break;
  1788     case B8G8R8A8_COMPONENT_BYTEOFFSET_G:
  1789       FillLookupTableImpl(mTableG, aTable);
  1790       break;
  1791     case B8G8R8A8_COMPONENT_BYTEOFFSET_B:
  1792       FillLookupTableImpl(mTableB, aTable);
  1793       break;
  1794     case B8G8R8A8_COMPONENT_BYTEOFFSET_A:
  1795       FillLookupTableImpl(mTableA, aTable);
  1796       break;
  1797     default:
  1798       MOZ_ASSERT(false, "unknown component");
  1799       break;
  1803 void
  1804 FilterNodeTableTransferSoftware::FillLookupTableImpl(std::vector<Float>& aTableValues,
  1805                                                      uint8_t aTable[256])
  1807   uint32_t tvLength = aTableValues.size();
  1808   if (tvLength < 2) {
  1809     return;
  1812   for (size_t i = 0; i < 256; i++) {
  1813     uint32_t k = (i * (tvLength - 1)) / 255;
  1814     Float v1 = aTableValues[k];
  1815     Float v2 = aTableValues[std::min(k + 1, tvLength - 1)];
  1816     int32_t val =
  1817       int32_t(255 * (v1 + (i/255.0f - k/float(tvLength-1))*(tvLength - 1)*(v2 - v1)));
  1818     val = std::min(255, val);
  1819     val = std::max(0, val);
  1820     aTable[i] = val;
  1824 void
  1825 FilterNodeDiscreteTransferSoftware::SetAttribute(uint32_t aIndex,
  1826                                               const Float* aFloat,
  1827                                               uint32_t aSize)
  1829   std::vector<Float> discrete(aFloat, aFloat + aSize);
  1830   switch (aIndex) {
  1831     case ATT_DISCRETE_TRANSFER_TABLE_R:
  1832       mTableR = discrete;
  1833       break;
  1834     case ATT_DISCRETE_TRANSFER_TABLE_G:
  1835       mTableG = discrete;
  1836       break;
  1837     case ATT_DISCRETE_TRANSFER_TABLE_B:
  1838       mTableB = discrete;
  1839       break;
  1840     case ATT_DISCRETE_TRANSFER_TABLE_A:
  1841       mTableA = discrete;
  1842       break;
  1843     default:
  1844       MOZ_CRASH();
  1846   Invalidate();
  1849 void
  1850 FilterNodeDiscreteTransferSoftware::FillLookupTable(ptrdiff_t aComponent,
  1851                                                     uint8_t aTable[256])
  1853   switch (aComponent) {
  1854     case B8G8R8A8_COMPONENT_BYTEOFFSET_R:
  1855       FillLookupTableImpl(mTableR, aTable);
  1856       break;
  1857     case B8G8R8A8_COMPONENT_BYTEOFFSET_G:
  1858       FillLookupTableImpl(mTableG, aTable);
  1859       break;
  1860     case B8G8R8A8_COMPONENT_BYTEOFFSET_B:
  1861       FillLookupTableImpl(mTableB, aTable);
  1862       break;
  1863     case B8G8R8A8_COMPONENT_BYTEOFFSET_A:
  1864       FillLookupTableImpl(mTableA, aTable);
  1865       break;
  1866     default:
  1867       MOZ_ASSERT(false, "unknown component");
  1868       break;
  1872 void
  1873 FilterNodeDiscreteTransferSoftware::FillLookupTableImpl(std::vector<Float>& aTableValues,
  1874                                                         uint8_t aTable[256])
  1876   uint32_t tvLength = aTableValues.size();
  1877   if (tvLength < 1) {
  1878     return;
  1881   for (size_t i = 0; i < 256; i++) {
  1882     uint32_t k = (i * tvLength) / 255;
  1883     k = std::min(k, tvLength - 1);
  1884     Float v = aTableValues[k];
  1885     int32_t val = NS_lround(255 * v);
  1886     val = std::min(255, val);
  1887     val = std::max(0, val);
  1888     aTable[i] = val;
  1892 FilterNodeLinearTransferSoftware::FilterNodeLinearTransferSoftware()
  1893  : mSlopeR(0)
  1894  , mSlopeG(0)
  1895  , mSlopeB(0)
  1896  , mSlopeA(0)
  1897  , mInterceptR(0)
  1898  , mInterceptG(0)
  1899  , mInterceptB(0)
  1900  , mInterceptA(0)
  1901 {}
  1903 void
  1904 FilterNodeLinearTransferSoftware::SetAttribute(uint32_t aIndex,
  1905                                                Float aValue)
  1907   switch (aIndex) {
  1908     case ATT_LINEAR_TRANSFER_SLOPE_R:
  1909       mSlopeR = aValue;
  1910       break;
  1911     case ATT_LINEAR_TRANSFER_INTERCEPT_R:
  1912       mInterceptR = aValue;
  1913       break;
  1914     case ATT_LINEAR_TRANSFER_SLOPE_G:
  1915       mSlopeG = aValue;
  1916       break;
  1917     case ATT_LINEAR_TRANSFER_INTERCEPT_G:
  1918       mInterceptG = aValue;
  1919       break;
  1920     case ATT_LINEAR_TRANSFER_SLOPE_B:
  1921       mSlopeB = aValue;
  1922       break;
  1923     case ATT_LINEAR_TRANSFER_INTERCEPT_B:
  1924       mInterceptB = aValue;
  1925       break;
  1926     case ATT_LINEAR_TRANSFER_SLOPE_A:
  1927       mSlopeA = aValue;
  1928       break;
  1929     case ATT_LINEAR_TRANSFER_INTERCEPT_A:
  1930       mInterceptA = aValue;
  1931       break;
  1932     default:
  1933       MOZ_CRASH();
  1935   Invalidate();
  1938 void
  1939 FilterNodeLinearTransferSoftware::FillLookupTable(ptrdiff_t aComponent,
  1940                                                   uint8_t aTable[256])
  1942   switch (aComponent) {
  1943     case B8G8R8A8_COMPONENT_BYTEOFFSET_R:
  1944       FillLookupTableImpl(mSlopeR, mInterceptR, aTable);
  1945       break;
  1946     case B8G8R8A8_COMPONENT_BYTEOFFSET_G:
  1947       FillLookupTableImpl(mSlopeG, mInterceptG, aTable);
  1948       break;
  1949     case B8G8R8A8_COMPONENT_BYTEOFFSET_B:
  1950       FillLookupTableImpl(mSlopeB, mInterceptB, aTable);
  1951       break;
  1952     case B8G8R8A8_COMPONENT_BYTEOFFSET_A:
  1953       FillLookupTableImpl(mSlopeA, mInterceptA, aTable);
  1954       break;
  1955     default:
  1956       MOZ_ASSERT(false, "unknown component");
  1957       break;
  1961 void
  1962 FilterNodeLinearTransferSoftware::FillLookupTableImpl(Float aSlope,
  1963                                                       Float aIntercept,
  1964                                                       uint8_t aTable[256])
  1966   for (size_t i = 0; i < 256; i++) {
  1967     int32_t val = NS_lround(aSlope * i + 255 * aIntercept);
  1968     val = std::min(255, val);
  1969     val = std::max(0, val);
  1970     aTable[i] = val;
  1974 FilterNodeGammaTransferSoftware::FilterNodeGammaTransferSoftware()
  1975  : mAmplitudeR(0)
  1976  , mAmplitudeG(0)
  1977  , mAmplitudeB(0)
  1978  , mAmplitudeA(0)
  1979  , mExponentR(0)
  1980  , mExponentG(0)
  1981  , mExponentB(0)
  1982  , mExponentA(0)
  1983 {}
  1985 void
  1986 FilterNodeGammaTransferSoftware::SetAttribute(uint32_t aIndex,
  1987                                               Float aValue)
  1989   switch (aIndex) {
  1990     case ATT_GAMMA_TRANSFER_AMPLITUDE_R:
  1991       mAmplitudeR = aValue;
  1992       break;
  1993     case ATT_GAMMA_TRANSFER_EXPONENT_R:
  1994       mExponentR = aValue;
  1995       break;
  1996     case ATT_GAMMA_TRANSFER_OFFSET_R:
  1997       mOffsetR = aValue;
  1998       break;
  1999     case ATT_GAMMA_TRANSFER_AMPLITUDE_G:
  2000       mAmplitudeG = aValue;
  2001       break;
  2002     case ATT_GAMMA_TRANSFER_EXPONENT_G:
  2003       mExponentG = aValue;
  2004       break;
  2005     case ATT_GAMMA_TRANSFER_OFFSET_G:
  2006       mOffsetG = aValue;
  2007       break;
  2008     case ATT_GAMMA_TRANSFER_AMPLITUDE_B:
  2009       mAmplitudeB = aValue;
  2010       break;
  2011     case ATT_GAMMA_TRANSFER_EXPONENT_B:
  2012       mExponentB = aValue;
  2013       break;
  2014     case ATT_GAMMA_TRANSFER_OFFSET_B:
  2015       mOffsetB = aValue;
  2016       break;
  2017     case ATT_GAMMA_TRANSFER_AMPLITUDE_A:
  2018       mAmplitudeA = aValue;
  2019       break;
  2020     case ATT_GAMMA_TRANSFER_EXPONENT_A:
  2021       mExponentA = aValue;
  2022       break;
  2023     case ATT_GAMMA_TRANSFER_OFFSET_A:
  2024       mOffsetA = aValue;
  2025       break;
  2026     default:
  2027       MOZ_CRASH();
  2029   Invalidate();
  2032 void
  2033 FilterNodeGammaTransferSoftware::FillLookupTable(ptrdiff_t aComponent,
  2034                                                  uint8_t aTable[256])
  2036   switch (aComponent) {
  2037     case B8G8R8A8_COMPONENT_BYTEOFFSET_R:
  2038       FillLookupTableImpl(mAmplitudeR, mExponentR, mOffsetR, aTable);
  2039       break;
  2040     case B8G8R8A8_COMPONENT_BYTEOFFSET_G:
  2041       FillLookupTableImpl(mAmplitudeG, mExponentG, mOffsetG, aTable);
  2042       break;
  2043     case B8G8R8A8_COMPONENT_BYTEOFFSET_B:
  2044       FillLookupTableImpl(mAmplitudeB, mExponentB, mOffsetB, aTable);
  2045       break;
  2046     case B8G8R8A8_COMPONENT_BYTEOFFSET_A:
  2047       FillLookupTableImpl(mAmplitudeA, mExponentA, mOffsetA, aTable);
  2048       break;
  2049     default:
  2050       MOZ_ASSERT(false, "unknown component");
  2051       break;
  2055 void
  2056 FilterNodeGammaTransferSoftware::FillLookupTableImpl(Float aAmplitude,
  2057                                                      Float aExponent,
  2058                                                      Float aOffset,
  2059                                                      uint8_t aTable[256])
  2061   for (size_t i = 0; i < 256; i++) {
  2062     int32_t val = NS_lround(255 * (aAmplitude * pow(i / 255.0f, aExponent) + aOffset));
  2063     val = std::min(255, val);
  2064     val = std::max(0, val);
  2065     aTable[i] = val;
  2069 FilterNodeConvolveMatrixSoftware::FilterNodeConvolveMatrixSoftware()
  2070  : mDivisor(0)
  2071  , mBias(0)
  2072  , mEdgeMode(EDGE_MODE_DUPLICATE)
  2073  , mPreserveAlpha(false)
  2074 {}
  2076 int32_t
  2077 FilterNodeConvolveMatrixSoftware::InputIndex(uint32_t aInputEnumIndex)
  2079   switch (aInputEnumIndex) {
  2080     case IN_CONVOLVE_MATRIX_IN: return 0;
  2081     default: return -1;
  2085 void
  2086 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex,
  2087                                                const IntSize &aKernelSize)
  2089   MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_KERNEL_SIZE);
  2090   mKernelSize = aKernelSize;
  2091   Invalidate();
  2094 void
  2095 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex,
  2096                                                const Float *aMatrix,
  2097                                                uint32_t aSize)
  2099   MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_KERNEL_MATRIX);
  2100   mKernelMatrix = std::vector<Float>(aMatrix, aMatrix + aSize);
  2101   Invalidate();
  2104 void
  2105 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, Float aValue)
  2107   switch (aIndex) {
  2108     case ATT_CONVOLVE_MATRIX_DIVISOR:
  2109       mDivisor = aValue;
  2110       break;
  2111     case ATT_CONVOLVE_MATRIX_BIAS:
  2112       mBias = aValue;
  2113       break;
  2114     default:
  2115       MOZ_CRASH();
  2117   Invalidate();
  2120 void
  2121 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, const Size &aKernelUnitLength)
  2123   switch (aIndex) {
  2124     case ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH:
  2125       mKernelUnitLength = aKernelUnitLength;
  2126       break;
  2127     default:
  2128       MOZ_CRASH();
  2130   Invalidate();
  2133 void
  2134 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex,
  2135                                                const IntPoint &aTarget)
  2137   MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_TARGET);
  2138   mTarget = aTarget;
  2139   Invalidate();
  2142 void
  2143 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex,
  2144                                                const IntRect &aSourceRect)
  2146   MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_SOURCE_RECT);
  2147   mSourceRect = aSourceRect;
  2148   Invalidate();
  2151 void
  2152 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex,
  2153                                                uint32_t aEdgeMode)
  2155   MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_EDGE_MODE);
  2156   mEdgeMode = static_cast<ConvolveMatrixEdgeMode>(aEdgeMode);
  2157   Invalidate();
  2160 void
  2161 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex,
  2162                                                bool aPreserveAlpha)
  2164   MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA);
  2165   mPreserveAlpha = aPreserveAlpha;
  2166   Invalidate();
  2169 #ifdef DEBUG
  2170 static bool sColorSamplingAccessControlEnabled = false;
  2171 static uint8_t* sColorSamplingAccessControlStart = nullptr;
  2172 static uint8_t* sColorSamplingAccessControlEnd = nullptr;
  2174 struct DebugOnlyAutoColorSamplingAccessControl
  2176   DebugOnlyAutoColorSamplingAccessControl(DataSourceSurface* aSurface)
  2178     sColorSamplingAccessControlStart = aSurface->GetData();
  2179     sColorSamplingAccessControlEnd = sColorSamplingAccessControlStart +
  2180       aSurface->Stride() * aSurface->GetSize().height;
  2181     sColorSamplingAccessControlEnabled = true;
  2184   ~DebugOnlyAutoColorSamplingAccessControl()
  2186     sColorSamplingAccessControlEnabled = false;
  2188 };
  2190 static inline void
  2191 DebugOnlyCheckColorSamplingAccess(const uint8_t* aSampleAddress)
  2193   if (sColorSamplingAccessControlEnabled) {
  2194     MOZ_ASSERT(aSampleAddress >= sColorSamplingAccessControlStart, "accessing before start");
  2195     MOZ_ASSERT(aSampleAddress < sColorSamplingAccessControlEnd, "accessing after end");
  2198 #else
  2199 typedef DebugOnly<DataSourceSurface*> DebugOnlyAutoColorSamplingAccessControl;
  2200 #define DebugOnlyCheckColorSamplingAccess(address)
  2201 #endif
  2203 static inline uint8_t
  2204 ColorComponentAtPoint(const uint8_t *aData, int32_t aStride, int32_t x, int32_t y, size_t bpp, ptrdiff_t c)
  2206   DebugOnlyCheckColorSamplingAccess(&aData[y * aStride + bpp * x + c]);
  2207   return aData[y * aStride + bpp * x + c];
  2210 static inline int32_t
  2211 ColorAtPoint(const uint8_t *aData, int32_t aStride, int32_t x, int32_t y)
  2213   DebugOnlyCheckColorSamplingAccess(aData + y * aStride + 4 * x);
  2214   return *(uint32_t*)(aData + y * aStride + 4 * x);
  2217 // Accepts fractional x & y and does bilinear interpolation.
  2218 // Only call this if the pixel (floor(x)+1, floor(y)+1) is accessible.
  2219 static inline uint8_t
  2220 ColorComponentAtPoint(const uint8_t *aData, int32_t aStride, Float x, Float y, size_t bpp, ptrdiff_t c)
  2222   const uint32_t f = 256;
  2223   const int32_t lx = floor(x);
  2224   const int32_t ly = floor(y);
  2225   const int32_t tux = uint32_t((x - lx) * f);
  2226   const int32_t tlx = f - tux;
  2227   const int32_t tuy = uint32_t((y - ly) * f);
  2228   const int32_t tly = f - tuy;
  2229   const uint8_t &cll = ColorComponentAtPoint(aData, aStride, lx,     ly,     bpp, c);
  2230   const uint8_t &cul = ColorComponentAtPoint(aData, aStride, lx + 1, ly,     bpp, c);
  2231   const uint8_t &clu = ColorComponentAtPoint(aData, aStride, lx,     ly + 1, bpp, c);
  2232   const uint8_t &cuu = ColorComponentAtPoint(aData, aStride, lx + 1, ly + 1, bpp, c);
  2233   return ((cll * tlx + cul * tux) * tly +
  2234           (clu * tlx + cuu * tux) * tuy + f * f / 2) / (f * f);
  2237 static inline uint32_t
  2238 ColorAtPoint(const uint8_t *aData, int32_t aStride, Float x, Float y)
  2240   return ColorComponentAtPoint(aData, aStride, x, y, 4, 0) |
  2241          (ColorComponentAtPoint(aData, aStride, x, y, 4, 1) << 8) |
  2242          (ColorComponentAtPoint(aData, aStride, x, y, 4, 2) << 16) |
  2243          (ColorComponentAtPoint(aData, aStride, x, y, 4, 3) << 24);
  2246 static int32_t
  2247 ClampToNonZero(int32_t a)
  2249   return a * (a >= 0);
  2252 template<typename CoordType>
  2253 static void
  2254 ConvolvePixel(const uint8_t *aSourceData,
  2255               uint8_t *aTargetData,
  2256               int32_t aWidth, int32_t aHeight,
  2257               int32_t aSourceStride, int32_t aTargetStride,
  2258               int32_t aX, int32_t aY,
  2259               const int32_t *aKernel,
  2260               int32_t aBias, int32_t shiftL, int32_t shiftR,
  2261               bool aPreserveAlpha,
  2262               int32_t aOrderX, int32_t aOrderY,
  2263               int32_t aTargetX, int32_t aTargetY,
  2264               CoordType aKernelUnitLengthX,
  2265               CoordType aKernelUnitLengthY)
  2267   int32_t sum[4] = {0, 0, 0, 0};
  2268   int32_t offsets[4] = { B8G8R8A8_COMPONENT_BYTEOFFSET_R,
  2269                          B8G8R8A8_COMPONENT_BYTEOFFSET_G,
  2270                          B8G8R8A8_COMPONENT_BYTEOFFSET_B,
  2271                          B8G8R8A8_COMPONENT_BYTEOFFSET_A };
  2272   int32_t channels = aPreserveAlpha ? 3 : 4;
  2273   int32_t roundingAddition = shiftL == 0 ? 0 : 1 << (shiftL - 1);
  2275   for (int32_t y = 0; y < aOrderY; y++) {
  2276     CoordType sampleY = aY + (y - aTargetY) * aKernelUnitLengthY;
  2277     for (int32_t x = 0; x < aOrderX; x++) {
  2278       CoordType sampleX = aX + (x - aTargetX) * aKernelUnitLengthX;
  2279       for (int32_t i = 0; i < channels; i++) {
  2280         sum[i] += aKernel[aOrderX * y + x] *
  2281           ColorComponentAtPoint(aSourceData, aSourceStride,
  2282                                 sampleX, sampleY, 4, offsets[i]);
  2286   for (int32_t i = 0; i < channels; i++) {
  2287     int32_t clamped = umin(ClampToNonZero(sum[i] + aBias), 255 << shiftL >> shiftR);
  2288     aTargetData[aY * aTargetStride + 4 * aX + offsets[i]] =
  2289       (clamped + roundingAddition) << shiftR >> shiftL;
  2291   if (aPreserveAlpha) {
  2292     aTargetData[aY * aTargetStride + 4 * aX + B8G8R8A8_COMPONENT_BYTEOFFSET_A] =
  2293       aSourceData[aY * aSourceStride + 4 * aX + B8G8R8A8_COMPONENT_BYTEOFFSET_A];
  2297 TemporaryRef<DataSourceSurface>
  2298 FilterNodeConvolveMatrixSoftware::Render(const IntRect& aRect)
  2300   if (mKernelUnitLength.width == floor(mKernelUnitLength.width) &&
  2301       mKernelUnitLength.height == floor(mKernelUnitLength.height)) {
  2302     return DoRender(aRect, (int32_t)mKernelUnitLength.width, (int32_t)mKernelUnitLength.height);
  2304   return DoRender(aRect, mKernelUnitLength.width, mKernelUnitLength.height);
  2307 static std::vector<Float>
  2308 ReversedVector(const std::vector<Float> &aVector)
  2310   size_t length = aVector.size();
  2311   std::vector<Float> result(length, 0);
  2312   for (size_t i = 0; i < length; i++) {
  2313     result[length - 1 - i] = aVector[i];
  2315   return result;
  2318 static std::vector<Float>
  2319 ScaledVector(const std::vector<Float> &aVector, Float aDivisor)
  2321   size_t length = aVector.size();
  2322   std::vector<Float> result(length, 0);
  2323   for (size_t i = 0; i < length; i++) {
  2324     result[i] = aVector[i] / aDivisor;
  2326   return result;
  2329 static Float
  2330 MaxVectorSum(const std::vector<Float> &aVector)
  2332   Float sum = 0;
  2333   size_t length = aVector.size();
  2334   for (size_t i = 0; i < length; i++) {
  2335     if (aVector[i] > 0) {
  2336       sum += aVector[i];
  2339   return sum;
  2342 // Returns shiftL and shiftR in such a way that
  2343 // a << shiftL >> shiftR is roughly a * aFloat.
  2344 static void
  2345 TranslateDoubleToShifts(double aDouble, int32_t &aShiftL, int32_t &aShiftR)
  2347   aShiftL = 0;
  2348   aShiftR = 0;
  2349   if (aDouble <= 0) {
  2350     MOZ_CRASH();
  2352   if (aDouble < 1) {
  2353     while (1 << (aShiftR + 1) < 1 / aDouble) {
  2354       aShiftR++;
  2356   } else {
  2357     while (1 << (aShiftL + 1) < aDouble) {
  2358       aShiftL++;
  2363 template<typename CoordType>
  2364 TemporaryRef<DataSourceSurface>
  2365 FilterNodeConvolveMatrixSoftware::DoRender(const IntRect& aRect,
  2366                                            CoordType aKernelUnitLengthX,
  2367                                            CoordType aKernelUnitLengthY)
  2369   if (mKernelSize.width <= 0 || mKernelSize.height <= 0 ||
  2370       mKernelMatrix.size() != uint32_t(mKernelSize.width * mKernelSize.height) ||
  2371       !IntRect(IntPoint(0, 0), mKernelSize).Contains(mTarget) ||
  2372       mDivisor == 0) {
  2373     return Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8);
  2376   IntRect srcRect = InflatedSourceRect(aRect);
  2378   // Inflate the source rect by another pixel because the bilinear filtering in
  2379   // ColorComponentAtPoint may want to access the margins.
  2380   srcRect.Inflate(1);
  2382   RefPtr<DataSourceSurface> input =
  2383     GetInputDataSourceSurface(IN_CONVOLVE_MATRIX_IN, srcRect, NEED_COLOR_CHANNELS, mEdgeMode, &mSourceRect);
  2385   if (!input) {
  2386     return nullptr;
  2389   DebugOnlyAutoColorSamplingAccessControl accessControl(input);
  2391   RefPtr<DataSourceSurface> target =
  2392     Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8);
  2393   if (!target) {
  2394     return nullptr;
  2396   ClearDataSourceSurface(target);
  2398   IntPoint offset = aRect.TopLeft() - srcRect.TopLeft();
  2400   uint8_t* sourceData = DataAtOffset(input, offset);
  2401   int32_t sourceStride = input->Stride();
  2402   uint8_t* targetData = target->GetData();
  2403   int32_t targetStride = target->Stride();
  2405   // Why exactly are we reversing the kernel?
  2406   std::vector<Float> kernel = ReversedVector(mKernelMatrix);
  2407   kernel = ScaledVector(kernel, mDivisor);
  2408   Float maxResultAbs = std::max(MaxVectorSum(kernel) + mBias,
  2409                                 MaxVectorSum(ScaledVector(kernel, -1)) - mBias);
  2410   maxResultAbs = std::max(maxResultAbs, 1.0f);
  2412   double idealFactor = INT32_MAX / 2.0 / maxResultAbs / 255.0 * 0.999;
  2413   MOZ_ASSERT(255.0 * maxResultAbs * idealFactor <= INT32_MAX / 2.0, "badly chosen float-to-int scale");
  2414   int32_t shiftL, shiftR;
  2415   TranslateDoubleToShifts(idealFactor, shiftL, shiftR);
  2416   double factorFromShifts = Float(1 << shiftL) / Float(1 << shiftR);
  2417   MOZ_ASSERT(255.0 * maxResultAbs * factorFromShifts <= INT32_MAX / 2.0, "badly chosen float-to-int scale");
  2419   int32_t* intKernel = new int32_t[kernel.size()];
  2420   for (size_t i = 0; i < kernel.size(); i++) {
  2421     intKernel[i] = NS_lround(kernel[i] * factorFromShifts);
  2423   int32_t bias = NS_lround(mBias * 255 * factorFromShifts);
  2425   for (int32_t y = 0; y < aRect.height; y++) {
  2426     for (int32_t x = 0; x < aRect.width; x++) {
  2427       ConvolvePixel(sourceData, targetData,
  2428                     aRect.width, aRect.height, sourceStride, targetStride,
  2429                     x, y, intKernel, bias, shiftL, shiftR, mPreserveAlpha,
  2430                     mKernelSize.width, mKernelSize.height, mTarget.x, mTarget.y,
  2431                     aKernelUnitLengthX, aKernelUnitLengthY);
  2434   delete[] intKernel;
  2436   return target;
  2439 void
  2440 FilterNodeConvolveMatrixSoftware::RequestFromInputsForRect(const IntRect &aRect)
  2442   RequestInputRect(IN_CONVOLVE_MATRIX_IN, InflatedSourceRect(aRect));
  2445 IntRect
  2446 FilterNodeConvolveMatrixSoftware::InflatedSourceRect(const IntRect &aDestRect)
  2448   if (aDestRect.IsEmpty()) {
  2449     return IntRect();
  2452   IntMargin margin;
  2453   margin.left = ceil(mTarget.x * mKernelUnitLength.width);
  2454   margin.top = ceil(mTarget.y * mKernelUnitLength.height);
  2455   margin.right = ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width);
  2456   margin.bottom = ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height);
  2458   IntRect srcRect = aDestRect;
  2459   srcRect.Inflate(margin);
  2460   return srcRect;
  2463 IntRect
  2464 FilterNodeConvolveMatrixSoftware::InflatedDestRect(const IntRect &aSourceRect)
  2466   if (aSourceRect.IsEmpty()) {
  2467     return IntRect();
  2470   IntMargin margin;
  2471   margin.left = ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width);
  2472   margin.top = ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height);
  2473   margin.right = ceil(mTarget.x * mKernelUnitLength.width);
  2474   margin.bottom = ceil(mTarget.y * mKernelUnitLength.height);
  2476   IntRect destRect = aSourceRect;
  2477   destRect.Inflate(margin);
  2478   return destRect;
  2481 IntRect
  2482 FilterNodeConvolveMatrixSoftware::GetOutputRectInRect(const IntRect& aRect)
  2484   IntRect srcRequest = InflatedSourceRect(aRect);
  2485   IntRect srcOutput = GetInputRectInRect(IN_COLOR_MATRIX_IN, srcRequest);
  2486   return InflatedDestRect(srcOutput).Intersect(aRect);
  2489 FilterNodeDisplacementMapSoftware::FilterNodeDisplacementMapSoftware()
  2490  : mScale(0.0f)
  2491  , mChannelX(COLOR_CHANNEL_R)
  2492  , mChannelY(COLOR_CHANNEL_G)
  2493 {}
  2495 int32_t
  2496 FilterNodeDisplacementMapSoftware::InputIndex(uint32_t aInputEnumIndex)
  2498   switch (aInputEnumIndex) {
  2499     case IN_DISPLACEMENT_MAP_IN: return 0;
  2500     case IN_DISPLACEMENT_MAP_IN2: return 1;
  2501     default: return -1;
  2505 void
  2506 FilterNodeDisplacementMapSoftware::SetAttribute(uint32_t aIndex,
  2507                                                 Float aScale)
  2509   MOZ_ASSERT(aIndex == ATT_DISPLACEMENT_MAP_SCALE);
  2510   mScale = aScale;
  2511   Invalidate();
  2514 void
  2515 FilterNodeDisplacementMapSoftware::SetAttribute(uint32_t aIndex, uint32_t aValue)
  2517   switch (aIndex) {
  2518     case ATT_DISPLACEMENT_MAP_X_CHANNEL:
  2519       mChannelX = static_cast<ColorChannel>(aValue);
  2520       break;
  2521     case ATT_DISPLACEMENT_MAP_Y_CHANNEL:
  2522       mChannelY = static_cast<ColorChannel>(aValue);
  2523       break;
  2524     default:
  2525       MOZ_CRASH();
  2527   Invalidate();
  2530 TemporaryRef<DataSourceSurface>
  2531 FilterNodeDisplacementMapSoftware::Render(const IntRect& aRect)
  2533   IntRect srcRect = InflatedSourceOrDestRect(aRect);
  2534   RefPtr<DataSourceSurface> input =
  2535     GetInputDataSourceSurface(IN_DISPLACEMENT_MAP_IN, srcRect, NEED_COLOR_CHANNELS);
  2536   RefPtr<DataSourceSurface> map =
  2537     GetInputDataSourceSurface(IN_DISPLACEMENT_MAP_IN2, aRect, NEED_COLOR_CHANNELS);
  2538   RefPtr<DataSourceSurface> target =
  2539     Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8);
  2540   if (!input || !map || !target) {
  2541     return nullptr;
  2544   IntPoint offset = aRect.TopLeft() - srcRect.TopLeft();
  2546   uint8_t* sourceData = DataAtOffset(input, offset);
  2547   int32_t sourceStride = input->Stride();
  2548   uint8_t* mapData = map->GetData();
  2549   int32_t mapStride = map->Stride();
  2550   uint8_t* targetData = target->GetData();
  2551   int32_t targetStride = target->Stride();
  2553   static const ptrdiff_t channelMap[4] = {
  2554                              B8G8R8A8_COMPONENT_BYTEOFFSET_R,
  2555                              B8G8R8A8_COMPONENT_BYTEOFFSET_G,
  2556                              B8G8R8A8_COMPONENT_BYTEOFFSET_B,
  2557                              B8G8R8A8_COMPONENT_BYTEOFFSET_A };
  2558   uint16_t xChannel = channelMap[mChannelX];
  2559   uint16_t yChannel = channelMap[mChannelY];
  2561   float scaleOver255 = mScale / 255.0f;
  2562   float scaleAdjustment = -0.5f * mScale;
  2564   for (int32_t y = 0; y < aRect.height; y++) {
  2565     for (int32_t x = 0; x < aRect.width; x++) {
  2566       uint32_t mapIndex = y * mapStride + 4 * x;
  2567       uint32_t targIndex = y * targetStride + 4 * x;
  2568       int32_t sourceX = x +
  2569         scaleOver255 * mapData[mapIndex + xChannel] + scaleAdjustment;
  2570       int32_t sourceY = y +
  2571         scaleOver255 * mapData[mapIndex + yChannel] + scaleAdjustment;
  2572       *(uint32_t*)(targetData + targIndex) =
  2573         ColorAtPoint(sourceData, sourceStride, sourceX, sourceY);
  2577   return target;
  2580 void
  2581 FilterNodeDisplacementMapSoftware::RequestFromInputsForRect(const IntRect &aRect)
  2583   RequestInputRect(IN_DISPLACEMENT_MAP_IN, InflatedSourceOrDestRect(aRect));
  2584   RequestInputRect(IN_DISPLACEMENT_MAP_IN2, aRect);
  2587 IntRect
  2588 FilterNodeDisplacementMapSoftware::InflatedSourceOrDestRect(const IntRect &aDestOrSourceRect)
  2590   IntRect sourceOrDestRect = aDestOrSourceRect;
  2591   sourceOrDestRect.Inflate(ceil(fabs(mScale) / 2));
  2592   return sourceOrDestRect;
  2595 IntRect
  2596 FilterNodeDisplacementMapSoftware::GetOutputRectInRect(const IntRect& aRect)
  2598   IntRect srcRequest = InflatedSourceOrDestRect(aRect);
  2599   IntRect srcOutput = GetInputRectInRect(IN_DISPLACEMENT_MAP_IN, srcRequest);
  2600   return InflatedSourceOrDestRect(srcOutput).Intersect(aRect);
  2603 FilterNodeTurbulenceSoftware::FilterNodeTurbulenceSoftware()
  2604  : mNumOctaves(0)
  2605  , mSeed(0)
  2606  , mStitchable(false)
  2607  , mType(TURBULENCE_TYPE_TURBULENCE)
  2608 {}
  2610 int32_t
  2611 FilterNodeTurbulenceSoftware::InputIndex(uint32_t aInputEnumIndex)
  2613   return -1;
  2616 void
  2617 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, const Size &aBaseFrequency)
  2619   switch (aIndex) {
  2620     case ATT_TURBULENCE_BASE_FREQUENCY:
  2621       mBaseFrequency = aBaseFrequency;
  2622       break;
  2623     default:
  2624       MOZ_CRASH();
  2625       break;
  2627   Invalidate();
  2630 void
  2631 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, const IntRect &aRect)
  2633   switch (aIndex) {
  2634     case ATT_TURBULENCE_RECT:
  2635       mRenderRect = aRect;
  2636       break;
  2637     default:
  2638       MOZ_CRASH();
  2639       break;
  2641   Invalidate();
  2644 void
  2645 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, bool aStitchable)
  2647   MOZ_ASSERT(aIndex == ATT_TURBULENCE_STITCHABLE);
  2648   mStitchable = aStitchable;
  2649   Invalidate();
  2652 void
  2653 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, uint32_t aValue)
  2655   switch (aIndex) {
  2656     case ATT_TURBULENCE_NUM_OCTAVES:
  2657       mNumOctaves = aValue;
  2658       break;
  2659     case ATT_TURBULENCE_SEED:
  2660       mSeed = aValue;
  2661       break;
  2662     case ATT_TURBULENCE_TYPE:
  2663       mType = static_cast<TurbulenceType>(aValue);
  2664       break;
  2665     default:
  2666       MOZ_CRASH();
  2667       break;
  2669   Invalidate();
  2672 TemporaryRef<DataSourceSurface>
  2673 FilterNodeTurbulenceSoftware::Render(const IntRect& aRect)
  2675   return FilterProcessing::RenderTurbulence(
  2676     aRect.Size(), aRect.TopLeft(), mBaseFrequency,
  2677     mSeed, mNumOctaves, mType, mStitchable, Rect(mRenderRect));
  2680 IntRect
  2681 FilterNodeTurbulenceSoftware::GetOutputRectInRect(const IntRect& aRect)
  2683   return aRect.Intersect(mRenderRect);
  2686 FilterNodeArithmeticCombineSoftware::FilterNodeArithmeticCombineSoftware()
  2687  : mK1(0), mK2(0), mK3(0), mK4(0)
  2691 int32_t
  2692 FilterNodeArithmeticCombineSoftware::InputIndex(uint32_t aInputEnumIndex)
  2694   switch (aInputEnumIndex) {
  2695     case IN_ARITHMETIC_COMBINE_IN: return 0;
  2696     case IN_ARITHMETIC_COMBINE_IN2: return 1;
  2697     default: return -1;
  2701 void
  2702 FilterNodeArithmeticCombineSoftware::SetAttribute(uint32_t aIndex,
  2703                                                   const Float* aFloat,
  2704                                                   uint32_t aSize)
  2706   MOZ_ASSERT(aIndex == ATT_ARITHMETIC_COMBINE_COEFFICIENTS);
  2707   MOZ_ASSERT(aSize == 4);
  2709   mK1 = aFloat[0];
  2710   mK2 = aFloat[1];
  2711   mK3 = aFloat[2];
  2712   mK4 = aFloat[3];
  2714   Invalidate();
  2717 TemporaryRef<DataSourceSurface>
  2718 FilterNodeArithmeticCombineSoftware::Render(const IntRect& aRect)
  2720   RefPtr<DataSourceSurface> input1 =
  2721     GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN, aRect, NEED_COLOR_CHANNELS);
  2722   RefPtr<DataSourceSurface> input2 =
  2723     GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN2, aRect, NEED_COLOR_CHANNELS);
  2724   if (!input1 && !input2) {
  2725     return nullptr;
  2728   // If one input is null, treat it as transparent by adjusting the factors.
  2729   Float k1 = mK1, k2 = mK2, k3 = mK3, k4 = mK4;
  2730   if (!input1) {
  2731     k1 = 0.0f;
  2732     k2 = 0.0f;
  2733     input1 = input2;
  2736   if (!input2) {
  2737     k1 = 0.0f;
  2738     k3 = 0.0f;
  2739     input2 = input1;
  2742   return FilterProcessing::ApplyArithmeticCombine(input1, input2, k1, k2, k3, k4);
  2745 void
  2746 FilterNodeArithmeticCombineSoftware::RequestFromInputsForRect(const IntRect &aRect)
  2748   RequestInputRect(IN_ARITHMETIC_COMBINE_IN, aRect);
  2749   RequestInputRect(IN_ARITHMETIC_COMBINE_IN2, aRect);
  2752 IntRect
  2753 FilterNodeArithmeticCombineSoftware::GetOutputRectInRect(const IntRect& aRect)
  2755   if (mK4 > 0.0f) {
  2756     return aRect;
  2758   IntRect rectFrom1 = GetInputRectInRect(IN_ARITHMETIC_COMBINE_IN, aRect).Intersect(aRect);
  2759   IntRect rectFrom2 = GetInputRectInRect(IN_ARITHMETIC_COMBINE_IN2, aRect).Intersect(aRect);
  2760   IntRect result;
  2761   if (mK1 > 0.0f) {
  2762     result = rectFrom1.Intersect(rectFrom2);
  2764   if (mK2 > 0.0f) {
  2765     result = result.Union(rectFrom1);
  2767   if (mK3 > 0.0f) {
  2768     result = result.Union(rectFrom2);
  2770   return result;
  2773 FilterNodeCompositeSoftware::FilterNodeCompositeSoftware()
  2774  : mOperator(COMPOSITE_OPERATOR_OVER)
  2775 {}
  2777 int32_t
  2778 FilterNodeCompositeSoftware::InputIndex(uint32_t aInputEnumIndex)
  2780   return aInputEnumIndex - IN_COMPOSITE_IN_START;
  2783 void
  2784 FilterNodeCompositeSoftware::SetAttribute(uint32_t aIndex, uint32_t aCompositeOperator)
  2786   MOZ_ASSERT(aIndex == ATT_COMPOSITE_OPERATOR);
  2787   mOperator = static_cast<CompositeOperator>(aCompositeOperator);
  2788   Invalidate();
  2791 TemporaryRef<DataSourceSurface>
  2792 FilterNodeCompositeSoftware::Render(const IntRect& aRect)
  2794   RefPtr<DataSourceSurface> start =
  2795     GetInputDataSourceSurface(IN_COMPOSITE_IN_START, aRect, NEED_COLOR_CHANNELS);
  2796   RefPtr<DataSourceSurface> dest =
  2797     Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8);
  2798   if (!dest) {
  2799     return nullptr;
  2802   if (start) {
  2803     CopyRect(start, dest, aRect - aRect.TopLeft(), IntPoint());
  2804   } else {
  2805     ClearDataSourceSurface(dest);
  2808   for (size_t inputIndex = 1; inputIndex < NumberOfSetInputs(); inputIndex++) {
  2809     RefPtr<DataSourceSurface> input =
  2810       GetInputDataSourceSurface(IN_COMPOSITE_IN_START + inputIndex, aRect, NEED_COLOR_CHANNELS);
  2811     if (input) {
  2812       FilterProcessing::ApplyComposition(input, dest, mOperator);
  2813     } else {
  2814       // We need to treat input as transparent. Depending on the composite
  2815       // operator, different things happen to dest.
  2816       switch (mOperator) {
  2817         case COMPOSITE_OPERATOR_OVER:
  2818         case COMPOSITE_OPERATOR_ATOP:
  2819         case COMPOSITE_OPERATOR_XOR:
  2820           // dest is unchanged.
  2821           break;
  2822         case COMPOSITE_OPERATOR_OUT:
  2823           // dest is now transparent, but it can become non-transparent again
  2824           // when compositing additional inputs.
  2825           ClearDataSourceSurface(dest);
  2826           break;
  2827         case COMPOSITE_OPERATOR_IN:
  2828           // Transparency always wins. We're completely transparent now and
  2829           // no additional input can get rid of that transparency.
  2830           return nullptr;
  2834   return dest;
  2837 void
  2838 FilterNodeCompositeSoftware::RequestFromInputsForRect(const IntRect &aRect)
  2840   for (size_t inputIndex = 0; inputIndex < NumberOfSetInputs(); inputIndex++) {
  2841     RequestInputRect(IN_COMPOSITE_IN_START + inputIndex, aRect);
  2845 IntRect
  2846 FilterNodeCompositeSoftware::GetOutputRectInRect(const IntRect& aRect)
  2848   IntRect rect;
  2849   for (size_t inputIndex = 0; inputIndex < NumberOfSetInputs(); inputIndex++) {
  2850     IntRect inputRect = GetInputRectInRect(IN_COMPOSITE_IN_START + inputIndex, aRect);
  2851     if (mOperator == COMPOSITE_OPERATOR_IN && inputIndex > 0) {
  2852       rect = rect.Intersect(inputRect);
  2853     } else {
  2854       rect = rect.Union(inputRect);
  2857   return rect;
  2860 int32_t
  2861 FilterNodeBlurXYSoftware::InputIndex(uint32_t aInputEnumIndex)
  2863   switch (aInputEnumIndex) {
  2864     case IN_GAUSSIAN_BLUR_IN: return 0;
  2865     default: return -1;
  2869 TemporaryRef<DataSourceSurface>
  2870 FilterNodeBlurXYSoftware::Render(const IntRect& aRect)
  2872   Size sigmaXY = StdDeviationXY();
  2873   IntSize d = AlphaBoxBlur::CalculateBlurRadius(Point(sigmaXY.width, sigmaXY.height));
  2875   if (d.width == 0 && d.height == 0) {
  2876     return GetInputDataSourceSurface(IN_GAUSSIAN_BLUR_IN, aRect);
  2879   IntRect srcRect = InflatedSourceOrDestRect(aRect);
  2880   RefPtr<DataSourceSurface> input =
  2881     GetInputDataSourceSurface(IN_GAUSSIAN_BLUR_IN, srcRect);
  2882   if (!input) {
  2883     return nullptr;
  2886   RefPtr<DataSourceSurface> target;
  2887   Rect r(0, 0, srcRect.width, srcRect.height);
  2889   if (input->GetFormat() == SurfaceFormat::A8) {
  2890     target = Factory::CreateDataSourceSurface(srcRect.Size(), SurfaceFormat::A8);
  2891     CopyRect(input, target, IntRect(IntPoint(), input->GetSize()), IntPoint());
  2892     AlphaBoxBlur blur(r, target->Stride(), sigmaXY.width, sigmaXY.height);
  2893     blur.Blur(target->GetData());
  2894   } else {
  2895     RefPtr<DataSourceSurface> channel0, channel1, channel2, channel3;
  2896     FilterProcessing::SeparateColorChannels(input, channel0, channel1, channel2, channel3);
  2897     AlphaBoxBlur blur(r, channel0->Stride(), sigmaXY.width, sigmaXY.height);
  2898     blur.Blur(channel0->GetData());
  2899     blur.Blur(channel1->GetData());
  2900     blur.Blur(channel2->GetData());
  2901     blur.Blur(channel3->GetData());
  2902     target = FilterProcessing::CombineColorChannels(channel0, channel1, channel2, channel3);
  2905   return GetDataSurfaceInRect(target, srcRect, aRect, EDGE_MODE_NONE);
  2908 void
  2909 FilterNodeBlurXYSoftware::RequestFromInputsForRect(const IntRect &aRect)
  2911   RequestInputRect(IN_GAUSSIAN_BLUR_IN, InflatedSourceOrDestRect(aRect));
  2914 IntRect
  2915 FilterNodeBlurXYSoftware::InflatedSourceOrDestRect(const IntRect &aDestRect)
  2917   Size sigmaXY = StdDeviationXY();
  2918   IntSize d = AlphaBoxBlur::CalculateBlurRadius(Point(sigmaXY.width, sigmaXY.height));
  2919   IntRect srcRect = aDestRect;
  2920   srcRect.Inflate(d);
  2921   return srcRect;
  2924 IntRect
  2925 FilterNodeBlurXYSoftware::GetOutputRectInRect(const IntRect& aRect)
  2927   IntRect srcRequest = InflatedSourceOrDestRect(aRect);
  2928   IntRect srcOutput = GetInputRectInRect(IN_GAUSSIAN_BLUR_IN, srcRequest);
  2929   return InflatedSourceOrDestRect(srcOutput).Intersect(aRect);
  2932 FilterNodeGaussianBlurSoftware::FilterNodeGaussianBlurSoftware()
  2933  : mStdDeviation(0)
  2934 {}
  2936 void
  2937 FilterNodeGaussianBlurSoftware::SetAttribute(uint32_t aIndex,
  2938                                              float aStdDeviation)
  2940   switch (aIndex) {
  2941     case ATT_GAUSSIAN_BLUR_STD_DEVIATION:
  2942       mStdDeviation = std::max(0.0f, aStdDeviation);
  2943       break;
  2944     default:
  2945       MOZ_CRASH();
  2947   Invalidate();
  2950 Size
  2951 FilterNodeGaussianBlurSoftware::StdDeviationXY()
  2953   return Size(mStdDeviation, mStdDeviation);
  2956 FilterNodeDirectionalBlurSoftware::FilterNodeDirectionalBlurSoftware()
  2957  : mBlurDirection(BLUR_DIRECTION_X)
  2958 {}
  2960 void
  2961 FilterNodeDirectionalBlurSoftware::SetAttribute(uint32_t aIndex,
  2962                                                 Float aStdDeviation)
  2964   switch (aIndex) {
  2965     case ATT_DIRECTIONAL_BLUR_STD_DEVIATION:
  2966       mStdDeviation = std::max(0.0f, aStdDeviation);
  2967       break;
  2968     default:
  2969       MOZ_CRASH();
  2971   Invalidate();
  2974 void
  2975 FilterNodeDirectionalBlurSoftware::SetAttribute(uint32_t aIndex,
  2976                                                 uint32_t aBlurDirection)
  2978   switch (aIndex) {
  2979     case ATT_DIRECTIONAL_BLUR_DIRECTION:
  2980       mBlurDirection = (BlurDirection)aBlurDirection;
  2981       break;
  2982     default:
  2983       MOZ_CRASH();
  2985   Invalidate();
  2988 Size
  2989 FilterNodeDirectionalBlurSoftware::StdDeviationXY()
  2991   float sigmaX = mBlurDirection == BLUR_DIRECTION_X ? mStdDeviation : 0;
  2992   float sigmaY = mBlurDirection == BLUR_DIRECTION_Y ? mStdDeviation : 0;
  2993   return Size(sigmaX, sigmaY);
  2996 int32_t
  2997 FilterNodeCropSoftware::InputIndex(uint32_t aInputEnumIndex)
  2999   switch (aInputEnumIndex) {
  3000     case IN_CROP_IN: return 0;
  3001     default: return -1;
  3005 void
  3006 FilterNodeCropSoftware::SetAttribute(uint32_t aIndex,
  3007                                      const Rect &aSourceRect)
  3009   MOZ_ASSERT(aIndex == ATT_CROP_RECT);
  3010   Rect srcRect = aSourceRect;
  3011   srcRect.Round();
  3012   if (!srcRect.ToIntRect(&mCropRect)) {
  3013     mCropRect = IntRect();
  3015   Invalidate();
  3018 TemporaryRef<DataSourceSurface>
  3019 FilterNodeCropSoftware::Render(const IntRect& aRect)
  3021   return GetInputDataSourceSurface(IN_CROP_IN, aRect.Intersect(mCropRect));
  3024 void
  3025 FilterNodeCropSoftware::RequestFromInputsForRect(const IntRect &aRect)
  3027   RequestInputRect(IN_CROP_IN, aRect.Intersect(mCropRect));
  3030 IntRect
  3031 FilterNodeCropSoftware::GetOutputRectInRect(const IntRect& aRect)
  3033   return GetInputRectInRect(IN_CROP_IN, aRect).Intersect(mCropRect);
  3036 int32_t
  3037 FilterNodePremultiplySoftware::InputIndex(uint32_t aInputEnumIndex)
  3039   switch (aInputEnumIndex) {
  3040     case IN_PREMULTIPLY_IN: return 0;
  3041     default: return -1;
  3045 TemporaryRef<DataSourceSurface>
  3046 FilterNodePremultiplySoftware::Render(const IntRect& aRect)
  3048   RefPtr<DataSourceSurface> input =
  3049     GetInputDataSourceSurface(IN_PREMULTIPLY_IN, aRect);
  3050   return input ? Premultiply(input) : nullptr;
  3053 void
  3054 FilterNodePremultiplySoftware::RequestFromInputsForRect(const IntRect &aRect)
  3056   RequestInputRect(IN_PREMULTIPLY_IN, aRect);
  3059 IntRect
  3060 FilterNodePremultiplySoftware::GetOutputRectInRect(const IntRect& aRect)
  3062   return GetInputRectInRect(IN_PREMULTIPLY_IN, aRect);
  3065 int32_t
  3066 FilterNodeUnpremultiplySoftware::InputIndex(uint32_t aInputEnumIndex)
  3068   switch (aInputEnumIndex) {
  3069     case IN_UNPREMULTIPLY_IN: return 0;
  3070     default: return -1;
  3074 TemporaryRef<DataSourceSurface>
  3075 FilterNodeUnpremultiplySoftware::Render(const IntRect& aRect)
  3077   RefPtr<DataSourceSurface> input =
  3078     GetInputDataSourceSurface(IN_UNPREMULTIPLY_IN, aRect);
  3079   return input ? Unpremultiply(input) : nullptr;
  3082 void
  3083 FilterNodeUnpremultiplySoftware::RequestFromInputsForRect(const IntRect &aRect)
  3085   RequestInputRect(IN_UNPREMULTIPLY_IN, aRect);
  3088 IntRect
  3089 FilterNodeUnpremultiplySoftware::GetOutputRectInRect(const IntRect& aRect)
  3091   return GetInputRectInRect(IN_UNPREMULTIPLY_IN, aRect);
  3094 bool
  3095 PointLightSoftware::SetAttribute(uint32_t aIndex, const Point3D &aPoint)
  3097   switch (aIndex) {
  3098     case ATT_POINT_LIGHT_POSITION:
  3099       mPosition = aPoint;
  3100       break;
  3101     default:
  3102       return false;
  3104   return true;
  3107 SpotLightSoftware::SpotLightSoftware()
  3108  : mSpecularFocus(0)
  3109  , mLimitingConeAngle(0)
  3110  , mLimitingConeCos(1)
  3114 bool
  3115 SpotLightSoftware::SetAttribute(uint32_t aIndex, const Point3D &aPoint)
  3117   switch (aIndex) {
  3118     case ATT_SPOT_LIGHT_POSITION:
  3119       mPosition = aPoint;
  3120       break;
  3121     case ATT_SPOT_LIGHT_POINTS_AT:
  3122       mPointsAt = aPoint;
  3123       break;
  3124     default:
  3125       return false;
  3127   return true;
  3130 bool
  3131 SpotLightSoftware::SetAttribute(uint32_t aIndex, Float aValue)
  3133   switch (aIndex) {
  3134     case ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE:
  3135       mLimitingConeAngle = aValue;
  3136       break;
  3137     case ATT_SPOT_LIGHT_FOCUS:
  3138       mSpecularFocus = aValue;
  3139       break;
  3140     default:
  3141       return false;
  3143   return true;
  3146 DistantLightSoftware::DistantLightSoftware()
  3147  : mAzimuth(0)
  3148  , mElevation(0)
  3152 bool
  3153 DistantLightSoftware::SetAttribute(uint32_t aIndex, Float aValue)
  3155   switch (aIndex) {
  3156     case ATT_DISTANT_LIGHT_AZIMUTH:
  3157       mAzimuth = aValue;
  3158       break;
  3159     case ATT_DISTANT_LIGHT_ELEVATION:
  3160       mElevation = aValue;
  3161       break;
  3162     default:
  3163       return false;
  3165   return true;
  3168 static inline Point3D Normalized(const Point3D &vec) {
  3169   Point3D copy(vec);
  3170   copy.Normalize();
  3171   return copy;
  3174 template<typename LightType, typename LightingType>
  3175 FilterNodeLightingSoftware<LightType, LightingType>::FilterNodeLightingSoftware(const char* aTypeName)
  3176  : mSurfaceScale(0)
  3177 #if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
  3178  , mTypeName(aTypeName)
  3179 #endif
  3180 {}
  3182 template<typename LightType, typename LightingType>
  3183 int32_t
  3184 FilterNodeLightingSoftware<LightType, LightingType>::InputIndex(uint32_t aInputEnumIndex)
  3186   switch (aInputEnumIndex) {
  3187     case IN_LIGHTING_IN: return 0;
  3188     default: return -1;
  3192 template<typename LightType, typename LightingType>
  3193 void
  3194 FilterNodeLightingSoftware<LightType, LightingType>::SetAttribute(uint32_t aIndex, const Point3D &aPoint)
  3196   if (mLight.SetAttribute(aIndex, aPoint)) {
  3197     Invalidate();
  3198     return;
  3200   MOZ_CRASH();
  3203 template<typename LightType, typename LightingType>
  3204 void
  3205 FilterNodeLightingSoftware<LightType, LightingType>::SetAttribute(uint32_t aIndex, Float aValue)
  3207   if (mLight.SetAttribute(aIndex, aValue) ||
  3208       mLighting.SetAttribute(aIndex, aValue)) {
  3209     Invalidate();
  3210     return;
  3212   switch (aIndex) {
  3213     case ATT_LIGHTING_SURFACE_SCALE:
  3214       mSurfaceScale = aValue;
  3215       break;
  3216     default:
  3217       MOZ_CRASH();
  3219   Invalidate();
  3222 template<typename LightType, typename LightingType>
  3223 void
  3224 FilterNodeLightingSoftware<LightType, LightingType>::SetAttribute(uint32_t aIndex, const Size &aKernelUnitLength)
  3226   switch (aIndex) {
  3227     case ATT_LIGHTING_KERNEL_UNIT_LENGTH:
  3228       mKernelUnitLength = aKernelUnitLength;
  3229       break;
  3230     default:
  3231       MOZ_CRASH();
  3233   Invalidate();
  3236 template<typename LightType, typename LightingType>
  3237 void
  3238 FilterNodeLightingSoftware<LightType, LightingType>::SetAttribute(uint32_t aIndex, const Color &aColor)
  3240   MOZ_ASSERT(aIndex == ATT_LIGHTING_COLOR);
  3241   mColor = aColor;
  3242   Invalidate();
  3245 template<typename LightType, typename LightingType>
  3246 IntRect
  3247 FilterNodeLightingSoftware<LightType, LightingType>::GetOutputRectInRect(const IntRect& aRect)
  3249   return GetInputRectInRect(IN_LIGHTING_IN, aRect);
  3252 Point3D
  3253 PointLightSoftware::GetVectorToLight(const Point3D &aTargetPoint)
  3255   return Normalized(mPosition - aTargetPoint);
  3258 uint32_t
  3259 PointLightSoftware::GetColor(uint32_t aLightColor, const Point3D &aVectorToLight)
  3261   return aLightColor;
  3264 void
  3265 SpotLightSoftware::Prepare()
  3267   mVectorFromFocusPointToLight = Normalized(mPointsAt - mPosition);
  3268   mLimitingConeCos = std::max<double>(cos(mLimitingConeAngle * M_PI/180.0), 0.0);
  3269   mPowCache.CacheForExponent(mSpecularFocus);
  3272 Point3D
  3273 SpotLightSoftware::GetVectorToLight(const Point3D &aTargetPoint)
  3275   return Normalized(mPosition - aTargetPoint);
  3278 uint32_t
  3279 SpotLightSoftware::GetColor(uint32_t aLightColor, const Point3D &aVectorToLight)
  3281   union {
  3282     uint32_t color;
  3283     uint8_t colorC[4];
  3284   };
  3285   color = aLightColor;
  3286   Float dot = -aVectorToLight.DotProduct(mVectorFromFocusPointToLight);
  3287   uint16_t doti = dot * (dot >= 0) * (1 << PowCache::sInputIntPrecisionBits);
  3288   uint32_t tmp = mPowCache.Pow(doti) * (dot >= mLimitingConeCos);
  3289   MOZ_ASSERT(tmp <= (1 << PowCache::sOutputIntPrecisionBits), "pow() result must not exceed 1.0");
  3290   colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_R] = uint8_t((colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_R] * tmp) >> PowCache::sOutputIntPrecisionBits);
  3291   colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_G] = uint8_t((colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_G] * tmp) >> PowCache::sOutputIntPrecisionBits);
  3292   colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_B] = uint8_t((colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_B] * tmp) >> PowCache::sOutputIntPrecisionBits);
  3293   colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_A] = 255;
  3294   return color;
  3297 void
  3298 DistantLightSoftware::Prepare()
  3300   const double radPerDeg = M_PI / 180.0;
  3301   mVectorToLight.x = cos(mAzimuth * radPerDeg) * cos(mElevation * radPerDeg);
  3302   mVectorToLight.y = sin(mAzimuth * radPerDeg) * cos(mElevation * radPerDeg);
  3303   mVectorToLight.z = sin(mElevation * radPerDeg);
  3306 Point3D
  3307 DistantLightSoftware::GetVectorToLight(const Point3D &aTargetPoint)
  3309   return mVectorToLight;
  3312 uint32_t
  3313 DistantLightSoftware::GetColor(uint32_t aLightColor, const Point3D &aVectorToLight)
  3315   return aLightColor;
  3318 template<typename CoordType>
  3319 static Point3D
  3320 GenerateNormal(const uint8_t *data, int32_t stride,
  3321                int32_t x, int32_t y, float surfaceScale,
  3322                CoordType dx, CoordType dy)
  3324   const uint8_t *index = data + y * stride + x;
  3326   CoordType zero = 0;
  3328   // See this for source of constants:
  3329   //   http://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement
  3330   int16_t normalX =
  3331     -1 * ColorComponentAtPoint(index, stride, -dx, -dy, 1, 0) +
  3332      1 * ColorComponentAtPoint(index, stride, dx, -dy, 1, 0) +
  3333     -2 * ColorComponentAtPoint(index, stride, -dx, zero, 1, 0) +
  3334      2 * ColorComponentAtPoint(index, stride, dx, zero, 1, 0) +
  3335     -1 * ColorComponentAtPoint(index, stride, -dx, dy, 1, 0) +
  3336      1 * ColorComponentAtPoint(index, stride, dx, dy, 1, 0);
  3338   int16_t normalY =
  3339     -1 * ColorComponentAtPoint(index, stride, -dx, -dy, 1, 0) +
  3340     -2 * ColorComponentAtPoint(index, stride, zero, -dy, 1, 0) +
  3341     -1 * ColorComponentAtPoint(index, stride, dx, -dy, 1, 0) +
  3342      1 * ColorComponentAtPoint(index, stride, -dx, dy, 1, 0) +
  3343      2 * ColorComponentAtPoint(index, stride, zero, dy, 1, 0) +
  3344      1 * ColorComponentAtPoint(index, stride, dx, dy, 1, 0);
  3346   Point3D normal;
  3347   normal.x = -surfaceScale * normalX / 4.0f;
  3348   normal.y = -surfaceScale * normalY / 4.0f;
  3349   normal.z = 255;
  3350   return Normalized(normal);
  3353 template<typename LightType, typename LightingType>
  3354 TemporaryRef<DataSourceSurface>
  3355 FilterNodeLightingSoftware<LightType, LightingType>::Render(const IntRect& aRect)
  3357   if (mKernelUnitLength.width == floor(mKernelUnitLength.width) &&
  3358       mKernelUnitLength.height == floor(mKernelUnitLength.height)) {
  3359     return DoRender(aRect, (int32_t)mKernelUnitLength.width, (int32_t)mKernelUnitLength.height);
  3361   return DoRender(aRect, mKernelUnitLength.width, mKernelUnitLength.height);
  3364 template<typename LightType, typename LightingType>
  3365 void
  3366 FilterNodeLightingSoftware<LightType, LightingType>::RequestFromInputsForRect(const IntRect &aRect)
  3368   IntRect srcRect = aRect;
  3369   srcRect.Inflate(ceil(mKernelUnitLength.width),
  3370                   ceil(mKernelUnitLength.height));
  3371   RequestInputRect(IN_LIGHTING_IN, srcRect);
  3374 template<typename LightType, typename LightingType> template<typename CoordType>
  3375 TemporaryRef<DataSourceSurface>
  3376 FilterNodeLightingSoftware<LightType, LightingType>::DoRender(const IntRect& aRect,
  3377                                                               CoordType aKernelUnitLengthX,
  3378                                                               CoordType aKernelUnitLengthY)
  3380   IntRect srcRect = aRect;
  3381   IntSize size = aRect.Size();
  3382   srcRect.Inflate(ceil(float(aKernelUnitLengthX)),
  3383                   ceil(float(aKernelUnitLengthY)));
  3385   // Inflate the source rect by another pixel because the bilinear filtering in
  3386   // ColorComponentAtPoint may want to access the margins.
  3387   srcRect.Inflate(1);
  3389   RefPtr<DataSourceSurface> input =
  3390     GetInputDataSourceSurface(IN_LIGHTING_IN, srcRect, CAN_HANDLE_A8,
  3391                               EDGE_MODE_DUPLICATE);
  3393   if (!input) {
  3394     return nullptr;
  3397   if (input->GetFormat() != SurfaceFormat::A8) {
  3398     input = FilterProcessing::ExtractAlpha(input);
  3401   DebugOnlyAutoColorSamplingAccessControl accessControl(input);
  3403   RefPtr<DataSourceSurface> target =
  3404     Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
  3405   if (!target) {
  3406     return nullptr;
  3409   IntPoint offset = aRect.TopLeft() - srcRect.TopLeft();
  3411   uint8_t* sourceData = DataAtOffset(input, offset);
  3412   int32_t sourceStride = input->Stride();
  3413   uint8_t* targetData = target->GetData();
  3414   int32_t targetStride = target->Stride();
  3416   uint32_t lightColor = ColorToBGRA(mColor);
  3417   mLight.Prepare();
  3418   mLighting.Prepare();
  3420   for (int32_t y = 0; y < size.height; y++) {
  3421     for (int32_t x = 0; x < size.width; x++) {
  3422       int32_t sourceIndex = y * sourceStride + x;
  3423       int32_t targetIndex = y * targetStride + 4 * x;
  3425       Point3D normal = GenerateNormal(sourceData, sourceStride,
  3426                                       x, y, mSurfaceScale,
  3427                                       aKernelUnitLengthX, aKernelUnitLengthY);
  3429       IntPoint pointInFilterSpace(aRect.x + x, aRect.y + y);
  3430       Float Z = mSurfaceScale * sourceData[sourceIndex] / 255.0f;
  3431       Point3D pt(pointInFilterSpace.x, pointInFilterSpace.y, Z);
  3432       Point3D rayDir = mLight.GetVectorToLight(pt);
  3433       uint32_t color = mLight.GetColor(lightColor, rayDir);
  3435       *(uint32_t*)(targetData + targetIndex) = mLighting.LightPixel(normal, rayDir, color);
  3439   return target;
  3442 DiffuseLightingSoftware::DiffuseLightingSoftware()
  3443  : mDiffuseConstant(0)
  3447 bool
  3448 DiffuseLightingSoftware::SetAttribute(uint32_t aIndex, Float aValue)
  3450   switch (aIndex) {
  3451     case ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT:
  3452       mDiffuseConstant = aValue;
  3453       break;
  3454     default:
  3455       return false;
  3457   return true;
  3460 uint32_t
  3461 DiffuseLightingSoftware::LightPixel(const Point3D &aNormal,
  3462                                     const Point3D &aVectorToLight,
  3463                                     uint32_t aColor)
  3465   Float dotNL = std::max(0.0f, aNormal.DotProduct(aVectorToLight));
  3466   Float diffuseNL = mDiffuseConstant * dotNL;
  3468   union {
  3469     uint32_t bgra;
  3470     uint8_t components[4];
  3471   } color = { aColor };
  3472   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B] =
  3473     umin(uint32_t(diffuseNL * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B]), 255U);
  3474   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G] =
  3475     umin(uint32_t(diffuseNL * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G]), 255U);
  3476   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R] =
  3477     umin(uint32_t(diffuseNL * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R]), 255U);
  3478   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_A] = 255;
  3479   return color.bgra;
  3482 SpecularLightingSoftware::SpecularLightingSoftware()
  3483  : mSpecularConstant(0)
  3484  , mSpecularExponent(0)
  3488 bool
  3489 SpecularLightingSoftware::SetAttribute(uint32_t aIndex, Float aValue)
  3491   switch (aIndex) {
  3492     case ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT:
  3493       mSpecularConstant = std::min(std::max(aValue, 0.0f), 255.0f);
  3494       break;
  3495     case ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT:
  3496       mSpecularExponent = std::min(std::max(aValue, 1.0f), 128.0f);
  3497       break;
  3498     default:
  3499       return false;
  3501   return true;
  3504 void
  3505 SpecularLightingSoftware::Prepare()
  3507   mPowCache.CacheForExponent(mSpecularExponent);
  3508   mSpecularConstantInt = uint32_t(mSpecularConstant * (1 << 8));
  3511 uint32_t
  3512 SpecularLightingSoftware::LightPixel(const Point3D &aNormal,
  3513                                      const Point3D &aVectorToLight,
  3514                                      uint32_t aColor)
  3516   Point3D vectorToEye(0, 0, 1);
  3517   Point3D halfwayVector = Normalized(aVectorToLight + vectorToEye);
  3518   Float dotNH = aNormal.DotProduct(halfwayVector);
  3519   uint16_t dotNHi = uint16_t(dotNH * (dotNH >= 0) * (1 << PowCache::sInputIntPrecisionBits));
  3520   uint32_t specularNHi = uint32_t(mSpecularConstantInt) * mPowCache.Pow(dotNHi) >> 8;
  3522   union {
  3523     uint32_t bgra;
  3524     uint8_t components[4];
  3525   } color = { aColor };
  3526   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B] =
  3527     umin(
  3528       (specularNHi * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B]) >> PowCache::sOutputIntPrecisionBits, 255U);
  3529   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G] =
  3530     umin(
  3531       (specularNHi * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G]) >> PowCache::sOutputIntPrecisionBits, 255U);
  3532   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R] =
  3533     umin(
  3534       (specularNHi * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R]) >> PowCache::sOutputIntPrecisionBits, 255U);
  3536   color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_A] =
  3537     umax(color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B],
  3538       umax(color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G],
  3539                color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R]));
  3540   return color.bgra;
  3543 } // namespace gfx
  3544 } // namespace mozilla

mercurial