Bug 964200 (Part 3 main) - Implement Filter Effects Module feDropShadow filter. r=mstange
☠☠ backed out by 9bb874d01080 ☠ ☠
authorRobert Longson <longsonr@gmail.com>
Wed, 05 Feb 2014 16:46:47 +0000
changeset 166970 19993e76f4a0cb610961129a38fb8f6151870fb9
parent 166969 e9a091fd0265f894828f0d99355279b83643949d
child 166971 7dbe53176a38fbb7a836900f7b621eb989e594d4
push id39348
push userlongsonr@gmail.com
push dateWed, 05 Feb 2014 16:47:21 +0000
treeherdermozilla-inbound@19993e76f4a0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs964200
milestone30.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 964200 (Part 3 main) - Implement Filter Effects Module feDropShadow filter. r=mstange
content/svg/content/src/SVGFEDropShadowElement.cpp
content/svg/content/src/SVGFEDropShadowElement.h
content/svg/content/src/SVGFEGaussianBlurElement.cpp
content/svg/content/src/SVGTagList.h
content/svg/content/src/moz.build
content/svg/content/test/test_SVG_namespace_ids.html
dom/webidl/SVGFEDropShadowElement.webidl
dom/webidl/moz.build
gfx/src/FilterSupport.cpp
gfx/src/FilterSupport.h
layout/base/nsCSSFrameConstructor.cpp
layout/reftests/svg/filters/feDropShadow-01-ref.svg
layout/reftests/svg/filters/feDropShadow-01.svg
copy from content/svg/content/src/SVGFEGaussianBlurElement.cpp
copy to content/svg/content/src/SVGFEDropShadowElement.cpp
--- a/content/svg/content/src/SVGFEGaussianBlurElement.cpp
+++ b/content/svg/content/src/SVGFEDropShadowElement.cpp
@@ -1,125 +1,181 @@
 /* a*- 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 "mozilla/dom/SVGFEGaussianBlurElement.h"
-#include "mozilla/dom/SVGFEGaussianBlurElementBinding.h"
+#include "mozilla/dom/SVGFEDropShadowElement.h"
+#include "mozilla/dom/SVGFEDropShadowElementBinding.h"
 #include "nsSVGFilterInstance.h"
-#include "nsSVGUtils.h"
 
-NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEGaussianBlur)
+NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEDropShadow)
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
 
 JSObject*
-SVGFEGaussianBlurElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
+SVGFEDropShadowElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
-  return SVGFEGaussianBlurElementBinding::Wrap(aCx, aScope, this);
+  return SVGFEDropShadowElementBinding::Wrap(aCx, aScope, this);
 }
 
-nsSVGElement::NumberPairInfo SVGFEGaussianBlurElement::sNumberPairInfo[1] =
+nsSVGElement::NumberInfo SVGFEDropShadowElement::sNumberInfo[2] =
 {
-  { &nsGkAtoms::stdDeviation, 0, 0 }
+  { &nsGkAtoms::dx, 2, false },
+  { &nsGkAtoms::dy, 2, false }
 };
 
-nsSVGElement::StringInfo SVGFEGaussianBlurElement::sStringInfo[2] =
+nsSVGElement::NumberPairInfo SVGFEDropShadowElement::sNumberPairInfo[1] =
+{
+  { &nsGkAtoms::stdDeviation, 2, 2 }
+};
+
+nsSVGElement::StringInfo SVGFEDropShadowElement::sStringInfo[2] =
 {
   { &nsGkAtoms::result, kNameSpaceID_None, true },
   { &nsGkAtoms::in, kNameSpaceID_None, true }
 };
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
-NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEGaussianBlurElement)
+NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEDropShadowElement)
 
 //----------------------------------------------------------------------
 
 already_AddRefed<SVGAnimatedString>
-SVGFEGaussianBlurElement::In1()
+SVGFEDropShadowElement::In1()
 {
   return mStringAttributes[IN1].ToDOMAnimatedString(this);
 }
 
 already_AddRefed<SVGAnimatedNumber>
-SVGFEGaussianBlurElement::StdDeviationX()
+SVGFEDropShadowElement::Dx()
+{
+  return mNumberAttributes[DX].ToDOMAnimatedNumber(this);
+}
+
+already_AddRefed<SVGAnimatedNumber>
+SVGFEDropShadowElement::Dy()
+{
+  return mNumberAttributes[DY].ToDOMAnimatedNumber(this);
+}
+
+already_AddRefed<SVGAnimatedNumber>
+SVGFEDropShadowElement::StdDeviationX()
 {
   return mNumberPairAttributes[STD_DEV].ToDOMAnimatedNumber(nsSVGNumberPair::eFirst, this);
 }
 
 already_AddRefed<SVGAnimatedNumber>
-SVGFEGaussianBlurElement::StdDeviationY()
+SVGFEDropShadowElement::StdDeviationY()
 {
   return mNumberPairAttributes[STD_DEV].ToDOMAnimatedNumber(nsSVGNumberPair::eSecond, this);
 }
 
 void
-SVGFEGaussianBlurElement::SetStdDeviation(float stdDeviationX, float stdDeviationY)
+SVGFEDropShadowElement::SetStdDeviation(float stdDeviationX, float stdDeviationY)
 {
   mNumberPairAttributes[STD_DEV].SetBaseValues(stdDeviationX, stdDeviationY, this);
 }
 
-static const float kMaxStdDeviation = 500;
-
 FilterPrimitiveDescription
-SVGFEGaussianBlurElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
-                                                  const IntRect& aFilterSubregion,
-                                                  const nsTArray<bool>& aInputsAreTainted,
-                                                  nsTArray<RefPtr<SourceSurface>>& aInputImages)
+SVGFEDropShadowElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
+                                                const IntRect& aFilterSubregion,
+                                                const nsTArray<bool>& aInputsAreTainted,
+                                                nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   float stdX = aInstance->GetPrimitiveNumber(SVGContentUtils::X,
                                              &mNumberPairAttributes[STD_DEV],
                                              nsSVGNumberPair::eFirst);
   float stdY = aInstance->GetPrimitiveNumber(SVGContentUtils::Y,
                                              &mNumberPairAttributes[STD_DEV],
                                              nsSVGNumberPair::eSecond);
   if (stdX < 0 || stdY < 0) {
     return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
   }
 
-  stdX = std::min(stdX, kMaxStdDeviation);
-  stdY = std::min(stdY, kMaxStdDeviation);
-  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eGaussianBlur);
-  descr.Attributes().Set(eGaussianBlurStdDeviation, Size(stdX, stdY));
+  IntPoint offset(int32_t(aInstance->GetPrimitiveNumber(
+                            SVGContentUtils::X, &mNumberAttributes[DX])),
+                  int32_t(aInstance->GetPrimitiveNumber(
+                            SVGContentUtils::Y, &mNumberAttributes[DY])));
+
+  FilterPrimitiveDescription descr(FilterPrimitiveDescription::eDropShadow);
+  descr.Attributes().Set(eDropShadowStdDeviation, Size(stdX, stdY));
+  descr.Attributes().Set(eDropShadowOffset, offset);
+
+  nsIFrame* frame = GetPrimaryFrame();
+  if (frame) {
+    nsStyleContext* style = frame->StyleContext();
+    nscolor floodColor = style->StyleSVGReset()->mFloodColor;
+    float floodOpacity = style->StyleSVGReset()->mFloodOpacity;
+    Color color(NS_GET_R(floodColor) / 255.0,
+                NS_GET_G(floodColor) / 255.0,
+                NS_GET_B(floodColor) / 255.0,
+                NS_GET_A(floodColor) / 255.0 * floodOpacity);
+    descr.Attributes().Set(eDropShadowColor, color);
+  } else {
+    descr.Attributes().Set(eDropShadowColor, Color());
+  }
   return descr;
 }
 
 bool
-SVGFEGaussianBlurElement::AttributeAffectsRendering(int32_t aNameSpaceID,
-                                                    nsIAtom* aAttribute) const
+SVGFEDropShadowElement::AttributeAffectsRendering(int32_t aNameSpaceID,
+                                                  nsIAtom* aAttribute) const
 {
-  return SVGFEGaussianBlurElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
+  return SVGFEDropShadowElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
           (aAttribute == nsGkAtoms::in ||
-           aAttribute == nsGkAtoms::stdDeviation));
+           aAttribute == nsGkAtoms::stdDeviation ||
+           aAttribute == nsGkAtoms::dx ||
+           aAttribute == nsGkAtoms::dy));
 }
 
 void
-SVGFEGaussianBlurElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
+SVGFEDropShadowElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
 //----------------------------------------------------------------------
+// nsIContent methods
+
+NS_IMETHODIMP_(bool)
+SVGFEDropShadowElement::IsAttributeMapped(const nsIAtom* name) const
+{
+  static const MappedAttributeEntry* const map[] = {
+    sFEFloodMap
+  };
+
+  return FindAttributeDependence(name, map) ||
+    SVGFEDropShadowElementBase::IsAttributeMapped(name);
+}
+
+//----------------------------------------------------------------------
 // nsSVGElement methods
 
+nsSVGElement::NumberAttributesInfo
+SVGFEDropShadowElement::GetNumberInfo()
+{
+  return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
+                              ArrayLength(sNumberInfo));
+}
+
 nsSVGElement::NumberPairAttributesInfo
-SVGFEGaussianBlurElement::GetNumberPairInfo()
+SVGFEDropShadowElement::GetNumberPairInfo()
 {
   return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
                                   ArrayLength(sNumberPairInfo));
 }
 
 nsSVGElement::StringAttributesInfo
-SVGFEGaussianBlurElement::GetStringInfo()
+SVGFEDropShadowElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               ArrayLength(sStringInfo));
 }
 
 } // namespace dom
 } // namespace mozilla
copy from content/svg/content/src/SVGFEGaussianBlurElement.h
copy to content/svg/content/src/SVGFEDropShadowElement.h
--- a/content/svg/content/src/SVGFEGaussianBlurElement.h
+++ b/content/svg/content/src/SVGFEDropShadowElement.h
@@ -1,68 +1,79 @@
 /* a*- 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 mozilla_dom_SVGFEGaussianBlurElement_h
-#define mozilla_dom_SVGFEGaussianBlurElement_h
+#ifndef mozilla_dom_SVGFEDropShadowElement_h
+#define mozilla_dom_SVGFEDropShadowElement_h
 
 #include "nsSVGFilters.h"
+#include "nsSVGNumber2.h"
 #include "nsSVGNumberPair.h"
 #include "nsSVGString.h"
 
-nsresult NS_NewSVGFEGaussianBlurElement(nsIContent **aResult,
-                                        already_AddRefed<nsINodeInfo> aNodeInfo);
+nsresult NS_NewSVGFEDropShadowElement(nsIContent **aResult,
+                                      already_AddRefed<nsINodeInfo> aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
-typedef nsSVGFE SVGFEGaussianBlurElementBase;
+typedef nsSVGFE SVGFEDropShadowElementBase;
 
-class SVGFEGaussianBlurElement : public SVGFEGaussianBlurElementBase
+class SVGFEDropShadowElement : public SVGFEDropShadowElementBase
 {
-  friend nsresult (::NS_NewSVGFEGaussianBlurElement(nsIContent **aResult,
-                                                    already_AddRefed<nsINodeInfo> aNodeInfo));
+  friend nsresult (::NS_NewSVGFEDropShadowElement(nsIContent **aResult,
+                                                  already_AddRefed<nsINodeInfo> aNodeInfo));
 protected:
-  SVGFEGaussianBlurElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-    : SVGFEGaussianBlurElementBase(aNodeInfo)
+  SVGFEDropShadowElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+    : SVGFEDropShadowElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
   virtual FilterPrimitiveDescription
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<mozilla::RefPtr<SourceSurface>>& aInputImages) MOZ_OVERRIDE;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo >& aSources) MOZ_OVERRIDE;
 
+  // nsIContent interface
+  NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
+
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
+  already_AddRefed<SVGAnimatedNumber> Dx();
+  already_AddRefed<SVGAnimatedNumber> Dy();
   already_AddRefed<SVGAnimatedNumber> StdDeviationX();
   already_AddRefed<SVGAnimatedNumber> StdDeviationY();
   void SetStdDeviation(float stdDeviationX, float stdDeviationY);
 
 protected:
+  virtual NumberAttributesInfo GetNumberInfo() MOZ_OVERRIDE;
   virtual NumberPairAttributesInfo GetNumberPairInfo() MOZ_OVERRIDE;
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
 
+  enum { DX, DY };
+  nsSVGNumber2 mNumberAttributes[2];
+  static NumberInfo sNumberInfo[2];
+
   enum { STD_DEV };
   nsSVGNumberPair mNumberPairAttributes[1];
   static NumberPairInfo sNumberPairInfo[1];
 
   enum { RESULT, IN1 };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_SVGFEGaussianBlurElement_h
+#endif // mozilla_dom_SVGFEDropShadowElement_h
--- a/content/svg/content/src/SVGFEGaussianBlurElement.cpp
+++ b/content/svg/content/src/SVGFEGaussianBlurElement.cpp
@@ -58,36 +58,32 @@ SVGFEGaussianBlurElement::StdDeviationY(
 }
 
 void
 SVGFEGaussianBlurElement::SetStdDeviation(float stdDeviationX, float stdDeviationY)
 {
   mNumberPairAttributes[STD_DEV].SetBaseValues(stdDeviationX, stdDeviationY, this);
 }
 
-static const float kMaxStdDeviation = 500;
-
 FilterPrimitiveDescription
 SVGFEGaussianBlurElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                   const IntRect& aFilterSubregion,
                                                   const nsTArray<bool>& aInputsAreTainted,
                                                   nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   float stdX = aInstance->GetPrimitiveNumber(SVGContentUtils::X,
                                              &mNumberPairAttributes[STD_DEV],
                                              nsSVGNumberPair::eFirst);
   float stdY = aInstance->GetPrimitiveNumber(SVGContentUtils::Y,
                                              &mNumberPairAttributes[STD_DEV],
                                              nsSVGNumberPair::eSecond);
   if (stdX < 0 || stdY < 0) {
     return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
   }
 
-  stdX = std::min(stdX, kMaxStdDeviation);
-  stdY = std::min(stdY, kMaxStdDeviation);
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eGaussianBlur);
   descr.Attributes().Set(eGaussianBlurStdDeviation, Size(stdX, stdY));
   return descr;
 }
 
 bool
 SVGFEGaussianBlurElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                     nsIAtom* aAttribute) const
--- a/content/svg/content/src/SVGTagList.h
+++ b/content/svg/content/src/SVGTagList.h
@@ -40,16 +40,17 @@ SVG_TAG(ellipse, Ellipse)
 SVG_TAG(feBlend, FEBlend)
 SVG_TAG(feColorMatrix, FEColorMatrix)
 SVG_TAG(feComponentTransfer, FEComponentTransfer)
 SVG_TAG(feComposite, FEComposite)
 SVG_TAG(feConvolveMatrix, FEConvolveMatrix)
 SVG_TAG(feDiffuseLighting, FEDiffuseLighting)
 SVG_TAG(feDisplacementMap, FEDisplacementMap)
 SVG_TAG(feDistantLight, FEDistantLight)
+SVG_TAG(feDropShadow, FEDropShadow)
 SVG_TAG(feFlood, FEFlood)
 SVG_TAG(feFuncA, FEFuncA)
 SVG_TAG(feFuncB, FEFuncB)
 SVG_TAG(feFuncG, FEFuncG)
 SVG_TAG(feFuncR, FEFuncR)
 SVG_TAG(feGaussianBlur, FEGaussianBlur)
 SVG_TAG(feImage, FEImage)
 SVG_TAG(feMerge, FEMerge)
--- a/content/svg/content/src/moz.build
+++ b/content/svg/content/src/moz.build
@@ -40,16 +40,17 @@ EXPORTS.mozilla.dom += [
     'SVGFEBlendElement.h',
     'SVGFEColorMatrixElement.h',
     'SVGFEComponentTransferElement.h',
     'SVGFECompositeElement.h',
     'SVGFEConvolveMatrixElement.h',
     'SVGFEDiffuseLightingElement.h',
     'SVGFEDisplacementMapElement.h',
     'SVGFEDistantLightElement.h',
+    'SVGFEDropShadowElement.h',
     'SVGFEFloodElement.h',
     'SVGFEGaussianBlurElement.h',
     'SVGFEImageElement.h',
     'SVGFEMergeElement.h',
     'SVGFEMergeNodeElement.h',
     'SVGFEMorphologyElement.h',
     'SVGFEOffsetElement.h',
     'SVGFEPointLightElement.h',
@@ -163,16 +164,17 @@ UNIFIED_SOURCES += [
     'SVGFEBlendElement.cpp',
     'SVGFEColorMatrixElement.cpp',
     'SVGFEComponentTransferElement.cpp',
     'SVGFECompositeElement.cpp',
     'SVGFEConvolveMatrixElement.cpp',
     'SVGFEDiffuseLightingElement.cpp',
     'SVGFEDisplacementMapElement.cpp',
     'SVGFEDistantLightElement.cpp',
+    'SVGFEDropShadowElement.cpp',
     'SVGFEFloodElement.cpp',
     'SVGFEGaussianBlurElement.cpp',
     'SVGFEImageElement.cpp',
     'SVGFEMergeElement.cpp',
     'SVGFEMergeNodeElement.cpp',
     'SVGFEMorphologyElement.cpp',
     'SVGFEOffsetElement.cpp',
     'SVGFEPointLightElement.cpp',
--- a/content/svg/content/test/test_SVG_namespace_ids.html
+++ b/content/svg/content/test/test_SVG_namespace_ids.html
@@ -49,16 +49,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <feBlend id="feBlend" />
   <feColorMatrix id="feColorMatrix" />
   <feComponentTransfer id="feComponentTransfer" />
   <feComposite id="feComposite" />
   <feConvolveMatrix id="feConvolveMatrix" />
   <feDiffuseLighting id="feDiffuseLighting" />
   <feDisplacementMap id="feDisplacementMap" />
   <feDistantLight id="feDistantLight" />
+  <feDropShadow id="feDropShadow" />
   <feFlood id="feFlood" />
   <feFuncA id="feFuncA" />
   <feFuncB id="feFuncB" />
   <feFuncG id="feFuncG" />
   <feFuncR id="feFuncR" />
   <feGaussianBlur id="feGaussianBlur" />
   <feImage id="feImage" />
   <feMerge id="feMerge" />
copy from dom/webidl/SVGFEGaussianBlurElement.webidl
copy to dom/webidl/SVGFEDropShadowElement.webidl
--- a/dom/webidl/SVGFEGaussianBlurElement.webidl
+++ b/dom/webidl/SVGFEDropShadowElement.webidl
@@ -5,17 +5,19 @@
  *
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface SVGFEGaussianBlurElement : SVGElement {
+interface SVGFEDropShadowElement : SVGElement {
   readonly attribute SVGAnimatedString in1;
+  readonly attribute SVGAnimatedNumber dx;
+  readonly attribute SVGAnimatedNumber dy;
   readonly attribute SVGAnimatedNumber stdDeviationX;
   readonly attribute SVGAnimatedNumber stdDeviationY;
 
   void setStdDeviation(float stdDeviationX, float stdDeviationY);
 };
 
-SVGFEGaussianBlurElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEDropShadowElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -321,16 +321,17 @@ WEBIDL_FILES = [
     'SVGFEBlendElement.webidl',
     'SVGFEColorMatrixElement.webidl',
     'SVGFEComponentTransferElement.webidl',
     'SVGFECompositeElement.webidl',
     'SVGFEConvolveMatrixElement.webidl',
     'SVGFEDiffuseLightingElement.webidl',
     'SVGFEDisplacementMapElement.webidl',
     'SVGFEDistantLightElement.webidl',
+    'SVGFEDropShadowElement.webidl',
     'SVGFEFloodElement.webidl',
     'SVGFEFuncAElement.webidl',
     'SVGFEFuncBElement.webidl',
     'SVGFEFuncGElement.webidl',
     'SVGFEFuncRElement.webidl',
     'SVGFEGaussianBlurElement.webidl',
     'SVGFEImageElement.webidl',
     'SVGFEMergeElement.webidl',
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -90,16 +90,18 @@ static const float gsRGBToLinearRGBMap[2
   0.939f, 0.947f, 0.956f, 0.965f, 0.973f, 0.982f, 0.991f, 1.000f
 };
 
 namespace mozilla {
 namespace gfx {
 
 // Some convenience FilterNode creation functions.
 
+static const float kMaxStdDeviation = 500;
+
 namespace FilterWrappers {
 
   static TemporaryRef<FilterNode>
   Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
     filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
     return filter;
@@ -157,16 +159,38 @@ namespace FilterWrappers {
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
     filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix().Translate(aOffset.x, aOffset.y));
     filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
     return filter;
   }
 
   static TemporaryRef<FilterNode>
+  GaussianBlur(DrawTarget* aDT, FilterNode* aInputFilter, const Size& aStdDeviation)
+  {
+    float stdX = float(std::min(aStdDeviation.width, kMaxStdDeviation));
+    float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
+    if (stdX == stdY) {
+      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
+      filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
+      filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
+      return filter;
+    }
+    RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
+    RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
+    filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
+    filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
+    filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
+    filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
+    filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
+    filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
+    return filterV;
+  }
+
+  static TemporaryRef<FilterNode>
   Clear(DrawTarget* aDT)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
     filter->SetAttribute(ATT_FLOOD_COLOR, Color(0,0,0,0));
     return filter;
   }
 
   static TemporaryRef<FilterNode>
@@ -810,32 +834,47 @@ FilterNodeFromPrimitiveDescription(const
       for (size_t i = 0; i < aSources.Length(); i++) {
         filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
       }
       return filter;
     }
 
     case FilterPrimitiveDescription::eGaussianBlur:
     {
-      Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
-      if (stdDeviation.width == stdDeviation.height) {
-        RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
-        filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, float(stdDeviation.width));
-        filter->SetInput(IN_GAUSSIAN_BLUR_IN, aSources[0]);
-        return filter;
+      return FilterWrappers::GaussianBlur(aDT, aSources[0],
+                                          atts.GetSize(eGaussianBlurStdDeviation));
+    }
+
+    case FilterPrimitiveDescription::eDropShadow:
+    {
+      RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(aDT, aSources[0]);
+      RefPtr<FilterNode> blur = FilterWrappers::GaussianBlur(aDT, alpha,
+                                  atts.GetSize(eDropShadowStdDeviation));
+      RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
+                                        atts.GetIntPoint(eDropShadowOffset));
+      RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
+      Color color = atts.GetColor(eDropShadowColor);
+      if (aDescription.InputColorSpace(0) == LINEAR_RGB) {
+        color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
+                      gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
+                      gsRGBToLinearRGBMap[uint8_t(color.b * 255)],
+                      color.a);
       }
-      RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
-      RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
-      filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
-      filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, float(stdDeviation.width));
-      filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
-      filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, float(stdDeviation.height));
-      filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aSources[0]);
-      filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
-      return filterV;
+      flood->SetAttribute(ATT_FLOOD_COLOR, color);
+
+      RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
+      composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
+      composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
+      composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
+
+      RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
+      filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
+      filter->SetInput(IN_COMPOSITE_IN_START, composite);
+      filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
+      return filter;
     }
 
     case FilterPrimitiveDescription::eDiffuseLighting:
     case FilterPrimitiveDescription::eSpecularLighting:
     {
       bool isSpecular =
         aDescription.Type() == FilterPrimitiveDescription::eSpecularLighting;
 
@@ -1122,21 +1161,19 @@ UnionOfRegions(const nsTArray<nsIntRegio
   nsIntRegion result;
   for (size_t i = 0; i < aRegions.Length(); i++) {
     result.Or(result, aRegions[i]);
   }
   return result;
 }
 
 static int32_t
-InflateSizeForBlurStdDev(double aStdDev)
+InflateSizeForBlurStdDev(float aStdDev)
 {
-  double size = aStdDev * (3 * sqrt(2 * M_PI) / 4) * 1.5;
-  static const double max = 1024;
-  size = std::min(size, max);
+  double size = std::min(aStdDev, kMaxStdDeviation) * (3 * sqrt(2 * M_PI) / 4) * 1.5;
   return uint32_t(floor(size + 0.5));
 }
 
 static nsIntRegion
 ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
                                const nsTArray<nsIntRegion>& aInputChangeRegions)
 {
   const AttributeMap& atts = aDescription.Attributes();
@@ -1195,16 +1232,28 @@ ResultChangeRegionForPrimitive(const Fil
     case FilterPrimitiveDescription::eGaussianBlur:
     {
       Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
       return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
     }
 
+    case FilterPrimitiveDescription::eDropShadow:
+    {
+      IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
+      nsIntRegion offsetRegion = aInputChangeRegions[0].MovedBy(offset.x, offset.y);
+      Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
+      int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
+      int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
+      nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
+      blurRegion.Or(blurRegion, aInputChangeRegions[0]);
+      return blurRegion;
+    }
+
     case FilterPrimitiveDescription::eDiffuseLighting:
     case FilterPrimitiveDescription::eSpecularLighting:
     {
       Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
       int32_t dx = ceil(kernelUnitLength.width);
       int32_t dy = ceil(kernelUnitLength.height);
       return aInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
     }
@@ -1413,16 +1462,29 @@ SourceNeededRegionForPrimitive(const Fil
     case FilterPrimitiveDescription::eGaussianBlur:
     {
       Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation);
       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
       return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
     }
 
+    case FilterPrimitiveDescription::eDropShadow:
+    {
+      IntPoint offset = atts.GetIntPoint(eDropShadowOffset);
+      nsIntRegion offsetRegion =
+        aResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
+      Size stdDeviation = atts.GetSize(eDropShadowStdDeviation);
+      int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
+      int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
+      nsIntRegion blurRegion = offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
+      blurRegion.Or(blurRegion, aResultNeededRegion);
+      return blurRegion;
+    }
+
     case FilterPrimitiveDescription::eDiffuseLighting:
     case FilterPrimitiveDescription::eSpecularLighting:
     {
       Size kernelUnitLength = atts.GetSize(eLightingKernelUnitLength);
       int32_t dx = ceil(kernelUnitLength.width);
       int32_t dy = ceil(kernelUnitLength.height);
       return aResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
     }
--- a/gfx/src/FilterSupport.h
+++ b/gfx/src/FilterSupport.h
@@ -95,16 +95,19 @@ enum AttributeName {
   eConvolveMatrixKernelMatrix,
   eConvolveMatrixDivisor,
   eConvolveMatrixBias,
   eConvolveMatrixTarget,
   eConvolveMatrixEdgeMode,
   eConvolveMatrixKernelUnitLength,
   eConvolveMatrixPreserveAlpha,
   eOffsetOffset,
+  eDropShadowStdDeviation,
+  eDropShadowOffset,
+  eDropShadowColor,
   eDisplacementMapScale,
   eDisplacementMapXChannel,
   eDisplacementMapYChannel,
   eTurbulenceOffset,
   eTurbulenceBaseFrequency,
   eTurbulenceNumOctaves,
   eTurbulenceSeed,
   eTurbulenceStitchable,
@@ -226,16 +229,17 @@ public:
     eConvolveMatrix,
     eOffset,
     eDisplacementMap,
     eTurbulence,
     eComposite,
     eMerge,
     eImage,
     eGaussianBlur,
+    eDropShadow,
     eDiffuseLighting,
     eSpecularLighting
   };
   enum {
     kPrimitiveIndexSourceGraphic = -1,
     kPrimitiveIndexSourceAlpha = -2,
     kPrimitiveIndexFillPaint = -3,
     kPrimitiveIndexStrokePaint = -4
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -4984,16 +4984,17 @@ nsCSSFrameConstructor::FindSVGData(Eleme
     SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
     SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
     SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
     SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
     SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
     SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
     SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
     SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
+    SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame),
     SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
     SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
     SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
     SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
     SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
     SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame), 
     SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame), 
     SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/feDropShadow-01-ref.svg
@@ -0,0 +1,68 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+
+  <title>Reference for Filter Effects Module Level 1 feDropShadow</title>
+
+  <defs>
+    <filter id="dropShadow1">
+      <feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
+      <feOffset dx="2" dy="2" result="offsetblur"/>
+      <feFlood flood-color="green"/>
+      <feComposite in2="offsetblur" operator="in"/>
+      <feMerge>
+        <feMergeNode/>
+        <feMergeNode in="SourceGraphic"/>
+      </feMerge>
+    </filter>
+    <filter id="dropShadow2">
+      <feGaussianBlur in="SourceAlpha" stdDeviation="5"/>
+      <feOffset dx="-2" dy="-5" result="offsetblur"/>
+      <feFlood flood-color="green"/>
+      <feComposite in2="offsetblur" operator="in"/>
+      <feMerge>
+        <feMergeNode/>
+        <feMergeNode in="SourceGraphic"/>
+      </feMerge>
+    </filter>
+    <filter id="dropShadow3">
+      <feGaussianBlur in="SourceAlpha" stdDeviation="2 5"/>
+      <feOffset dx="5" dy="5" result="offsetblur"/>
+      <feFlood flood-color="green" flood-opacity="0.5"/>
+      <feComposite in2="offsetblur" operator="in"/>
+      <feMerge>
+        <feMergeNode/>
+        <feMergeNode in="SourceGraphic"/>
+      </feMerge>
+    </filter>
+    <filter id="dropShadow4" color-interpolation-filters="sRGB">
+      <feGaussianBlur in="SourceAlpha" stdDeviation="5"/>
+      <feOffset dx="5" dy="5" result="offsetblur"/>
+      <feFlood flood-color="green"/>
+      <feComposite in2="offsetblur" operator="in"/>
+      <feMerge>
+        <feMergeNode/>
+        <feMergeNode in="SourceGraphic"/>
+      </feMerge>
+    </filter>
+    <filter id="dropShadow5">
+      <feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
+      <feOffset dx="2" dy="2" result="offsetblur"/>
+      <feFlood flood-color="green"/>
+      <feComposite in2="offsetblur" operator="in"/>
+      <feMerge>
+        <feMergeNode/>
+        <feMergeNode in="SourceAlpha"/>
+      </feMerge>
+    </filter>
+  </defs>
+  <g fill="yellow" transform="translate(10,10)">
+    <circle cx="75" cy="75" r="70" filter="url(#dropShadow1)" />
+    <circle cx="250" cy="75" r="70" filter="url(#dropShadow2)" />
+    <circle cx="425" cy="75" r="70" filter="url(#dropShadow3)" />
+    <circle cx="600" cy="75" r="70" filter="url(#dropShadow4)" />
+    <circle cx="75" cy="250" r="70" filter="url(#dropShadow5)" />
+  </g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/feDropShadow-01.svg
@@ -0,0 +1,43 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+
+  <title>Testcase for Filter Effects Module Level 1 feDropShadow</title>
+
+  <defs>
+    <!-- check default values -->
+    <filter id="dropShadow1">
+      <feDropShadow flood-color="green"/>
+    </filter>
+    <!-- check negative dx, dy -->
+    <filter id="dropShadow2">
+      <feDropShadow stdDeviation="5" dx="-2" dy="-5" flood-color="green"/>
+    </filter>
+    <!-- check flood-opacity and non-default values -->
+    <filter id="dropShadow3">
+      <feDropShadow stdDeviation="2 5" dx="5" dy="5" flood-color="green" flood-opacity="0.5"/>
+    </filter>
+    <!-- check sRGB -->
+    <filter id="dropShadow4" color-interpolation-filters="sRGB">
+      <feDropShadow stdDeviation="5" dx="5" dy="5" flood-color="green"/>
+    </filter>
+    <!-- check sourceAlpha input -->
+    <filter id="dropShadow5">
+      <feDropShadow in="SourceAlpha" flood-color="green"/>
+    </filter>
+    <!-- check negative stdDeviation (should not display anything) -->
+    <filter id="dropShadow6">
+      <feDropShadow stdDeviation="-2" flood-color="green"/>
+    </filter>
+  </defs>
+  <g fill="yellow" transform="translate(10,10)">
+    <circle cx="75" cy="75" r="70" filter="url(#dropShadow1)" />
+    <circle cx="250" cy="75" r="70" filter="url(#dropShadow2)" />
+    <circle cx="425" cy="75" r="70" filter="url(#dropShadow3)" />
+    <circle cx="600" cy="75" r="70" filter="url(#dropShadow4)" />
+    <circle cx="75" cy="250" r="70" filter="url(#dropShadow5)" />
+    <circle cx="250" cy="250" r="70" filter="url(#dropShadow6)" />
+  </g>
+</svg>