Bug 1047477 - "Add support for all blend mode to feBlend". r=longsonr r=bz
authorRik Cabanier <cabanier@adobe.com>
Fri, 12 Sep 2014 16:32:00 +0200
changeset 205299 d8af54b625deb2f9083f790353411653d8a21507
parent 205298 2a7fe756a652d2fcd4cd3b99aef60f9c2c158a1d
child 205300 01ccf9bdf3d2b79131f5cafc373da7228e4b704f
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerslongsonr, bz
bugs1047477
milestone35.0a1
Bug 1047477 - "Add support for all blend mode to feBlend". r=longsonr r=bz
content/base/src/nsGkAtomList.h
content/svg/content/src/SVGFEBlendElement.cpp
dom/webidl/SVGFEBlendElement.webidl
gfx/2d/FilterNodeD2D1.cpp
gfx/2d/FilterNodeSoftware.cpp
gfx/2d/FilterProcessing.cpp
gfx/2d/FilterProcessing.h
gfx/2d/FilterProcessingScalar.cpp
gfx/2d/Filters.h
gfx/src/FilterSupport.cpp
gfx/src/FilterSupport.h
layout/reftests/svg/filters/feBlend-1-ref.svg
layout/reftests/svg/filters/feBlend-1.svg
layout/reftests/svg/filters/reftest.list
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1255,16 +1255,18 @@ GK_ATOM(baseFrequency, "baseFrequency")
 GK_ATOM(baseline_shift, "baseline-shift")
 GK_ATOM(bias, "bias")
 GK_ATOM(caption_side, "caption-side")
 GK_ATOM(clip_path, "clip-path")
 GK_ATOM(clip_rule, "clip-rule")
 GK_ATOM(clipPath, "clipPath")
 GK_ATOM(clipPathUnits, "clipPathUnits")
 GK_ATOM(cm, "cm")
+GK_ATOM(colorBurn, "color-burn")
+GK_ATOM(colorDodge, "color-dodge")
 GK_ATOM(colorInterpolation, "color-interpolation")
 GK_ATOM(colorInterpolationFilters, "color-interpolation-filters")
 GK_ATOM(colorProfile, "color-profile")
 GK_ATOM(cursor, "cursor")
 GK_ATOM(cx, "cx")
 GK_ATOM(cy, "cy")
 GK_ATOM(d, "d")
 GK_ATOM(darken, "darken")
@@ -1283,16 +1285,17 @@ GK_ATOM(duplicate, "duplicate")
 GK_ATOM(dx, "dx")
 GK_ATOM(dy, "dy")
 GK_ATOM(edgeMode, "edgeMode")
 GK_ATOM(ellipse, "ellipse")
 GK_ATOM(elevation, "elevation")
 GK_ATOM(erode, "erode")
 GK_ATOM(ex, "ex")
 GK_ATOM(exact, "exact")
+GK_ATOM(exclusion, "exclusion")
 GK_ATOM(exponent, "exponent")
 GK_ATOM(feBlend, "feBlend")
 GK_ATOM(feColorMatrix, "feColorMatrix")
 GK_ATOM(feComponentTransfer, "feComponentTransfer")
 GK_ATOM(feComposite, "feComposite")
 GK_ATOM(feConvolveMatrix, "feConvolveMatrix")
 GK_ATOM(feDiffuseLighting, "feDiffuseLighting")
 GK_ATOM(feDisplacementMap, "feDisplacementMap")
@@ -1347,17 +1350,19 @@ GK_ATOM(gamma, "gamma")
 GK_ATOM(generic_, "generic")
 GK_ATOM(glyph, "glyph")
 GK_ATOM(glyphRef, "glyphRef")
 GK_ATOM(glyph_orientation_horizontal, "glyph-orientation-horizontal")
 GK_ATOM(glyph_orientation_vertical, "glyph-orientation-vertical")
 GK_ATOM(grad, "grad")
 GK_ATOM(gradientTransform, "gradientTransform")
 GK_ATOM(gradientUnits, "gradientUnits")
+GK_ATOM(hardLight, "hard-light")
 GK_ATOM(hkern, "hkern")
+GK_ATOM(hue, "hue")
 GK_ATOM(hueRotate, "hueRotate")
 GK_ATOM(identity, "identity")
 GK_ATOM(image_rendering, "image-rendering")
 GK_ATOM(in, "in")
 GK_ATOM(in2, "in2")
 GK_ATOM(intercept, "intercept")
 GK_ATOM(k1, "k1")
 GK_ATOM(k2, "k2")
@@ -1371,16 +1376,17 @@ GK_ATOM(letter_spacing, "letter-spacing"
 GK_ATOM(lighten, "lighten")
 GK_ATOM(lighting_color, "lighting-color")
 GK_ATOM(limitingConeAngle, "limitingConeAngle")
 GK_ATOM(linear, "linear")
 GK_ATOM(linearGradient, "linearGradient")
 GK_ATOM(linearRGB, "linearRGB")
 GK_ATOM(list_style_type, "list-style-type")
 GK_ATOM(luminanceToAlpha, "luminanceToAlpha")
+GK_ATOM(luminosity, "luminosity")
 GK_ATOM(magnify, "magnify")
 GK_ATOM(marker, "marker")
 GK_ATOM(marker_end, "marker-end")
 GK_ATOM(marker_mid, "marker-mid")
 GK_ATOM(marker_start, "marker-start")
 GK_ATOM(markerHeight, "markerHeight")
 GK_ATOM(markerUnits, "markerUnits")
 GK_ATOM(markerWidth, "markerWidth")
@@ -1436,23 +1442,25 @@ GK_ATOM(reflect, "reflect")
 GK_ATOM(refX, "refX")
 GK_ATOM(refY, "refY")
 GK_ATOM(requiredExtensions, "requiredExtensions")
 GK_ATOM(requiredFeatures, "requiredFeatures")
 GK_ATOM(rotate, "rotate")
 GK_ATOM(rx, "rx")
 GK_ATOM(ry, "ry")
 GK_ATOM(saturate, "saturate")
+GK_ATOM(saturation, "saturation")
 GK_ATOM(set, "set")
 GK_ATOM(seed, "seed")
 GK_ATOM(shadow, "shadow")
 GK_ATOM(shape_rendering, "shape-rendering")
 GK_ATOM(skewX, "skewX")
 GK_ATOM(skewY, "skewY")
 GK_ATOM(slope, "slope")
+GK_ATOM(softLight, "soft-light")
 GK_ATOM(spacing, "spacing")
 GK_ATOM(spacingAndGlyphs, "spacingAndGlyphs")
 GK_ATOM(specularConstant, "specularConstant")
 GK_ATOM(specularExponent, "specularExponent")
 GK_ATOM(spreadMethod, "spreadMethod")
 GK_ATOM(sRGB, "sRGB")
 GK_ATOM(startOffset, "startOffset")
 GK_ATOM(stdDeviation, "stdDeviation")
--- a/content/svg/content/src/SVGFEBlendElement.cpp
+++ b/content/svg/content/src/SVGFEBlendElement.cpp
@@ -21,16 +21,27 @@ SVGFEBlendElement::WrapNode(JSContext *a
 }
 
 nsSVGEnumMapping SVGFEBlendElement::sModeMap[] = {
   {&nsGkAtoms::normal, SVG_FEBLEND_MODE_NORMAL},
   {&nsGkAtoms::multiply, SVG_FEBLEND_MODE_MULTIPLY},
   {&nsGkAtoms::screen, SVG_FEBLEND_MODE_SCREEN},
   {&nsGkAtoms::darken, SVG_FEBLEND_MODE_DARKEN},
   {&nsGkAtoms::lighten, SVG_FEBLEND_MODE_LIGHTEN},
+  {&nsGkAtoms::overlay, SVG_FEBLEND_MODE_OVERLAY},
+  {&nsGkAtoms::colorDodge, SVG_FEBLEND_MODE_COLOR_DODGE},
+  {&nsGkAtoms::colorBurn, SVG_FEBLEND_MODE_COLOR_BURN},
+  {&nsGkAtoms::hardLight, SVG_FEBLEND_MODE_HARD_LIGHT},
+  {&nsGkAtoms::softLight, SVG_FEBLEND_MODE_SOFT_LIGHT},
+  {&nsGkAtoms::difference, SVG_FEBLEND_MODE_DIFFERENCE},
+  {&nsGkAtoms::exclusion, SVG_FEBLEND_MODE_EXCLUSION},
+  {&nsGkAtoms::hue, SVG_FEBLEND_MODE_HUE},
+  {&nsGkAtoms::saturation, SVG_FEBLEND_MODE_SATURATION},
+  {&nsGkAtoms::color, SVG_FEBLEND_MODE_COLOR},
+  {&nsGkAtoms::luminosity, SVG_FEBLEND_MODE_LUMINOSITY},
   {nullptr, 0}
 };
 
 nsSVGElement::EnumInfo SVGFEBlendElement::sEnumInfo[1] =
 {
   { &nsGkAtoms::mode,
     sModeMap,
     SVG_FEBLEND_MODE_NORMAL
--- a/dom/webidl/SVGFEBlendElement.webidl
+++ b/dom/webidl/SVGFEBlendElement.webidl
@@ -14,15 +14,25 @@ interface SVGFEBlendElement : SVGElement
 
   // Blend Mode Types
   const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0;
   const unsigned short SVG_FEBLEND_MODE_NORMAL = 1;
   const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2;
   const unsigned short SVG_FEBLEND_MODE_SCREEN = 3;
   const unsigned short SVG_FEBLEND_MODE_DARKEN = 4;
   const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5;
-
+  const unsigned short SVG_FEBLEND_MODE_OVERLAY = 6;
+  const unsigned short SVG_FEBLEND_MODE_COLOR_DODGE = 7;
+  const unsigned short SVG_FEBLEND_MODE_COLOR_BURN = 8;
+  const unsigned short SVG_FEBLEND_MODE_HARD_LIGHT = 9;
+  const unsigned short SVG_FEBLEND_MODE_SOFT_LIGHT = 10;
+  const unsigned short SVG_FEBLEND_MODE_DIFFERENCE = 11;
+  const unsigned short SVG_FEBLEND_MODE_EXCLUSION = 12;
+  const unsigned short SVG_FEBLEND_MODE_HUE = 13;
+  const unsigned short SVG_FEBLEND_MODE_SATURATION = 14;
+  const unsigned short SVG_FEBLEND_MODE_COLOR = 15;
+  const unsigned short SVG_FEBLEND_MODE_LUMINOSITY = 16;
   readonly attribute SVGAnimatedString in1;
   readonly attribute SVGAnimatedString in2;
   readonly attribute SVGAnimatedEnumeration mode;
 };
 
 SVGFEBlendElement implements SVGFilterPrimitiveStandardAttributes;
--- a/gfx/2d/FilterNodeD2D1.cpp
+++ b/gfx/2d/FilterNodeD2D1.cpp
@@ -52,16 +52,39 @@ D2D1_BLEND_MODE D2DBlendMode(uint32_t aM
   case BLEND_MODE_DARKEN:
     return D2D1_BLEND_MODE_DARKEN;
   case BLEND_MODE_LIGHTEN:
     return D2D1_BLEND_MODE_LIGHTEN;
   case BLEND_MODE_MULTIPLY:
     return D2D1_BLEND_MODE_MULTIPLY;
   case BLEND_MODE_SCREEN:
     return D2D1_BLEND_MODE_SCREEN;
+  case BLEND_MODE_OVERLAY:
+    return D2D1_BLEND_MODE_OVERLAY;
+  case BLEND_MODE_COLOR_DODGE:
+    return D2D1_BLEND_MODE_COLOR_DODGE;
+  case BLEND_MODE_COLOR_BURN:
+    return D2D1_BLEND_MODE_COLOR_BURN;
+  case BLEND_MODE_HARD_LIGHT:
+    return D2D1_BLEND_MODE_HARD_LIGHT;
+  case BLEND_MODE_SOFT_LIGHT:
+    return D2D1_BLEND_MODE_SOFT_LIGHT;
+  case BLEND_MODE_DIFFERENCE:
+    return D2D1_BLEND_MODE_DIFFERENCE;
+  case BLEND_MODE_EXCLUSION:
+    return D2D1_BLEND_MODE_EXCLUSION;
+  case BLEND_MODE_HUE:
+    return D2D1_BLEND_MODE_HUE;
+  case BLEND_MODE_SATURATION:
+    return D2D1_BLEND_MODE_SATURATION;
+  case BLEND_MODE_COLOR:
+    return D2D1_BLEND_MODE_COLOR;
+  case BLEND_MODE_LUMINOSITY:
+    return D2D1_BLEND_MODE_LUMINOSITY;
+
   default:
     MOZ_CRASH("Unknown enum value!");
   }
 
   return D2D1_BLEND_MODE_DARKEN;
 }
 
 D2D1_MORPHOLOGY_MODE D2DMorphologyMode(uint32_t aMode)
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -989,40 +989,104 @@ FilterNodeBlendSoftware::InputIndex(uint
 void
 FilterNodeBlendSoftware::SetAttribute(uint32_t aIndex, uint32_t aBlendMode)
 {
   MOZ_ASSERT(aIndex == ATT_BLEND_BLENDMODE);
   mBlendMode = static_cast<BlendMode>(aBlendMode);
   Invalidate();
 }
 
+static CompositionOp ToBlendOp(BlendMode aOp)
+{
+  switch (aOp) {
+  case BLEND_MODE_MULTIPLY:
+    return CompositionOp::OP_MULTIPLY;
+  case BLEND_MODE_SCREEN:
+    return CompositionOp::OP_SCREEN;
+  case BLEND_MODE_OVERLAY:
+    return CompositionOp::OP_OVERLAY;
+  case BLEND_MODE_DARKEN:
+    return CompositionOp::OP_DARKEN;
+  case BLEND_MODE_LIGHTEN:
+    return CompositionOp::OP_LIGHTEN;
+  case BLEND_MODE_COLOR_DODGE:
+    return CompositionOp::OP_COLOR_DODGE;
+  case BLEND_MODE_COLOR_BURN:
+    return CompositionOp::OP_COLOR_BURN;
+  case BLEND_MODE_HARD_LIGHT:
+    return CompositionOp::OP_HARD_LIGHT;
+  case BLEND_MODE_SOFT_LIGHT:
+    return CompositionOp::OP_SOFT_LIGHT;
+  case BLEND_MODE_DIFFERENCE:
+    return CompositionOp::OP_DIFFERENCE;
+  case BLEND_MODE_EXCLUSION:
+    return CompositionOp::OP_EXCLUSION;
+  case BLEND_MODE_HUE:
+    return CompositionOp::OP_HUE;
+  case BLEND_MODE_SATURATION:
+    return CompositionOp::OP_SATURATION;
+  case BLEND_MODE_COLOR:
+    return CompositionOp::OP_COLOR;
+  case BLEND_MODE_LUMINOSITY:
+    return CompositionOp::OP_LUMINOSITY;
+  default:
+    return CompositionOp::OP_OVER;
+  }
+
+  return CompositionOp::OP_OVER;
+}
+
 TemporaryRef<DataSourceSurface>
 FilterNodeBlendSoftware::Render(const IntRect& aRect)
 {
   RefPtr<DataSourceSurface> input1 =
     GetInputDataSourceSurface(IN_BLEND_IN, aRect, NEED_COLOR_CHANNELS);
   RefPtr<DataSourceSurface> input2 =
     GetInputDataSourceSurface(IN_BLEND_IN2, aRect, NEED_COLOR_CHANNELS);
 
   // Null inputs need to be treated as transparent.
 
   // First case: both are transparent.
   if (!input1 && !input2) {
     // Then the result is transparent, too.
     return nullptr;
   }
 
-  // Second case: both are non-transparent.
-  if (input1 && input2) {
-    // Apply normal filtering.
-    return FilterProcessing::ApplyBlending(input1, input2, mBlendMode);
+  // Second case: one of them is transparent. Return the non-transparent one.
+  if (!input1 || !input2) {
+    return input1 ? input1.forget() : input2.forget();
+  }
+
+  // Third case: both are non-transparent.
+  // Apply normal filtering.
+  RefPtr<DataSourceSurface> target = FilterProcessing::ApplyBlending(input1, input2, mBlendMode);
+  if (target != nullptr) {
+    return target.forget();
   }
 
-  // Third case: one of them is transparent. Return the non-transparent one.
-  return input1 ? input1.forget() : input2.forget();
+  IntSize size = input1->GetSize();
+  target =
+    Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
+  if (MOZ2D_WARN_IF(!target)) {
+    return nullptr;
+  }
+
+  CopyRect(input1, target, IntRect(IntPoint(), size), IntPoint());
+
+  RefPtr<DrawTarget> dt =
+	    Factory::CreateDrawTargetForData(BackendType::CAIRO,
+	                                     target->GetData(),
+	                                     target->GetSize(),
+	                                     target->Stride(),
+	                                     target->GetFormat());
+
+  Rect r(0, 0, size.width, size.height);
+  dt->DrawSurface(input2, r, r, DrawSurfaceOptions(), DrawOptions(1.0f, ToBlendOp(mBlendMode)));
+  dt->Flush();
+  return target.forget();
 }
 
 void
 FilterNodeBlendSoftware::RequestFromInputsForRect(const IntRect &aRect)
 {
   RequestInputRect(IN_BLEND_IN, aRect);
   RequestInputRect(IN_BLEND_IN2, aRect);
 }
--- a/gfx/2d/FilterProcessing.cpp
+++ b/gfx/2d/FilterProcessing.cpp
@@ -48,17 +48,17 @@ TemporaryRef<DataSourceSurface>
 FilterProcessing::ApplyBlending(DataSourceSurface* aInput1, DataSourceSurface* aInput2,
                                 BlendMode aBlendMode)
 {
   if (Factory::HasSSE2()) {
 #ifdef USE_SSE2
     return ApplyBlending_SSE2(aInput1, aInput2, aBlendMode);
 #endif
   }
-  return ApplyBlending_Scalar(aInput1, aInput2, aBlendMode);
+  return nullptr;
 }
 
 void
 FilterProcessing::ApplyMorphologyHorizontal(uint8_t* aSourceData, int32_t aSourceStride,
                                             uint8_t* aDestData, int32_t aDestStride,
                                             const IntRect& aDestRect, int32_t aRadius,
                                             MorphologyOperator aOp)
 {
--- a/gfx/2d/FilterProcessing.h
+++ b/gfx/2d/FilterProcessing.h
@@ -62,17 +62,16 @@ public:
     RenderTurbulence(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
                      int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect);
   static TemporaryRef<DataSourceSurface>
     ApplyArithmeticCombine(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4);
 
 protected:
   static void ExtractAlpha_Scalar(const IntSize& size, uint8_t* sourceData, int32_t sourceStride, uint8_t* alphaData, int32_t alphaStride);
   static TemporaryRef<DataSourceSurface> ConvertToB8G8R8A8_Scalar(SourceSurface* aSurface);
-  static TemporaryRef<DataSourceSurface> ApplyBlending_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2, BlendMode aBlendMode);
   static void ApplyMorphologyHorizontal_Scalar(uint8_t* aSourceData, int32_t aSourceStride,
                                                uint8_t* aDestData, int32_t aDestStride,
                                                const IntRect& aDestRect, int32_t aRadius,
                                                MorphologyOperator aOperator);
   static void ApplyMorphologyVertical_Scalar(uint8_t* aSourceData, int32_t aSourceStride,
                                                uint8_t* aDestData, int32_t aDestStride,
                                                const IntRect& aDestRect, int32_t aRadius,
                                                MorphologyOperator aOperator);
--- a/gfx/2d/FilterProcessingScalar.cpp
+++ b/gfx/2d/FilterProcessingScalar.cpp
@@ -24,94 +24,16 @@ FilterProcessing::ExtractAlpha_Scalar(co
 }
 
 TemporaryRef<DataSourceSurface>
 FilterProcessing::ConvertToB8G8R8A8_Scalar(SourceSurface* aSurface)
 {
   return ConvertToB8G8R8A8_SIMD<simd::Scalaru8x16_t>(aSurface);
 }
 
-template<BlendMode aBlendMode>
-static TemporaryRef<DataSourceSurface>
-ApplyBlending_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2)
-{
-  IntSize size = aInput1->GetSize();
-  RefPtr<DataSourceSurface> target =
-    Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
-  if (MOZ2D_WARN_IF(!target)) {
-    return nullptr;
-  }
-
-  uint8_t* source1Data = aInput1->GetData();
-  uint8_t* source2Data = aInput2->GetData();
-  uint8_t* targetData = target->GetData();
-  uint32_t targetStride = target->Stride();
-  uint32_t source1Stride = aInput1->Stride();
-  uint32_t source2Stride = aInput2->Stride();
-
-  for (int32_t y = 0; y < size.height; y++) {
-    for (int32_t x = 0; x < size.width; x++) {
-      uint32_t targetIndex = y * targetStride + 4 * x;
-      uint32_t source1Index = y * source1Stride + 4 * x;
-      uint32_t source2Index = y * source2Stride + 4 * x;
-      uint32_t qa = source1Data[source1Index + B8G8R8A8_COMPONENT_BYTEOFFSET_A];
-      uint32_t qb = source2Data[source2Index + B8G8R8A8_COMPONENT_BYTEOFFSET_A];
-      for (int32_t i = std::min(B8G8R8A8_COMPONENT_BYTEOFFSET_B, B8G8R8A8_COMPONENT_BYTEOFFSET_R);
-           i <= std::max(B8G8R8A8_COMPONENT_BYTEOFFSET_B, B8G8R8A8_COMPONENT_BYTEOFFSET_R); i++) {
-        uint32_t ca = source1Data[source1Index + i];
-        uint32_t cb = source2Data[source2Index + i];
-        uint32_t val;
-        switch (aBlendMode) {
-          case BLEND_MODE_MULTIPLY:
-            val = ((255 - qa) * cb + (255 - qb + cb) * ca);
-            break;
-          case BLEND_MODE_SCREEN:
-            val = 255 * (cb + ca) - ca * cb;
-            break;
-          case BLEND_MODE_DARKEN:
-            val = umin((255 - qa) * cb + 255 * ca,
-                       (255 - qb) * ca + 255 * cb);
-            break;
-          case BLEND_MODE_LIGHTEN:
-            val = umax((255 - qa) * cb + 255 * ca,
-                       (255 - qb) * ca + 255 * cb);
-            break;
-          default:
-            MOZ_CRASH();
-        }
-        val = umin(FilterProcessing::FastDivideBy255<unsigned>(val), 255U);
-        targetData[targetIndex + i] = static_cast<uint8_t>(val);
-      }
-      uint32_t alpha = 255 * 255 - (255 - qa) * (255 - qb);
-      targetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] =
-        FilterProcessing::FastDivideBy255<uint8_t>(alpha);
-    }
-  }
-
-  return target.forget();
-}
-
-TemporaryRef<DataSourceSurface>
-FilterProcessing::ApplyBlending_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2,
-                                       BlendMode aBlendMode)
-{
-  switch (aBlendMode) {
-    case BLEND_MODE_MULTIPLY:
-      return gfx::ApplyBlending_Scalar<BLEND_MODE_MULTIPLY>(aInput1, aInput2);
-    case BLEND_MODE_SCREEN:
-      return gfx::ApplyBlending_Scalar<BLEND_MODE_SCREEN>(aInput1, aInput2);
-    case BLEND_MODE_DARKEN:
-      return gfx::ApplyBlending_Scalar<BLEND_MODE_DARKEN>(aInput1, aInput2);
-    case BLEND_MODE_LIGHTEN:
-      return gfx::ApplyBlending_Scalar<BLEND_MODE_LIGHTEN>(aInput1, aInput2);
-    default:
-      return nullptr;
-  }
-}
-
 template<MorphologyOperator Operator>
 static void
 ApplyMorphologyHorizontal_Scalar(uint8_t* aSourceData, int32_t aSourceStride,
                                  uint8_t* aDestData, int32_t aDestStride,
                                  const IntRect& aDestRect, int32_t aRadius)
 {
   static_assert(Operator == MORPHOLOGY_OPERATOR_ERODE ||
                 Operator == MORPHOLOGY_OPERATOR_DILATE,
--- a/gfx/2d/Filters.h
+++ b/gfx/2d/Filters.h
@@ -40,17 +40,28 @@ enum BlendFilterAtts
   ATT_BLEND_BLENDMODE = 0                   // uint32_t
 };
 
 enum BlendMode
 {
   BLEND_MODE_MULTIPLY = 0,
   BLEND_MODE_SCREEN,
   BLEND_MODE_DARKEN,
-  BLEND_MODE_LIGHTEN
+  BLEND_MODE_LIGHTEN,
+  BLEND_MODE_OVERLAY,
+  BLEND_MODE_COLOR_DODGE,
+  BLEND_MODE_COLOR_BURN,
+  BLEND_MODE_HARD_LIGHT,
+  BLEND_MODE_SOFT_LIGHT,
+  BLEND_MODE_DIFFERENCE,
+  BLEND_MODE_EXCLUSION,
+  BLEND_MODE_HUE,
+  BLEND_MODE_SATURATION,
+  BLEND_MODE_COLOR,
+  BLEND_MODE_LUMINOSITY
 };
 
 enum BlendFilterInputs
 {
   IN_BLEND_IN = 0,
   IN_BLEND_IN2
 };
 
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -668,23 +668,34 @@ FilterNodeFromPrimitiveDescription(const
         return nullptr;
       }
       if (mode == SVG_FEBLEND_MODE_NORMAL) {
         filter = aDT->CreateFilter(FilterType::COMPOSITE);
         filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
         filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
       } else {
         filter = aDT->CreateFilter(FilterType::BLEND);
-        static const uint8_t blendModes[SVG_FEBLEND_MODE_LIGHTEN + 1] = {
+        static const uint8_t blendModes[SVG_FEBLEND_MODE_LUMINOSITY + 1] = {
           0,
           0,
           BLEND_MODE_MULTIPLY,
           BLEND_MODE_SCREEN,
           BLEND_MODE_DARKEN,
-          BLEND_MODE_LIGHTEN
+          BLEND_MODE_LIGHTEN,
+          BLEND_MODE_OVERLAY,
+          BLEND_MODE_COLOR_DODGE,
+          BLEND_MODE_COLOR_BURN,
+          BLEND_MODE_HARD_LIGHT,
+          BLEND_MODE_SOFT_LIGHT,
+          BLEND_MODE_DIFFERENCE,
+          BLEND_MODE_EXCLUSION,
+          BLEND_MODE_HUE,
+          BLEND_MODE_SATURATION,
+          BLEND_MODE_COLOR,
+          BLEND_MODE_LUMINOSITY
         };
         filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)blendModes[mode]);
         filter->SetInput(IN_BLEND_IN, aSources[0]);
         filter->SetInput(IN_BLEND_IN2, aSources[1]);
       }
       return filter;
     }
 
--- a/gfx/src/FilterSupport.h
+++ b/gfx/src/FilterSupport.h
@@ -42,16 +42,27 @@ const unsigned short SVG_FECOMPONENTTRAN
 
 // Blend Mode Values
 const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0;
 const unsigned short SVG_FEBLEND_MODE_NORMAL = 1;
 const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2;
 const unsigned short SVG_FEBLEND_MODE_SCREEN = 3;
 const unsigned short SVG_FEBLEND_MODE_DARKEN = 4;
 const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5;
+const unsigned short SVG_FEBLEND_MODE_OVERLAY = 6;
+const unsigned short SVG_FEBLEND_MODE_COLOR_DODGE = 7;
+const unsigned short SVG_FEBLEND_MODE_COLOR_BURN = 8;
+const unsigned short SVG_FEBLEND_MODE_HARD_LIGHT = 9;
+const unsigned short SVG_FEBLEND_MODE_SOFT_LIGHT = 10;
+const unsigned short SVG_FEBLEND_MODE_DIFFERENCE = 11;
+const unsigned short SVG_FEBLEND_MODE_EXCLUSION = 12;
+const unsigned short SVG_FEBLEND_MODE_HUE = 13;
+const unsigned short SVG_FEBLEND_MODE_SATURATION = 14;
+const unsigned short SVG_FEBLEND_MODE_COLOR = 15;
+const unsigned short SVG_FEBLEND_MODE_LUMINOSITY = 16;
 
 // Edge Mode Values
 const unsigned short SVG_EDGEMODE_UNKNOWN = 0;
 const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
 const unsigned short SVG_EDGEMODE_WRAP = 2;
 const unsigned short SVG_EDGEMODE_NONE = 3;
 
 // Channel Selectors
--- a/layout/reftests/svg/filters/feBlend-1-ref.svg
+++ b/layout/reftests/svg/filters/feBlend-1-ref.svg
@@ -1,9 +1,19 @@
 <svg xmlns="http://www.w3.org/2000/svg">
 
-<rect x="10" y="10" width="80" height="80" fill="#00ff00"/>
-<rect x="110" y="10" width="80" height="80" fill="#000000"/>
-<rect x="210" y="10" width="80" height="80" fill="#ffff00"/>
-<rect x="310" y="10" width="80" height="80" fill="#000000"/>
-<rect x="410" y="10" width="80" height="80" fill="#ffff00"/>
-
+<rect x="0" y="0" width="50" height="50" fill="#ACCC10"/>
+<rect x="50" y="0" width="50" height="50" fill="#B4B43F"/>
+<rect x="100" y="0" width="50" height="50" fill="#DFDF3F"/>
+<rect x="150" y="0" width="50" height="50" fill="#B4B43F"/>
+<rect x="200" y="0" width="50" height="50" fill="#DFDF3F"/>
+<rect x="250" y="0" width="50" height="50" fill="#DFB43F"/>
+<rect x="300" y="0" width="50" height="50" fill="#DFB43F"/>
+<rect x="350" y="0" width="50" height="50" fill="#DFB43F"/>
+<rect x="0" y="50" width="50" height="50" fill="#E0B440"/>
+<rect x="50" y="50" width="50" height="50" fill="#DFB43F"/>
+<rect x="100" y="50" width="50" height="50" fill="#DFDF3F"/>
+<rect x="150" y="50" width="50" height="50" fill="#DFDF3F"/>
+<rect x="200" y="50" width="50" height="50" fill="#B4CC3F"/>
+<rect x="250" y="50" width="50" height="50" fill="#DFB43F"/>
+<rect x="300" y="50" width="50" height="50" fill="#B4CC3F"/>
+<rect x="350" y="50" width="50" height="50" fill="#DFC88D"/>
 </svg>
--- a/layout/reftests/svg/filters/feBlend-1.svg
+++ b/layout/reftests/svg/filters/feBlend-1.svg
@@ -1,38 +1,104 @@
-<svg xmlns="http://www.w3.org/2000/svg">
-
-<filter id="f1" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
-         x="0%" y="0%" width="100%" height="100%">
-  <feFlood flood-color="#ff0000" result="flood"/>
-  <feBlend mode="normal" in="SourceGraphic" in2="flood" x="10%" y="10%" width="80%" height="80%"/>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
+<filter id="f0" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="normal"/>
+</filter>
+<rect x="0" y="0" width="50" height="50" filter="url(#f0)"/>
+<filter id="f1" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="multiply"/>
+</filter>
+<rect x="50" y="0" width="50" height="50" filter="url(#f1)"/>
+<filter id="f2" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="screen"/>
+</filter>
+<rect x="100" y="0" width="50" height="50" filter="url(#f2)"/>
+<filter id="f3" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="darken"/>
 </filter>
-<rect x="0" y="0" width="100" height="100" fill="#00ff00" filter="url(#f1)"/>
-
-<filter id="f2" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
-         x="0%" y="0%" width="100%" height="100%">
-  <feFlood flood-color="#ff0000" result="flood"/>
-  <feBlend mode="multiply" in="SourceGraphic" in2="flood" x="10%" y="10%" width="80%" height="80%"/>
+<rect x="150" y="0" width="50" height="50" filter="url(#f3)"/>
+<filter id="f4" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="lighten"/>
+</filter>
+<rect x="200" y="0" width="50" height="50" filter="url(#f4)"/>
+<filter id="f5" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="overlay"/>
+</filter>
+<rect x="250" y="0" width="50" height="50" filter="url(#f5)"/>
+<filter id="f6" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="color-dodge"/>
+</filter>
+<rect x="300" y="0" width="50" height="50" filter="url(#f6)"/>
+<filter id="f7" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="color-burn"/>
 </filter>
-<rect x="100" y="0" width="100" height="100" fill="#00ff00" filter="url(#f2)"/>
-
-<filter id="f3" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
-         x="0%" y="0%" width="100%" height="100%">
-  <feFlood flood-color="#ff0000" result="flood"/>
-  <feBlend mode="screen" in="SourceGraphic" in2="flood" x="10%" y="10%" width="80%" height="80%"/>
+<rect x="350" y="0" width="50" height="50" filter="url(#f7)"/>
+<filter id="f8" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="hard-light"/>
+</filter>
+<rect x="0" y="0" width="50" height="50" filter="url(#f8)"/>
+<filter id="f9" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="soft-light"/>
+</filter>
+<rect x="50" y="50" width="50" height="50" filter="url(#f9)"/>
+<filter id="f10" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="difference"/>
+</filter>
+<rect x="100" y="50" width="50" height="50" filter="url(#f10)"/>
+<filter id="f11" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="exclusion"/>
 </filter>
-<rect x="200" y="0" width="100" height="100" fill="#00ff00" filter="url(#f3)"/>
-
-<filter id="f4" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
-         x="0%" y="0%" width="100%" height="100%">
-  <feFlood flood-color="#ff0000" result="flood"/>
-  <feBlend mode="darken" in="SourceGraphic" in2="flood" x="10%" y="10%" width="80%" height="80%"/>
+<rect x="150" y="50" width="50" height="50" filter="url(#f11)"/>
+<filter id="f12" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="hue"/>
+</filter>
+<rect x="200" y="50" width="50" height="50" filter="url(#f12)"/>
+<filter id="f13" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="saturation"/>
 </filter>
-<rect x="300" y="0" width="100" height="100" fill="#00ff00" filter="url(#f4)"/>
-
-<filter id="f5" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
-         x="0%" y="0%" width="100%" height="100%">
-  <feFlood flood-color="#ff0000" result="flood"/>
-  <feBlend mode="lighten" in="SourceGraphic" in2="flood" x="10%" y="10%" width="80%" height="80%"/>
+<rect x="250" y="50" width="50" height="50" filter="url(#f13)"/>
+<filter id="f14" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="color"/>
 </filter>
-<rect x="400" y="0" width="100" height="100" fill="#00ff00" filter="url(#f5)"/>
-
-</svg>
+<rect x="300" y="50" width="50" height="50" filter="url(#f14)"/>
+<filter id="f15" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="luminosity"/>
+</filter>
+<rect x="350" y="50" width="50" height="50" filter="url(#f15)"/>
+  <filter id="f16" x="0%" y="0%" width="100%" height="100%">
+  <feFlood result="a" flood-color="rgb(255,0,0)" flood-opacity="0.5"/>
+  <feFlood result="b" flood-color="rgb(0,255,0)" flood-opacity="0.5"/>
+  <feBlend in="a" in2="b" mode="undefined"/>
+</filter>
+<rect x="0" y="50" width="50" height="50" filter="url(#f16)"/>
+</svg>
\ No newline at end of file
--- a/layout/reftests/svg/filters/reftest.list
+++ b/layout/reftests/svg/filters/reftest.list
@@ -13,17 +13,17 @@ include css-svg-filter-chains/reftest.li
 
 # SVG filter chain tests
 include svg-filter-chains/reftest.list
 
 == dynamic-filtered-foreignObject-01.svg pass.svg
 == dynamic-filter-invalidation-01.svg pass.svg
 == dynamic-filter-invalidation-02.svg pass.svg
 
-== feBlend-1.svg feBlend-1-ref.svg
+fuzzy(1,40000) == feBlend-1.svg feBlend-1-ref.svg
 == feBlend-2.svg feBlend-2-ref.svg
 
 fuzzy-if(d2d,1,6400) == feColorMatrix-1.svg feColorMatrix-1-ref.svg
 fuzzy-if(d2d,1,10000) == feColorMatrix-2.svg feColorMatrix-2-ref.svg
 
 == feComponentTransfer-1.svg feComponentTransfer-1-ref.svg
 == feComponentTransfer-2.svg feComponentTransfer-2-ref.svg