Bug 1359527. Part 1 - Add DrawTarget::IntoLuminance r=jrmuizel
authorMason Chang <mchang@mozilla.com>
Fri, 02 Jun 2017 11:13:36 -0700
changeset 411040 e14c50095f3660dbd7d995f7b4590cf21265d0ab
parent 411039 6b534147049e9a4afaa3320712d824dc9563ac67
child 411041 7fb451a4d22c87e7de74be4c169c85601bdb938e
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1359527
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1359527. Part 1 - Add DrawTarget::IntoLuminance r=jrmuizel
gfx/2d/2D.h
gfx/2d/DrawTarget.cpp
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
gfx/2d/Types.h
layout/svg/moz.build
layout/svg/nsSVGMaskFrame.cpp
layout/svg/nsSVGMaskFrame.h
layout/svg/nsSVGMaskFrameNEON.cpp
layout/svg/nsSVGMaskFrameNEON.h
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -889,16 +889,21 @@ public:
   virtual bool IsCaptureDT() const { return false; }
 
   /**
    * Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget.
    * Multiple calls to Snapshot() without any drawing operations in between will
    * normally return the same SourceSurface object.
    */
   virtual already_AddRefed<SourceSurface> Snapshot() = 0;
+
+  // Snapshots the contents and returns an alpha mask
+  // based on the RGB values.
+  virtual already_AddRefed<SourceSurface> IntoLuminanceSource(LuminanceType aLuminanceType,
+                                                              float aOpacity);
   virtual IntSize GetSize() = 0;
 
   /**
    * If possible returns the bits to this DrawTarget for direct manipulation. While
    * the bits is locked any modifications to this DrawTarget is forbidden.
    * Release takes the original data pointer for safety.
    */
   virtual bool LockBits(uint8_t** aData, IntSize* aSize,
--- a/gfx/2d/DrawTarget.cpp
+++ b/gfx/2d/DrawTarget.cpp
@@ -4,19 +4,172 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "2D.h"
 #include "Logging.h"
 #include "PathHelpers.h"
 
 #include "DrawTargetCapture.h"
 
+#ifdef BUILD_ARM_NEON
+#include "mozilla/arm.h"
+#endif
+
 namespace mozilla {
 namespace gfx {
 
+/**
+ * Byte offsets of channels in a native packed gfxColor or cairo image surface.
+ */
+#ifdef IS_BIG_ENDIAN
+#define GFX_ARGB32_OFFSET_A 0
+#define GFX_ARGB32_OFFSET_R 1
+#define GFX_ARGB32_OFFSET_G 2
+#define GFX_ARGB32_OFFSET_B 3
+#else
+#define GFX_ARGB32_OFFSET_A 3
+#define GFX_ARGB32_OFFSET_R 2
+#define GFX_ARGB32_OFFSET_G 1
+#define GFX_ARGB32_OFFSET_B 0
+#endif
+
+// c = n / 255
+// c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
+static const uint8_t gsRGBToLinearRGBMap[256] = {
+  0,   0,   0,   0,   0,   0,   0,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   2,   2,   2,   2,   2,   2,
+  2,   2,   3,   3,   3,   3,   3,   3,
+  4,   4,   4,   4,   4,   5,   5,   5,
+  5,   6,   6,   6,   6,   7,   7,   7,
+  8,   8,   8,   8,   9,   9,   9,  10,
+ 10,  10,  11,  11,  12,  12,  12,  13,
+ 13,  13,  14,  14,  15,  15,  16,  16,
+ 17,  17,  17,  18,  18,  19,  19,  20,
+ 20,  21,  22,  22,  23,  23,  24,  24,
+ 25,  25,  26,  27,  27,  28,  29,  29,
+ 30,  30,  31,  32,  32,  33,  34,  35,
+ 35,  36,  37,  37,  38,  39,  40,  41,
+ 41,  42,  43,  44,  45,  45,  46,  47,
+ 48,  49,  50,  51,  51,  52,  53,  54,
+ 55,  56,  57,  58,  59,  60,  61,  62,
+ 63,  64,  65,  66,  67,  68,  69,  70,
+ 71,  72,  73,  74,  76,  77,  78,  79,
+ 80,  81,  82,  84,  85,  86,  87,  88,
+ 90,  91,  92,  93,  95,  96,  97,  99,
+100, 101, 103, 104, 105, 107, 108, 109,
+111, 112, 114, 115, 116, 118, 119, 121,
+122, 124, 125, 127, 128, 130, 131, 133,
+134, 136, 138, 139, 141, 142, 144, 146,
+147, 149, 151, 152, 154, 156, 157, 159,
+161, 163, 164, 166, 168, 170, 171, 173,
+175, 177, 179, 181, 183, 184, 186, 188,
+190, 192, 194, 196, 198, 200, 202, 204,
+206, 208, 210, 212, 214, 216, 218, 220,
+222, 224, 226, 229, 231, 233, 235, 237,
+239, 242, 244, 246, 248, 250, 253, 255
+};
+
+static void
+ComputesRGBLuminanceMask(const uint8_t *aSourceData,
+                         int32_t aSourceStride,
+                         uint8_t *aDestData,
+                         int32_t aDestStride,
+                         const IntSize &aSize,
+                         float aOpacity)
+{
+  int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
+  int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
+  int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
+  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
+  const uint8_t *sourcePixel = aSourceData;
+  int32_t destOffset = aDestStride - aSize.width;
+  uint8_t *destPixel = aDestData;
+
+  for (int32_t y = 0; y < aSize.height; y++) {
+    for (int32_t x = 0; x < aSize.width; x++) {
+      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
+
+      if (a) {
+        *destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R] +
+                      greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
+                      blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
+      } else {
+        *destPixel = 0;
+      }
+      sourcePixel += 4;
+      destPixel++;
+    }
+    sourcePixel += sourceOffset;
+    destPixel += destOffset;
+  }
+}
+
+static void
+ComputeLinearRGBLuminanceMask(const uint8_t *aSourceData,
+                              int32_t aSourceStride,
+                              uint8_t *aDestData,
+                              int32_t aDestStride,
+                              const IntSize &aSize,
+                              float aOpacity)
+{
+  int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
+  int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
+  int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
+  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
+  const uint8_t *sourcePixel = aSourceData;
+  int32_t destOffset = aDestStride - aSize.width;
+  uint8_t *destPixel = aDestData;
+
+  for (int32_t y = 0; y < aSize.height; y++) {
+    for (int32_t x = 0; x < aSize.width; x++) {
+      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
+
+      // unpremultiply
+      if (a) {
+        if (a == 255) {
+          /* sRGB -> linearRGB -> intensity */
+          *destPixel =
+            static_cast<uint8_t>
+                       ((gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_R]] *
+                         redFactor +
+                         gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_G]] *
+                         greenFactor +
+                         gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_B]] *
+                         blueFactor) >> 8);
+        } else {
+          uint8_t tempPixel[4];
+          tempPixel[GFX_ARGB32_OFFSET_B] =
+            (255 * sourcePixel[GFX_ARGB32_OFFSET_B]) / a;
+          tempPixel[GFX_ARGB32_OFFSET_G] =
+            (255 * sourcePixel[GFX_ARGB32_OFFSET_G]) / a;
+          tempPixel[GFX_ARGB32_OFFSET_R] =
+            (255 * sourcePixel[GFX_ARGB32_OFFSET_R]) / a;
+
+          /* sRGB -> linearRGB -> intensity */
+          *destPixel =
+            static_cast<uint8_t>
+                       (((gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_R]] *
+                          redFactor +
+                          gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_G]] *
+                          greenFactor +
+                          gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_B]] *
+                          blueFactor) >> 8) * (a / 255.0f));
+        }
+      } else {
+        *destPixel = 0;
+      }
+      sourcePixel += 4;
+      destPixel++;
+    }
+    sourcePixel += sourceOffset;
+    destPixel += destOffset;
+  }
+}
+
 already_AddRefed<DrawTargetCapture>
 DrawTarget::CreateCaptureDT(const IntSize& aSize)
 {
   RefPtr<DrawTargetCaptureImpl> dt = new DrawTargetCaptureImpl();
 
   if (!dt->Init(aSize, this)) {
     gfxWarning() << "Failed to initialize Capture DrawTarget!";
     return nullptr;
@@ -59,11 +212,56 @@ DrawTarget::StrokeGlyphs(ScaledFont* aFo
                          const StrokeOptions& aStrokeOptions,
                          const DrawOptions& aOptions,
                          const GlyphRenderingOptions* aRenderingOptions)
 {
   RefPtr<Path> path = aFont->GetPathForGlyphs(aBuffer, this);
   Stroke(path, aPattern, aStrokeOptions, aOptions);
 }
 
+already_AddRefed<SourceSurface>
+DrawTarget::IntoLuminanceSource(LuminanceType aMaskType, float aOpacity)
+{
+  RefPtr<SourceSurface> surface = Snapshot();
+  IntSize size = surface->GetSize();
+
+  RefPtr<DataSourceSurface> maskSurface = surface->GetDataSurface();
+  DataSourceSurface::MappedSurface map;
+  if (!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
+    return nullptr;
+  }
+
+  // Create alpha channel mask for output
+  RefPtr<DataSourceSurface> destMaskSurface =
+    Factory::CreateDataSourceSurface(size, SurfaceFormat::A8);
+  if (!destMaskSurface) {
+    return nullptr;
+  }
+  DataSourceSurface::MappedSurface destMap;
+  if (!destMaskSurface->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
+    return nullptr;
+  }
+
+  switch (aMaskType) {
+    case LuminanceType::LUMINANCE:
+    {
+      ComputesRGBLuminanceMask(map.mData, map.mStride,
+                               destMap.mData, destMap.mStride,
+                               size, aOpacity);
+      break;
+    }
+    case LuminanceType::LINEARRGB:
+    {
+      ComputeLinearRGBLuminanceMask(map.mData, map.mStride,
+                                    destMap.mData, destMap.mStride,
+                                    size, aOpacity);
+      break;
+    }
+  }
+
+  maskSurface->Unmap();
+  destMaskSurface->Unmap();
+
+  return destMaskSurface.forget();
+}
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -94,16 +94,48 @@ DrawTargetD2D1::Snapshot()
   Flush();
 
   mSnapshot = new SourceSurfaceD2D1(mBitmap, mDC, mFormat, mSize, this);
 
   RefPtr<SourceSurface> snapshot(mSnapshot);
   return snapshot.forget();
 }
 
+void
+DrawTargetD2D1::EnsureLuminanceEffect()
+{
+  if (mLuminanceEffect.get()) {
+    return;
+  }
+
+  HRESULT hr = mDC->CreateEffect(CLSID_D2D1LuminanceToAlpha,
+                                 getter_AddRefs(mLuminanceEffect));
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to create luminance effect. Code: " << hexa(hr);
+  }
+}
+
+already_AddRefed<SourceSurface>
+DrawTargetD2D1::IntoLuminanceSource(LuminanceType aLuminanceType, float aOpacity)
+{
+  //return DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity);
+  if (aLuminanceType != LuminanceType::LUMINANCE) {
+    return DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity);
+  }
+
+  // Create the luminance effect
+  EnsureLuminanceEffect();
+  mLuminanceEffect->SetInput(0, mBitmap);
+
+  RefPtr<ID2D1Image> luminanceOutput;
+  mLuminanceEffect->GetOutput(getter_AddRefs(luminanceOutput));
+
+ return MakeAndAddRef<SourceSurfaceD2D1>(luminanceOutput, mDC, SurfaceFormat::A8, mSize);
+}
+
 // Command lists are kept around by device contexts until EndDraw is called,
 // this can cause issues with memory usage (see bug 1238328). EndDraw/BeginDraw
 // are expensive though, especially relatively when little work is done, so
 // we try to reduce the amount of times we execute these purges.
 static const uint32_t kPushedLayersBeforePurge = 25;
 
 void
 DrawTargetD2D1::Flush()
@@ -343,30 +375,58 @@ DrawTargetD2D1::MaskSurface(const Patter
 
   if (!image) {
     gfxWarning() << "Failed to get image for surface.";
     return;
   }
 
   PrepareForDrawing(aOptions.mCompositionOp, aSource);
 
+  IntSize size = IntSize::Truncate(aMask->GetSize().width, aMask->GetSize().height);
+  Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
+
+  HRESULT hr = image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
+  if (!bitmap || FAILED(hr)) {
+    // D2D says if we have an actual ID2D1Image and not a bitmap underlying the object,
+    // we can't query for a bitmap. Instead, Push/PopLayer
+    gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces. Falling back to push/pop layer";
+
+    RefPtr<ID2D1Brush> source = CreateBrushForPattern(aSource, aOptions.mAlpha);
+    RefPtr<ID2D1ImageBrush> maskBrush;
+    hr = mDC->CreateImageBrush(image,
+                               D2D1::ImageBrushProperties(D2D1::RectF(0, 0, size.width, size.height)),
+                               D2D1::BrushProperties(1.0f, D2D1::IdentityMatrix()),
+                               getter_AddRefs(maskBrush));
+    MOZ_ASSERT(SUCCEEDED(hr));
+
+    mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), nullptr,
+                                          D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
+                                          D2D1::IdentityMatrix(),
+                                          1.0f, maskBrush, D2D1_LAYER_OPTIONS1_NONE),
+                  nullptr);
+
+    mDC->FillRectangle(D2DRect(dest), source);
+    mDC->PopLayer();
+
+    FinalizeDrawing(aOptions.mCompositionOp, aSource);
+    return;
+  } else {
+    // If this is a data source surface, we might have created a partial bitmap
+    // for this surface and only uploaded part of the mask. In that case,
+    // we have to fixup our sizes here.
+    size.width = bitmap->GetSize().width;
+    size.height = bitmap->GetSize().height;
+    dest.width = size.width;
+    dest.height = size.height;
+  }
+
   // FillOpacityMask only works if the antialias mode is MODE_ALIASED
   mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
 
-  image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
-  if (!bitmap) {
-    gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces.";
-    return;
-  }
-
-  IntSize size = IntSize::Truncate(bitmap->GetSize().width, bitmap->GetSize().height);
-
   Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));
-
-  Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
   mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
 
   mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
 
   FinalizeDrawing(aOptions.mCompositionOp, aSource);
 }
 
@@ -1866,17 +1926,16 @@ DrawTargetD2D1::CreateBrushForPattern(co
 }
 
 already_AddRefed<ID2D1Image>
 DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTransform,
                                    ExtendMode aExtendMode, const IntRect* aSourceRect,
                                    bool aUserSpace)
 {
   RefPtr<ID2D1Image> image;
-
   switch (aSurface->GetType()) {
   case SurfaceType::D2D1_1_IMAGE:
     {
       SourceSurfaceD2D1 *surf = static_cast<SourceSurfaceD2D1*>(aSurface);
       image = surf->GetImage();
       AddDependencyOnSource(surf);
     }
     break;
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -31,16 +31,18 @@ class DrawTargetD2D1 : public DrawTarget
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetD2D1, override)
   DrawTargetD2D1();
   virtual ~DrawTargetD2D1();
 
   virtual DrawTargetType GetType() const override { return DrawTargetType::HARDWARE_RASTER; }
   virtual BackendType GetBackendType() const override { return BackendType::DIRECT2D1_1; }
   virtual already_AddRefed<SourceSurface> Snapshot() override;
+  virtual already_AddRefed<SourceSurface> IntoLuminanceSource(LuminanceType aLuminanceType,
+                                                              float aOpacity) override;
   virtual IntSize GetSize() override { return mSize; }
 
   virtual void Flush() override;
   virtual void DrawSurface(SourceSurface *aSurface,
                            const Rect &aDest,
                            const Rect &aSource,
                            const DrawSurfaceOptions &aSurfOptions,
                            const DrawOptions &aOptions) override;
@@ -290,14 +292,18 @@ private:
   // If we resolve the current command list before this happens
   // we can avoid the subsequent hang. (See bug 1293586)
   bool mDidComplexBlendWithListInList;
 
   static ID2D1Factory1 *mFactory;
   static IDWriteFactory *mDWriteFactory;
   // This value is uesed to verify if the DrawTarget is created by a stale device.
   uint32_t mDeviceSeq;
+
+  // List of effects we use
+  void EnsureLuminanceEffect();
+  RefPtr<ID2D1Effect> mLuminanceEffect;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_DRAWTARGETD2D_H_ */
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -273,16 +273,22 @@ enum class CapStyle : int8_t {
   SQUARE
 };
 
 enum class SamplingBounds : int8_t {
   UNBOUNDED,
   BOUNDED
 };
 
+// Moz2d version for SVG mask types
+enum class LuminanceType : int8_t {
+  LUMINANCE,
+  LINEARRGB,
+};
+
 /* Color is stored in non-premultiplied form */
 struct Color
 {
 public:
   Color()
     : r(0.0f), g(0.0f), b(0.0f), a(0.0f)
   {}
   Color(Float aR, Float aG, Float aB, Float aA)
--- a/layout/svg/moz.build
+++ b/layout/svg/moz.build
@@ -61,20 +61,16 @@ UNIFIED_SOURCES += [
     'SVGFELeafFrame.cpp',
     'SVGFEUnstyledLeafFrame.cpp',
     'SVGGeometryFrame.cpp',
     'SVGImageContext.cpp',
     'SVGTextFrame.cpp',
     'SVGViewFrame.cpp',
 ]
 
-if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
-    SOURCES += ['nsSVGMaskFrameNEON.cpp']
-    SOURCES['nsSVGMaskFrameNEON.cpp'].flags += CONFIG['NEON_FLAGS']
-
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '../../widget',
     '../base',
     '../generic',
     '../painting',
     '../style',
     '../xul',
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -9,172 +9,38 @@
 // Keep others in (case-insensitive) order:
 #include "AutoReferenceChainGuard.h"
 #include "gfx2DGlue.h"
 #include "gfxContext.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 #include "nsSVGEffects.h"
 #include "mozilla/dom/SVGMaskElement.h"
-#ifdef BUILD_ARM_NEON
-#include "mozilla/arm.h"
-#include "nsSVGMaskFrameNEON.h"
-#endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 
-// c = n / 255
-// c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
-static const uint8_t gsRGBToLinearRGBMap[256] = {
-  0,   0,   0,   0,   0,   0,   0,   1,
-  1,   1,   1,   1,   1,   1,   1,   1,
-  1,   1,   2,   2,   2,   2,   2,   2,
-  2,   2,   3,   3,   3,   3,   3,   3,
-  4,   4,   4,   4,   4,   5,   5,   5,
-  5,   6,   6,   6,   6,   7,   7,   7,
-  8,   8,   8,   8,   9,   9,   9,  10,
- 10,  10,  11,  11,  12,  12,  12,  13,
- 13,  13,  14,  14,  15,  15,  16,  16,
- 17,  17,  17,  18,  18,  19,  19,  20,
- 20,  21,  22,  22,  23,  23,  24,  24,
- 25,  25,  26,  27,  27,  28,  29,  29,
- 30,  30,  31,  32,  32,  33,  34,  35,
- 35,  36,  37,  37,  38,  39,  40,  41,
- 41,  42,  43,  44,  45,  45,  46,  47,
- 48,  49,  50,  51,  51,  52,  53,  54,
- 55,  56,  57,  58,  59,  60,  61,  62,
- 63,  64,  65,  66,  67,  68,  69,  70,
- 71,  72,  73,  74,  76,  77,  78,  79,
- 80,  81,  82,  84,  85,  86,  87,  88,
- 90,  91,  92,  93,  95,  96,  97,  99,
-100, 101, 103, 104, 105, 107, 108, 109,
-111, 112, 114, 115, 116, 118, 119, 121,
-122, 124, 125, 127, 128, 130, 131, 133,
-134, 136, 138, 139, 141, 142, 144, 146,
-147, 149, 151, 152, 154, 156, 157, 159,
-161, 163, 164, 166, 168, 170, 171, 173,
-175, 177, 179, 181, 183, 184, 186, 188,
-190, 192, 194, 196, 198, 200, 202, 204,
-206, 208, 210, 212, 214, 216, 218, 220,
-222, 224, 226, 229, 231, 233, 235, 237,
-239, 242, 244, 246, 248, 250, 253, 255
-};
-
-static void
-ComputesRGBLuminanceMask(const uint8_t *aSourceData,
-                         int32_t aSourceStride,
-                         uint8_t *aDestData,
-                         int32_t aDestStride,
-                         const IntSize &aSize,
-                         float aOpacity)
+static LuminanceType
+GetLuminanceType(uint8_t aNSMaskType)
 {
-#ifdef BUILD_ARM_NEON
-  if (mozilla::supports_neon()) {
-    ComputesRGBLuminanceMask_NEON(aSourceData, aSourceStride,
-                                  aDestData, aDestStride,
-                                  aSize, aOpacity);
-    return;
-  }
-#endif
-
-  int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
-  int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
-  int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
-  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
-  const uint8_t *sourcePixel = aSourceData;
-  int32_t destOffset = aDestStride - aSize.width;
-  uint8_t *destPixel = aDestData;
-
-  for (int32_t y = 0; y < aSize.height; y++) {
-    for (int32_t x = 0; x < aSize.width; x++) {
-      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
-
-      if (a) {
-        *destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R] +
-                      greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
-                      blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
-      } else {
-        *destPixel = 0;
-      }
-      sourcePixel += 4;
-      destPixel++;
+  switch (aNSMaskType) {
+    case NS_STYLE_MASK_TYPE_LUMINANCE:
+      return LuminanceType::LUMINANCE;
+    case NS_STYLE_COLOR_INTERPOLATION_LINEARRGB:
+      return LuminanceType::LINEARRGB;
+    default:
+    {
+      NS_WARNING("Unknown SVG mask type, defaulting to luminance");
+      return LuminanceType::LUMINANCE;
     }
-    sourcePixel += sourceOffset;
-    destPixel += destOffset;
   }
 }
 
-static void
-ComputeLinearRGBLuminanceMask(const uint8_t *aSourceData,
-                              int32_t aSourceStride,
-                              uint8_t *aDestData,
-                              int32_t aDestStride,
-                              const IntSize &aSize,
-                              float aOpacity)
-{
-  int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
-  int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
-  int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
-  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
-  const uint8_t *sourcePixel = aSourceData;
-  int32_t destOffset = aDestStride - aSize.width;
-  uint8_t *destPixel = aDestData;
-
-  for (int32_t y = 0; y < aSize.height; y++) {
-    for (int32_t x = 0; x < aSize.width; x++) {
-      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
-
-      // unpremultiply
-      if (a) {
-        if (a == 255) {
-          /* sRGB -> linearRGB -> intensity */
-          *destPixel =
-            static_cast<uint8_t>
-                       ((gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_R]] *
-                         redFactor +
-                         gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_G]] *
-                         greenFactor +
-                         gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_B]] *
-                         blueFactor) >> 8);
-        } else {
-          uint8_t tempPixel[4];
-          tempPixel[GFX_ARGB32_OFFSET_B] =
-            (255 * sourcePixel[GFX_ARGB32_OFFSET_B]) / a;
-          tempPixel[GFX_ARGB32_OFFSET_G] =
-            (255 * sourcePixel[GFX_ARGB32_OFFSET_G]) / a;
-          tempPixel[GFX_ARGB32_OFFSET_R] =
-            (255 * sourcePixel[GFX_ARGB32_OFFSET_R]) / a;
-
-          /* sRGB -> linearRGB -> intensity */
-          *destPixel =
-            static_cast<uint8_t>
-                       (((gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_R]] *
-                          redFactor +
-                          gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_G]] *
-                          greenFactor +
-                          gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_B]] *
-                          blueFactor) >> 8) * (a / 255.0f));
-        }
-      } else {
-        *destPixel = 0;
-      }
-      sourcePixel += 4;
-      destPixel++;
-    }
-    sourcePixel += sourceOffset;
-    destPixel += destOffset;
-  }
-}
-
-//----------------------------------------------------------------------
-// Implementation
-
 nsIFrame*
 NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSVGMaskFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGMaskFrame)
 
@@ -253,54 +119,30 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(Ma
     gfxMatrix m = mMatrixForChildren;
     if (kid->GetContent()->IsSVGElement()) {
       m = static_cast<nsSVGElement*>(kid->GetContent())->
             PrependLocalTransformsTo(m, eUserSpaceToParent);
     }
     nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m, aParams.imgParams);
   }
 
+  if (StyleSVG()->mColorInterpolation ==
+    NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
+    maskType = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
+  }
+
   RefPtr<SourceSurface> surface;
   if (maskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
-    RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
+    RefPtr<SourceSurface> maskSnapshot =
+      maskDT->IntoLuminanceSource(GetLuminanceType(maskType),
+                                  aParams.opacity);
     if (!maskSnapshot) {
       return nullptr;
     }
-
-    RefPtr<DataSourceSurface> maskSurface = maskSnapshot->GetDataSurface();
-    DataSourceSurface::MappedSurface map;
-    if (!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
-      return nullptr;
-    }
-
-    // Create alpha channel mask for output
-    RefPtr<DataSourceSurface> destMaskSurface =
-      Factory::CreateDataSourceSurface(maskSurfaceSize, SurfaceFormat::A8);
-    if (!destMaskSurface) {
-      return nullptr;
-    }
-    DataSourceSurface::MappedSurface destMap;
-    if (!destMaskSurface->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
-      return nullptr;
-    }
-
-    if (StyleSVG()->mColorInterpolation ==
-        NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
-      ComputeLinearRGBLuminanceMask(map.mData, map.mStride,
-                                    destMap.mData, destMap.mStride,
-                                    maskSurfaceSize, aParams.opacity);
-    } else {
-      ComputesRGBLuminanceMask(map.mData, map.mStride,
-                               destMap.mData, destMap.mStride,
-                               maskSurfaceSize, aParams.opacity);
-    }
-
-    maskSurface->Unmap();
-    destMaskSurface->Unmap();
-    surface = destMaskSurface.forget();
+    surface = maskSnapshot.forget();
   } else {
     maskDT->SetTransform(Matrix());
     maskDT->FillRect(Rect(0, 0, maskSurfaceSize.width, maskSurfaceSize.height), ColorPattern(Color(1.0f, 1.0f, 1.0f, aParams.opacity)), DrawOptions(1, CompositionOp::OP_IN));
     RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
     if (!maskSnapshot) {
       return nullptr;
     }
     surface = maskSnapshot.forget();
--- a/layout/svg/nsSVGMaskFrame.h
+++ b/layout/svg/nsSVGMaskFrame.h
@@ -11,31 +11,16 @@
 #include "mozilla/RefPtr.h"
 #include "gfxPattern.h"
 #include "gfxMatrix.h"
 #include "nsSVGContainerFrame.h"
 #include "nsSVGUtils.h"
 
 class gfxContext;
 
-/**
- * Byte offsets of channels in a native packed gfxColor or cairo image surface.
- */
-#ifdef IS_BIG_ENDIAN
-#define GFX_ARGB32_OFFSET_A 0
-#define GFX_ARGB32_OFFSET_R 1
-#define GFX_ARGB32_OFFSET_G 2
-#define GFX_ARGB32_OFFSET_B 3
-#else
-#define GFX_ARGB32_OFFSET_A 3
-#define GFX_ARGB32_OFFSET_R 2
-#define GFX_ARGB32_OFFSET_G 1
-#define GFX_ARGB32_OFFSET_B 0
-#endif
-
 class nsSVGMaskFrame final : public nsSVGContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   typedef mozilla::gfx::Matrix Matrix;
   typedef mozilla::gfx::SourceSurface SourceSurface;
   typedef mozilla::image::imgDrawingParams imgDrawingParams;
deleted file mode 100644
--- a/layout/svg/nsSVGMaskFrameNEON.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsSVGMaskFrameNEON.h"
-#include "nsSVGMaskFrame.h"
-#include <arm_neon.h>
-
-using namespace mozilla::gfx;
-
-void
-ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
-                              int32_t aSourceStride,
-                              uint8_t *aDestData,
-                              int32_t aDestStride,
-                              const IntSize &aSize,
-                              float aOpacity)
-{
-  int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
-  int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
-  int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
-  const uint8_t *sourcePixel = aSourceData;
-  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
-  uint8_t *destPixel = aDestData;
-  int32_t destOffset = aDestStride - aSize.width;
-
-  sourcePixel = aSourceData;
-  int32_t remainderWidth = aSize.width % 8;
-  int32_t roundedWidth = aSize.width - remainderWidth;
-  uint16x8_t temp;
-  uint8x8_t gray;
-  uint8x8_t redVector = vdup_n_u8(redFactor);
-  uint8x8_t greenVector = vdup_n_u8(greenFactor);
-  uint8x8_t blueVector = vdup_n_u8(blueFactor);
-  uint8x8_t fullBitVector = vdup_n_u8(255);
-  uint8x8_t oneVector = vdup_n_u8(1);
-  for (int32_t y = 0; y < aSize.height; y++) {
-    // Calculate luminance by neon with 8 pixels per loop
-    for (int32_t x = 0; x < roundedWidth; x += 8) {
-      uint8x8x4_t argb  = vld4_u8(sourcePixel);
-      temp = vmull_u8(argb.val[GFX_ARGB32_OFFSET_R], redVector); // temp = red * redFactor
-      temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_G], greenVector); // temp += green * greenFactor
-      temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_B], blueVector); // temp += blue * blueFactor
-      gray = vshrn_n_u16(temp, 8); // gray = temp >> 8
-
-      // Check alpha value
-      uint8x8_t alphaVector = vtst_u8(argb.val[GFX_ARGB32_OFFSET_A], fullBitVector);
-      gray = vmul_u8(gray, vand_u8(alphaVector, oneVector));
-
-      // Put the result to the 8 pixels
-      vst1_u8(destPixel, gray);
-      sourcePixel += 8 * 4;
-      destPixel += 8;
-    }
-
-    // Calculate the rest pixels of the line by cpu
-    for (int32_t x = 0; x < remainderWidth; x++) {
-      if (sourcePixel[GFX_ARGB32_OFFSET_A] > 0) {
-        *destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R]+
-                      greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
-                      blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
-      } else {
-        *destPixel = 0;
-      }
-      sourcePixel += 4;
-      destPixel++;
-    }
-    sourcePixel += sourceOffset;
-    destPixel += destOffset;
-  }
-}
-
deleted file mode 100644
--- a/layout/svg/nsSVGMaskFrameNEON.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* this source code form is subject to the terms of the mozilla public
- * license, v. 2.0. if a copy of the mpl was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef __NS_SVGMASKFRAMENEON_H__
-#define __NS_SVGMASKFRAMENEON_H__
-
-#include "mozilla/gfx/Point.h"
-
-void
-ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
-                              int32_t aSourceStride,
-                              uint8_t *aDestData,
-                              int32_t aDestStride,
-                              const mozilla::gfx::IntSize &aSize,
-                              float aOpacity);
-
-#endif /* __NS_SVGMASKFRAMENEON_H__ */