Bug 941887. r=roc, a=abillings
authorMarkus Stange <mstange@themasta.com>
Wed, 08 Jan 2014 10:30:03 +0100
changeset 176039 b7124d82a8ef5d782e29cd479742a69c521187ee
parent 176038 9c7bc5a8c72407b059b24a360057f85af5c10442
child 176040 c491444042dc8760ba1eb172fefe462507d9e6a4
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, abillings
bugs941887
milestone28.0a2
Bug 941887. r=roc, a=abillings
content/svg/content/src/SVGFEBlendElement.cpp
content/svg/content/src/SVGFEBlendElement.h
content/svg/content/src/SVGFEColorMatrixElement.cpp
content/svg/content/src/SVGFEColorMatrixElement.h
content/svg/content/src/SVGFEComponentTransferElement.cpp
content/svg/content/src/SVGFEComponentTransferElement.h
content/svg/content/src/SVGFECompositeElement.cpp
content/svg/content/src/SVGFECompositeElement.h
content/svg/content/src/SVGFEConvolveMatrixElement.cpp
content/svg/content/src/SVGFEConvolveMatrixElement.h
content/svg/content/src/SVGFEDiffuseLightingElement.cpp
content/svg/content/src/SVGFEDiffuseLightingElement.h
content/svg/content/src/SVGFEDisplacementMapElement.cpp
content/svg/content/src/SVGFEDisplacementMapElement.h
content/svg/content/src/SVGFEFloodElement.cpp
content/svg/content/src/SVGFEFloodElement.h
content/svg/content/src/SVGFEGaussianBlurElement.cpp
content/svg/content/src/SVGFEGaussianBlurElement.h
content/svg/content/src/SVGFEImageElement.cpp
content/svg/content/src/SVGFEImageElement.h
content/svg/content/src/SVGFEMergeElement.cpp
content/svg/content/src/SVGFEMergeElement.h
content/svg/content/src/SVGFEMorphologyElement.cpp
content/svg/content/src/SVGFEMorphologyElement.h
content/svg/content/src/SVGFEOffsetElement.cpp
content/svg/content/src/SVGFEOffsetElement.h
content/svg/content/src/SVGFESpecularLightingElement.cpp
content/svg/content/src/SVGFESpecularLightingElement.h
content/svg/content/src/SVGFETileElement.cpp
content/svg/content/src/SVGFETileElement.h
content/svg/content/src/SVGFETurbulenceElement.cpp
content/svg/content/src/SVGFETurbulenceElement.h
content/svg/content/src/nsSVGFilters.cpp
content/svg/content/src/nsSVGFilters.h
gfx/src/FilterSupport.cpp
gfx/src/FilterSupport.h
layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-1.svg
layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-2.svg
layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-3.svg
layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-ref.svg
layout/generic/test/file_taintedfilters_feDisplacementMap-untainted-1.svg
layout/generic/test/file_taintedfilters_feDisplacementMap-untainted-2.svg
layout/generic/test/file_taintedfilters_feDisplacementMap-untainted-ref.svg
layout/generic/test/file_taintedfilters_red-flood-for-feImage-cors.svg
layout/generic/test/file_taintedfilters_red-flood-for-feImage-cors.svg^headers^
layout/generic/test/file_taintedfilters_red-flood-for-feImage.svg
layout/generic/test/mochitest.ini
layout/generic/test/test_taintedfilters.html
layout/svg/nsSVGFilterInstance.cpp
layout/svg/nsSVGFilterInstance.h
--- a/content/svg/content/src/SVGFEBlendElement.cpp
+++ b/content/svg/content/src/SVGFEBlendElement.cpp
@@ -68,16 +68,17 @@ already_AddRefed<SVGAnimatedEnumeration>
 SVGFEBlendElement::Mode()
 {
   return mEnumAttributes[MODE].ToDOMAnimatedEnum(this);
 }
 
 FilterPrimitiveDescription
 SVGFEBlendElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                            const IntRect& aFilterSubregion,
+                                           const nsTArray<bool>& aInputsAreTainted,
                                            nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   uint32_t mode = mEnumAttributes[MODE].GetAnimValue();
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eBlend);
   descr.Attributes().Set(eBlendBlendmode, mode);
   return descr;
 }
 
--- a/content/svg/content/src/SVGFEBlendElement.h
+++ b/content/svg/content/src/SVGFEBlendElement.h
@@ -27,16 +27,17 @@ protected:
   }
   virtual JSObject* WrapNode(JSContext *cx,
                              JS::Handle<JSObject*> scope) 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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEColorMatrixElement.cpp
+++ b/content/svg/content/src/SVGFEColorMatrixElement.cpp
@@ -82,16 +82,17 @@ void
 SVGFEColorMatrixElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
 FilterPrimitiveDescription
 SVGFEColorMatrixElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                  const IntRect& aFilterSubregion,
+                                                 const nsTArray<bool>& aInputsAreTainted,
                                                  nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   uint32_t type = mEnumAttributes[TYPE].GetAnimValue();
   const SVGNumberList &values = mNumberListAttributes[VALUES].GetAnimValue();
 
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eColorMatrix);
   if (!mNumberListAttributes[VALUES].IsExplicitlySet() &&
       (type == SVG_FECOLORMATRIX_TYPE_MATRIX ||
--- a/content/svg/content/src/SVGFEColorMatrixElement.h
+++ b/content/svg/content/src/SVGFEColorMatrixElement.h
@@ -29,16 +29,17 @@ protected:
   }
   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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEComponentTransferElement.cpp
+++ b/content/svg/content/src/SVGFEComponentTransferElement.cpp
@@ -49,16 +49,17 @@ SVGFEComponentTransferElement::GetString
                               ArrayLength(sStringInfo));
 }
 
 //--------------------------------------------
 
 FilterPrimitiveDescription
 SVGFEComponentTransferElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                        const IntRect& aFilterSubregion,
+                                                       const nsTArray<bool>& aInputsAreTainted,
                                                        nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   nsRefPtr<SVGComponentTransferFunctionElement> childForChannel[4];
 
   for (nsIContent* childContent = nsINode::GetFirstChild();
        childContent;
        childContent = childContent->GetNextSibling()) {
 
--- a/content/svg/content/src/SVGFEComponentTransferElement.h
+++ b/content/svg/content/src/SVGFEComponentTransferElement.h
@@ -27,16 +27,17 @@ protected:
   }
   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
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
--- a/content/svg/content/src/SVGFECompositeElement.cpp
+++ b/content/svg/content/src/SVGFECompositeElement.cpp
@@ -107,16 +107,17 @@ SVGFECompositeElement::SetK(float k1, fl
   mNumberAttributes[ATTR_K2].SetBaseValue(k2, this);
   mNumberAttributes[ATTR_K3].SetBaseValue(k3, this);
   mNumberAttributes[ATTR_K4].SetBaseValue(k4, this);
 }
 
 FilterPrimitiveDescription
 SVGFECompositeElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                const IntRect& aFilterSubregion,
+                                               const nsTArray<bool>& aInputsAreTainted,
                                                nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eComposite);
   uint32_t op = mEnumAttributes[OPERATOR].GetAnimValue();
   descr.Attributes().Set(eCompositeOperator, op);
 
   if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
     float k[4];
--- a/content/svg/content/src/SVGFECompositeElement.h
+++ b/content/svg/content/src/SVGFECompositeElement.h
@@ -29,16 +29,17 @@ protected:
   }
   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;
 
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
--- a/content/svg/content/src/SVGFEConvolveMatrixElement.cpp
+++ b/content/svg/content/src/SVGFEConvolveMatrixElement.cpp
@@ -161,16 +161,17 @@ void
 SVGFEConvolveMatrixElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
   aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
 }
 
 FilterPrimitiveDescription
 SVGFEConvolveMatrixElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                     const IntRect& aFilterSubregion,
+                                                    const nsTArray<bool>& aInputsAreTainted,
                                                     nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   const FilterPrimitiveDescription failureDescription(FilterPrimitiveDescription::eNone);
 
   const SVGNumberList &kernelMatrix =
     mNumberListAttributes[KERNELMATRIX].GetAnimValue();
   uint32_t kmLength = kernelMatrix.Length();
 
--- a/content/svg/content/src/SVGFEConvolveMatrixElement.h
+++ b/content/svg/content/src/SVGFEConvolveMatrixElement.h
@@ -37,16 +37,17 @@ protected:
   }
   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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEDiffuseLightingElement.cpp
+++ b/content/svg/content/src/SVGFEDiffuseLightingElement.cpp
@@ -58,16 +58,17 @@ SVGFEDiffuseLightingElement::KernelUnitL
 {
   return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(
     nsSVGNumberPair::eSecond, this);
 }
 
 FilterPrimitiveDescription
 SVGFEDiffuseLightingElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                      const IntRect& aFilterSubregion,
+                                                     const nsTArray<bool>& aInputsAreTainted,
                                                      nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   float diffuseConstant = mNumberAttributes[DIFFUSE_CONSTANT].GetAnimValue();
 
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eDiffuseLighting);
   descr.Attributes().Set(eDiffuseLightingDiffuseConstant, diffuseConstant);
   return AddLightingAttributes(descr, aInstance);
 }
--- a/content/svg/content/src/SVGFEDiffuseLightingElement.h
+++ b/content/svg/content/src/SVGFEDiffuseLightingElement.h
@@ -27,16 +27,17 @@ protected:
   }
   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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
--- a/content/svg/content/src/SVGFEDisplacementMapElement.cpp
+++ b/content/svg/content/src/SVGFEDisplacementMapElement.cpp
@@ -88,18 +88,27 @@ already_AddRefed<SVGAnimatedEnumeration>
 SVGFEDisplacementMapElement::YChannelSelector()
 {
   return mEnumAttributes[CHANNEL_Y].ToDOMAnimatedEnum(this);
 }
 
 FilterPrimitiveDescription
 SVGFEDisplacementMapElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                      const IntRect& aFilterSubregion,
+                                                     const nsTArray<bool>& aInputsAreTainted,
                                                      nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
+  if (aInputsAreTainted[1]) {
+    // If the map is tainted, refuse to apply the effect and act as a
+    // pass-through filter instead, as required by the spec.
+    FilterPrimitiveDescription descr(FilterPrimitiveDescription::eOffset);
+    descr.Attributes().Set(eOffsetOffset, IntPoint(0, 0));
+    return descr;
+  }
+
   float scale = aInstance->GetPrimitiveNumber(SVGContentUtils::XY,
                                               &mNumberAttributes[SCALE]);
   uint32_t xChannel = mEnumAttributes[CHANNEL_X].GetAnimValue();
   uint32_t yChannel = mEnumAttributes[CHANNEL_Y].GetAnimValue();
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eDisplacementMap);
   descr.Attributes().Set(eDisplacementMapScale, scale);
   descr.Attributes().Set(eDisplacementMapXChannel, xChannel);
   descr.Attributes().Set(eDisplacementMapYChannel, yChannel);
--- a/content/svg/content/src/SVGFEDisplacementMapElement.h
+++ b/content/svg/content/src/SVGFEDisplacementMapElement.h
@@ -28,16 +28,17 @@ protected:
   }
   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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEFloodElement.cpp
+++ b/content/svg/content/src/SVGFEFloodElement.cpp
@@ -30,16 +30,17 @@ nsSVGElement::StringInfo SVGFEFloodEleme
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEFloodElement)
 
 FilterPrimitiveDescription
 SVGFEFloodElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                            const IntRect& aFilterSubregion,
+                                           const nsTArray<bool>& aInputsAreTainted,
                                            nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eFlood);
   nsIFrame* frame = GetPrimaryFrame();
   if (frame) {
     nsStyleContext* style = frame->StyleContext();
     nscolor floodColor = style->StyleSVGReset()->mFloodColor;
     float floodOpacity = style->StyleSVGReset()->mFloodOpacity;
--- a/content/svg/content/src/SVGFEFloodElement.h
+++ b/content/svg/content/src/SVGFEFloodElement.h
@@ -29,16 +29,17 @@ protected:
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
   virtual bool SubregionIsUnionOfRegions() MOZ_OVERRIDE { return false; }
 
   virtual FilterPrimitiveDescription
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
+                            const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<mozilla::RefPtr<SourceSurface>>& aInputImages) MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEGaussianBlurElement.cpp
+++ b/content/svg/content/src/SVGFEGaussianBlurElement.cpp
@@ -63,16 +63,17 @@ SVGFEGaussianBlurElement::SetStdDeviatio
   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);
--- a/content/svg/content/src/SVGFEGaussianBlurElement.h
+++ b/content/svg/content/src/SVGFEGaussianBlurElement.h
@@ -29,16 +29,17 @@ protected:
   }
   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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEImageElement.cpp
+++ b/content/svg/content/src/SVGFEImageElement.cpp
@@ -188,16 +188,17 @@ SVGFEImageElement::Href()
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGFEImageElement methods
 
 FilterPrimitiveDescription
 SVGFEImageElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                            const IntRect& aFilterSubregion,
+                                           const nsTArray<bool>& aInputsAreTainted,
                                            nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   nsIFrame* frame = GetPrimaryFrame();
   if (!frame) {
     return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
   }
 
   nsCOMPtr<imgIRequest> currentRequest;
@@ -256,16 +257,61 @@ SVGFEImageElement::AttributeAffectsRende
 {
   // nsGkAtoms::href is deliberately omitted as the frame has special
   // handling to load the image
   return SVGFEImageElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
          (aNameSpaceID == kNameSpaceID_None &&
           aAttribute == nsGkAtoms::preserveAspectRatio);
 }
 
+bool
+SVGFEImageElement::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
+                                   nsIPrincipal* aReferencePrincipal)
+{
+  nsresult rv;
+  nsCOMPtr<imgIRequest> currentRequest;
+  GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
+             getter_AddRefs(currentRequest));
+
+  if (!currentRequest) {
+    return false;
+  }
+
+  uint32_t status;
+  currentRequest->GetImageStatus(&status);
+  if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
+    // The load has not completed yet.
+    return false;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = currentRequest->GetImagePrincipal(getter_AddRefs(principal));
+  if (NS_FAILED(rv) || !principal) {
+    return true;
+  }
+
+  int32_t corsmode;
+  if (NS_SUCCEEDED(currentRequest->GetCORSMode(&corsmode)) &&
+      corsmode != imgIRequest::CORS_NONE) {
+    // If CORS was used to load the image, the page is allowed to read from it.
+    return false;
+  }
+
+  // Ignore document.domain in this check.
+  bool subsumes;
+  rv = aReferencePrincipal->SubsumesIgnoringDomain(principal, &subsumes);
+
+  if (NS_SUCCEEDED(rv) && subsumes) {
+    // The page is allowed to read from the image.
+    return false;
+  }
+
+  return true;
+}
+
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGFEImageElement::PreserveAspectRatio()
 {
   nsRefPtr<DOMSVGAnimatedPreserveAspectRatio> ratio;
   mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(getter_AddRefs(ratio), this);
--- a/content/svg/content/src/SVGFEImageElement.h
+++ b/content/svg/content/src/SVGFEImageElement.h
@@ -36,20 +36,23 @@ public:
   virtual bool SubregionIsUnionOfRegions() MOZ_OVERRIDE { return false; }
 
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
   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 bool OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
+                               nsIPrincipal* aReferencePrincipal) MOZ_OVERRIDE;
 
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE;
--- a/content/svg/content/src/SVGFEMergeElement.cpp
+++ b/content/svg/content/src/SVGFEMergeElement.cpp
@@ -25,16 +25,17 @@ nsSVGElement::StringInfo SVGFEMergeEleme
   { &nsGkAtoms::result, kNameSpaceID_None, true }
 };
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEMergeElement)
 
 FilterPrimitiveDescription
 SVGFEMergeElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                            const IntRect& aFilterSubregion,
+                                           const nsTArray<bool>& aInputsAreTainted,
                                            nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   return FilterPrimitiveDescription(FilterPrimitiveDescription::eMerge);
 }
 
 void
 SVGFEMergeElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
--- a/content/svg/content/src/SVGFEMergeElement.h
+++ b/content/svg/content/src/SVGFEMergeElement.h
@@ -27,16 +27,17 @@ protected:
   }
   virtual JSObject* WrapNode(JSContext *cx,
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
   virtual FilterPrimitiveDescription
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
+                            const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<mozilla::RefPtr<SourceSurface>>& aInputImages) MOZ_OVERRIDE;
   virtual nsSVGString& GetResultImageName() MOZ_OVERRIDE { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
 
   // nsIContent
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 protected:
   virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;
--- a/content/svg/content/src/SVGFEMorphologyElement.cpp
+++ b/content/svg/content/src/SVGFEMorphologyElement.cpp
@@ -109,16 +109,17 @@ SVGFEMorphologyElement::GetRXY(int32_t *
                                                   &mNumberPairAttributes[RADIUS],
                                                   nsSVGNumberPair::eSecond) -
                      MORPHOLOGY_EPSILON);
 }
 
 FilterPrimitiveDescription
 SVGFEMorphologyElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                 const IntRect& aFilterSubregion,
+                                                const nsTArray<bool>& aInputsAreTainted,
                                                 nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   int32_t rx, ry;
   GetRXY(&rx, &ry, *aInstance);
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eMorphology);
   descr.Attributes().Set(eMorphologyRadii, Size(rx, ry));
   descr.Attributes().Set(eMorphologyOperator,
                          (uint32_t)mEnumAttributes[OPERATOR].GetAnimValue());
--- a/content/svg/content/src/SVGFEMorphologyElement.h
+++ b/content/svg/content/src/SVGFEMorphologyElement.h
@@ -30,16 +30,17 @@ protected:
   }
   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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFEOffsetElement.cpp
+++ b/content/svg/content/src/SVGFEOffsetElement.cpp
@@ -67,16 +67,17 @@ SVGFEOffsetElement::GetOffset(const nsSV
                               SVGContentUtils::X, &mNumberAttributes[DX])),
                     int32_t(aInstance.GetPrimitiveNumber(
                               SVGContentUtils::Y, &mNumberAttributes[DY])));
 }
 
 FilterPrimitiveDescription
 SVGFEOffsetElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                             const IntRect& aFilterSubregion,
+                                            const nsTArray<bool>& aInputsAreTainted,
                                             nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   FilterPrimitiveDescription descr(FilterPrimitiveDescription::eOffset);
   nsIntPoint offset = GetOffset(*aInstance);
   descr.Attributes().Set(eOffsetOffset, IntPoint(offset.x, offset.y));
   return descr;
 }
 
--- a/content/svg/content/src/SVGFEOffsetElement.h
+++ b/content/svg/content/src/SVGFEOffsetElement.h
@@ -29,16 +29,17 @@ protected:
   }
   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() { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFESpecularLightingElement.cpp
+++ b/content/svg/content/src/SVGFESpecularLightingElement.cpp
@@ -65,16 +65,17 @@ SVGFESpecularLightingElement::KernelUnit
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 FilterPrimitiveDescription
 SVGFESpecularLightingElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                       const IntRect& aFilterSubregion,
+                                                      const nsTArray<bool>& aInputsAreTainted,
                                                       nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   float specularExponent = mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue();
   float specularConstant = mNumberAttributes[SPECULAR_CONSTANT].GetAnimValue();
 
   // specification defined range (15.22)
   if (specularExponent < 1 || specularExponent > 128) {
     return FilterPrimitiveDescription(FilterPrimitiveDescription::eNone);
--- a/content/svg/content/src/SVGFESpecularLightingElement.h
+++ b/content/svg/content/src/SVGFESpecularLightingElement.h
@@ -31,16 +31,17 @@ protected:
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   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;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> SurfaceScale();
   already_AddRefed<SVGAnimatedNumber> SpecularConstant();
--- a/content/svg/content/src/SVGFETileElement.cpp
+++ b/content/svg/content/src/SVGFETileElement.cpp
@@ -46,16 +46,17 @@ SVGFETileElement::GetSourceImageNames(ns
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 FilterPrimitiveDescription
 SVGFETileElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                           const IntRect& aFilterSubregion,
+                                          const nsTArray<bool>& aInputsAreTainted,
                                           nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   return FilterPrimitiveDescription(FilterPrimitiveDescription::eTile);
 }
 
 bool
 SVGFETileElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                             nsIAtom* aAttribute) const
--- a/content/svg/content/src/SVGFETileElement.h
+++ b/content/svg/content/src/SVGFETileElement.h
@@ -29,16 +29,17 @@ protected:
                              JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
 
 public:
   virtual bool SubregionIsUnionOfRegions() { return false; }
 
   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;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
--- a/content/svg/content/src/SVGFETurbulenceElement.cpp
+++ b/content/svg/content/src/SVGFETurbulenceElement.cpp
@@ -116,16 +116,17 @@ already_AddRefed<SVGAnimatedEnumeration>
 SVGFETurbulenceElement::Type()
 {
   return mEnumAttributes[TYPE].ToDOMAnimatedEnum(this);
 }
 
 FilterPrimitiveDescription
 SVGFETurbulenceElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                                 const IntRect& aFilterSubregion,
+                                                const nsTArray<bool>& aInputsAreTainted,
                                                 nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   float fX = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eFirst);
   float fY = mNumberPairAttributes[BASE_FREQ].GetAnimValue(nsSVGNumberPair::eSecond);
   float seed = mNumberAttributes[OCTAVES].GetAnimValue();
   uint32_t octaves = clamped(mIntegerAttributes[OCTAVES].GetAnimValue(), 0, MAX_OCTAVES);
   uint32_t type = mEnumAttributes[TYPE].GetAnimValue();
   uint16_t stitch = mEnumAttributes[STITCHTILES].GetAnimValue();
--- a/content/svg/content/src/SVGFETurbulenceElement.h
+++ b/content/svg/content/src/SVGFETurbulenceElement.h
@@ -33,16 +33,17 @@ protected:
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
 public:
   virtual bool SubregionIsUnionOfRegions() MOZ_OVERRIDE { return false; }
 
   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 nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -81,16 +81,30 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGFEB
 // Implementation
 
 void
 nsSVGFE::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
 {
 }
 
 bool
+nsSVGFE::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
+                         nsIPrincipal* aReferencePrincipal)
+{
+  // This is the default implementation for OutputIsTainted.
+  // Our output is tainted if we have at least one tainted input.
+  for (uint32_t i = 0; i < aInputsAreTainted.Length(); i++) {
+    if (aInputsAreTainted[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool
 nsSVGFE::AttributeAffectsRendering(int32_t aNameSpaceID,
                                    nsIAtom* aAttribute) const
 {
   return aNameSpaceID == kNameSpaceID_None &&
          (aAttribute == nsGkAtoms::x ||
           aAttribute == nsGkAtoms::y ||
           aAttribute == nsGkAtoms::width ||
           aAttribute == nsGkAtoms::height ||
--- a/content/svg/content/src/nsSVGFilters.h
+++ b/content/svg/content/src/nsSVGFilters.h
@@ -91,23 +91,31 @@ public:
   virtual nsSVGString& GetResultImageName() = 0;
   // Return a list of all image names used as sources. Default is to
   // return no sources.
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources);
 
   virtual FilterPrimitiveDescription
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
+                            const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<mozilla::RefPtr<SourceSurface>>& aInputImages) = 0;
 
   // returns true if changes to the attribute should cause us to
   // repaint the filter
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const;
 
+  // Return whether this filter primitive has tainted output. A filter's
+  // output is tainted if it depends on things that the web page is not
+  // allowed to read from, e.g. the source graphic or cross-origin images.
+  // aReferencePrincipal is the node principal of the filtered frame's element.
+  virtual bool OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
+                               nsIPrincipal* aReferencePrincipal);
+
   static nsIntRect GetMaxRect() {
     // Try to avoid overflow errors dealing with this rect. It will
     // be intersected with some other reasonable-sized rect eventually.
     return nsIntRect(INT32_MIN/2, INT32_MIN/2, INT32_MAX, INT32_MAX);
   }
 
   operator nsISupports*() { return static_cast<nsIContent*>(this); }
 
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -1466,39 +1466,42 @@ FilterSupport::ComputeSourceNeededRegion
   aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
                                  ThebesIntRect(aFilter.mFilterSpaceBounds));
 }
 
 // FilterPrimitiveDescription
 
 FilterPrimitiveDescription::FilterPrimitiveDescription(PrimitiveType aType)
  : mType(aType)
+ , mIsTainted(false)
 {
 }
 
 FilterPrimitiveDescription::FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther)
  : mType(aOther.mType)
  , mAttributes(aOther.mAttributes)
  , mInputPrimitives(aOther.mInputPrimitives)
  , mFilterPrimitiveSubregion(aOther.mFilterPrimitiveSubregion)
  , mInputColorSpaces(aOther.mInputColorSpaces)
  , mOutputColorSpace(aOther.mOutputColorSpace)
+ , mIsTainted(aOther.mIsTainted)
 {
 }
 
 FilterPrimitiveDescription&
 FilterPrimitiveDescription::operator=(const FilterPrimitiveDescription& aOther)
 {
   if (this != &aOther) {
     mType = aOther.mType;
     mAttributes = aOther.mAttributes;
     mInputPrimitives = aOther.mInputPrimitives;
     mFilterPrimitiveSubregion = aOther.mFilterPrimitiveSubregion;
     mInputColorSpaces = aOther.mInputColorSpaces;
     mOutputColorSpace = aOther.mOutputColorSpace;
+    mIsTainted = aOther.mIsTainted;
   }
   return *this;
 }
 
 // AttributeMap
 
 // A class that wraps different types for easy storage in a hashtable. Only
 // used by AttributeMap.
--- a/gfx/src/FilterSupport.h
+++ b/gfx/src/FilterSupport.h
@@ -245,16 +245,17 @@ public:
   FilterPrimitiveDescription(const FilterPrimitiveDescription& aOther);
   FilterPrimitiveDescription& operator=(const FilterPrimitiveDescription& aOther);
 
   PrimitiveType Type() const { return mType; }
   const AttributeMap& Attributes() const { return mAttributes; }
   AttributeMap& Attributes() { return mAttributes; }
 
   IntRect PrimitiveSubregion() const { return mFilterPrimitiveSubregion; }
+  bool IsTainted() const { return mIsTainted; }
 
   size_t NumberOfInputs() const { return mInputPrimitives.Length(); }
   int32_t InputPrimitiveIndex(size_t aInputIndex) const
   {
     return aInputIndex < mInputPrimitives.Length() ?
       mInputPrimitives[aInputIndex] : 0;
   }
 
@@ -266,16 +267,21 @@ public:
 
   ColorSpace OutputColorSpace() const { return mOutputColorSpace; }
 
   void SetPrimitiveSubregion(const IntRect& aRect)
   {
     mFilterPrimitiveSubregion = aRect;
   }
 
+  void SetIsTainted(bool aIsTainted)
+  {
+    mIsTainted = aIsTainted;
+  }
+
   void SetInputPrimitive(size_t aInputIndex, int32_t aInputPrimitiveIndex)
   {
     mInputPrimitives.EnsureLengthAtLeast(aInputIndex + 1);
     mInputPrimitives[aInputIndex] = aInputPrimitiveIndex;
   }
 
   void SetInputColorSpace(size_t aInputIndex, ColorSpace aColorSpace)
   {
@@ -290,16 +296,17 @@ public:
 
 private:
   PrimitiveType mType;
   AttributeMap mAttributes;
   nsTArray<int32_t> mInputPrimitives;
   IntRect mFilterPrimitiveSubregion;
   nsTArray<ColorSpace> mInputColorSpaces;
   ColorSpace mOutputColorSpace;
+  bool mIsTainted;
 };
 
 /**
  * A data structure that contains one or more FilterPrimitiveDescriptions.
  * Designed to be serializable via IPDL, so it must not contain complex
  * functionality.
  */
 struct FilterDescription MOZ_FINAL {
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-1.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+
+<filter id="f1" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
+         x="0" y="0" width="1" height="1">
+  <feFlood flood-color="#00ff00" result="flood"/>
+  <feDisplacementMap x="10%" y="10%" width="80%" height="80%" style="color-interpolation-filters:sRGB"
+   in2="SourceGraphic" in="flood" scale="1" xChannelSelector="R" yChannelSelector="G"/>
+</filter>
+<g filter="url(#f1)">
+  <rect x="0" y="0" width="100" height="100" fill="#ff0000"/>
+</g>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-2.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<filter id="f1" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
+         x="0" y="0" width="1" height="1">
+  <feImage xlink:href="http://example.com/tests/layout/generic/test/file_taintedfilters_red-flood-for-feImage.svg" result="flood"/>
+  <feDisplacementMap x="10%" y="10%" width="80%" height="80%" style="color-interpolation-filters:sRGB"
+   in="SourceGraphic" in2="flood" scale="1" xChannelSelector="R" yChannelSelector="G"/>
+</filter>
+<g filter="url(#f1)">
+  <rect x="0" y="0" width="100" height="100" fill="#00ff00"/>
+</g>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-3.svg
@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<filter id="f1" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
+         x="0" y="0" width="1" height="1">
+  <feImage xlink:href="file_taintedfilters_red-flood-for-feImage.svg" result="flood"/>
+  <feMerge result="map">
+    <feMergeNode in="SourceGraphic"/>
+    <feMergeNode in="flood"/>
+  </feMerge>
+  <feDisplacementMap x="10%" y="10%" width="80%" height="80%" style="color-interpolation-filters:sRGB"
+   in="SourceGraphic" in2="map" scale="1" xChannelSelector="R" yChannelSelector="G"/>
+</filter>
+<g filter="url(#f1)">
+  <rect x="0" y="0" width="100" height="100" fill="#00ff00"/>
+</g>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_feDisplacementMap-tainted-ref.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+
+<rect x="10" y="10" width="80" height="80" fill="#00ff00"/>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_feDisplacementMap-untainted-1.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<filter id="f1" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
+         x="0" y="0" width="1" height="1">
+  <feImage xlink:href="file_taintedfilters_red-flood-for-feImage.svg" result="flood"/>
+  <feDisplacementMap x="10%" y="10%" width="80%" height="80%" style="color-interpolation-filters:sRGB"
+   in="SourceGraphic" in2="flood" scale="1" xChannelSelector="R" yChannelSelector="G"/>
+</filter>
+<g filter="url(#f1)">
+  <rect x="0" y="0" width="100" height="100" fill="#00ff00"/>
+</g>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_feDisplacementMap-untainted-2.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<filter id="f1" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" 
+         x="0" y="0" width="1" height="1">
+  <feImage xlink:href="http://example.com/tests/layout/generic/test/file_taintedfilters_red-flood-for-feImage-cors.svg" result="flood"/>
+  <feDisplacementMap x="10%" y="10%" width="80%" height="80%" style="color-interpolation-filters:sRGB"
+   in="SourceGraphic" in2="flood" scale="1" xChannelSelector="R" yChannelSelector="G"/>
+</filter>
+<g filter="url(#f1)">
+  <rect x="0" y="0" width="100" height="100" fill="#00ff00"/>
+</g>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_feDisplacementMap-untainted-ref.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+
+<rect x="10" y="50" width="40" height="40" fill="#00ff00"/>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_red-flood-for-feImage-cors.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+
+<rect x="0" y="0" width="100" height="100" fill="#ff0000"/>
+
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_red-flood-for-feImage-cors.svg^headers^
@@ -0,0 +1,4 @@
+Access-Control-Allow-Origin: http://mochi.test:8888
+Access-Control-Allow-Credentials: true
+Content-Type: image/svg+xml
+Cache-Control: no-cache, must-revalidate
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/file_taintedfilters_red-flood-for-feImage.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+
+<rect x="0" y="0" width="100" height="100" fill="#ff0000"/>
+
+</svg>
--- a/layout/generic/test/mochitest.ini
+++ b/layout/generic/test/mochitest.ini
@@ -97,8 +97,10 @@ support-files = page_scroll_with_fixed_p
 [test_plugin_clipping_table.xhtml]
 [test_plugin_focus.html]
 [test_plugin_mouse_coords.html]
 [test_plugin_position.xhtml]
 [test_selection_expanding.html]
 support-files = selection_expanding_xbl.xml
 [test_selection_splitText-normalize.html]
 [test_selection_touchevents.html]
+[test_taintedfilters.html]
+support-files = file_taintedfilters_feDisplacementMap-tainted-1.svg file_taintedfilters_feDisplacementMap-tainted-2.svg file_taintedfilters_feDisplacementMap-tainted-3.svg file_taintedfilters_feDisplacementMap-tainted-ref.svg file_taintedfilters_feDisplacementMap-untainted-ref.svg file_taintedfilters_feDisplacementMap-untainted-1.svg file_taintedfilters_feDisplacementMap-untainted-2.svg file_taintedfilters_red-flood-for-feImage-cors.svg file_taintedfilters_red-flood-for-feImage-cors.svg^headers^ file_taintedfilters_red-flood-for-feImage.svg
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/test_taintedfilters.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=941887
+-->
+<head>
+  <title>Test for Bug 941887</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+    iframe {
+      width: 500px;
+      height: 300px;
+    }
+  </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=941887">Mozilla Bug 941887</a>
+<p id="display"></p>
+<div id="content">
+<iframe id="f1"></iframe>
+<iframe id="f2"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 941887 **/
+SimpleTest.waitForExplicitFinish();
+
+var f = [document.getElementById("f1"), document.getElementById("f2")];
+
+var testList = [
+  ["file_taintedfilters_feDisplacementMap-untainted-1.svg", "file_taintedfilters_feDisplacementMap-untainted-ref.svg"],
+
+  // Disabled until CORS for feImage is implemented.
+  // ["file_taintedfilters_feDisplacementMap-untainted-2.svg", "file_taintedfilters_feDisplacementMap-untainted-ref.svg"],
+
+  ["file_taintedfilters_feDisplacementMap-tainted-1.svg", "file_taintedfilters_feDisplacementMap-tainted-ref.svg"],
+  ["file_taintedfilters_feDisplacementMap-tainted-2.svg", "file_taintedfilters_feDisplacementMap-tainted-ref.svg"],
+  ["file_taintedfilters_feDisplacementMap-tainted-3.svg", "file_taintedfilters_feDisplacementMap-tainted-ref.svg"],
+];
+
+var currentTestIndex = 0;
+var currentTest = testList[0];
+var loaded = [false, false];
+
+function didLoadIframe(iframe, index) {
+  if (iframe.contentWindow.location.href == iframe.src) {
+    loaded[index] = true;
+    if (loaded[0] && loaded[1]) {
+      checkCurrentTest();
+    }
+  }
+}
+
+f[0].onload = function (e) { didLoadIframe(e.target, 0); }
+f[1].onload = function (e) { didLoadIframe(e.target, 1); }
+
+function loadCurrentTest() {
+  currentTest = testList[currentTestIndex];
+  f[0].contentWindow.stop();
+  f[0].src = currentTest[0];
+  f[1].contentWindow.stop();
+  f[1].src = currentTest[1];
+  loaded = [false, false];
+}
+
+function okEqualSnapshots(c1, c2, msg) {
+  var [correct, c1url, c2url] = compareSnapshots(c1, c2, true);
+  if (correct) {
+    ok(true, msg);
+  } else {
+    ok(false, msg + "\nTEST: " + c1url + "\nREFERENCE: " + c1url);
+  }
+}
+
+function checkCurrentTest() {
+  okEqualSnapshots(snapshotWindow(f[0].contentWindow),
+                   snapshotWindow(f[1].contentWindow),
+                   currentTest[0] + " and " + currentTest[1] + " should match.");
+
+  currentTestIndex++;
+
+  if (currentTestIndex < testList.length)
+    loadCurrentTest();
+  else
+    SimpleTest.finish();
+}
+
+loadCurrentTest();
+
+</script>
+</pre>
+</body>
+</html>
--- a/layout/svg/nsSVGFilterInstance.cpp
+++ b/layout/svg/nsSVGFilterInstance.cpp
@@ -131,16 +131,31 @@ nsSVGFilterInstance::ComputeFilterPrimit
   // We currently require filter primitive subregions to be pixel-aligned.
   // Following the spec, any pixel partially in the region is included
   // in the region.
   region.RoundOut();
 
   return RoundedToInt(region);
 }
 
+void
+nsSVGFilterInstance::GetInputsAreTainted(const nsTArray<int32_t>& aInputIndices,
+                                         nsTArray<bool>& aOutInputsAreTainted)
+{
+  for (uint32_t i = 0; i < aInputIndices.Length(); i++) {
+    int32_t inputIndex = aInputIndices[i];
+    if (inputIndex < 0) {
+      // SourceGraphic, SourceAlpha, FillPaint and StrokePaint are tainted.
+      aOutInputsAreTainted.AppendElement(true);
+    } else {
+      aOutInputsAreTainted.AppendElement(mPrimitiveDescriptions[inputIndex].IsTainted());
+    }
+  }
+}
+
 static nsresult
 GetSourceIndices(nsSVGFE* aFilterElement,
                  int32_t aCurrentIndex,
                  const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
                  nsTArray<int32_t>& aSourceIndices)
 {
   nsAutoTArray<nsSVGStringInfo,2> sources;
   aFilterElement->GetSourceImageNames(sources);
@@ -189,31 +204,38 @@ nsSVGFilterInstance::BuildPrimitives()
     if (primitive) {
       primitives.AppendElement(primitive);
     }
   }
 
   // Maps source image name to source index.
   nsDataHashtable<nsStringHashKey, int32_t> imageTable(10);
 
+  // The principal that we check principals of any loaded images against.
+  nsCOMPtr<nsIPrincipal> principal = mTargetFrame->GetContent()->NodePrincipal();
+
   for (uint32_t i = 0; i < primitives.Length(); ++i) {
     nsSVGFE* filter = primitives[i];
 
     nsAutoTArray<int32_t,2> sourceIndices;
     nsresult rv = GetSourceIndices(filter, i, imageTable, sourceIndices);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     IntRect primitiveSubregion =
       ComputeFilterPrimitiveSubregion(filter, sourceIndices);
 
+    nsTArray<bool> sourcesAreTainted;
+    GetInputsAreTainted(sourceIndices, sourcesAreTainted);
+
     FilterPrimitiveDescription descr =
-      filter->GetPrimitiveDescription(this, primitiveSubregion, mInputImages);
+      filter->GetPrimitiveDescription(this, primitiveSubregion, sourcesAreTainted, mInputImages);
 
+    descr.SetIsTainted(filter->OutputIsTainted(sourcesAreTainted, principal));
     descr.SetPrimitiveSubregion(primitiveSubregion);
 
     for (uint32_t j = 0; j < sourceIndices.Length(); j++) {
       int32_t inputIndex = sourceIndices[j];
       descr.SetInputPrimitive(j, inputIndex);
       ColorSpace inputColorSpace =
         inputIndex < 0 ? SRGB : mPrimitiveDescriptions[inputIndex].OutputColorSpace();
       ColorSpace desiredInputColorSpace = filter->GetInputColorSpace(j, inputColorSpace);
--- a/layout/svg/nsSVGFilterInstance.h
+++ b/layout/svg/nsSVGFilterInstance.h
@@ -267,16 +267,23 @@ private:
 
   /**
    * Computes the filter primitive subregion for the given primitive.
    */
   IntRect ComputeFilterPrimitiveSubregion(nsSVGFE* aFilterElement,
                                           const nsTArray<int32_t>& aInputIndices);
 
   /**
+   * Takes the input indices of a filter primitive and returns for each input
+   * whether the input's output is tainted.
+   */
+  void GetInputsAreTainted(const nsTArray<int32_t>& aInputIndices,
+                           nsTArray<bool>& aOutInputsAreTainted);
+
+  /**
    * Scales a numeric filter primitive length in the X, Y or "XY" directions
    * into a length in filter space (no offset is applied).
    */
   float GetPrimitiveNumber(uint8_t aCtxType, float aValue) const;
 
   gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const;
 
   /**