diff --git a/layout/reftests/svg/filters/css-filters/drop-shadow-default-color-ref.html b/layout/reftests/svg/filters/css-filters/drop-shadow-default-color-ref.html
new file mode 100644
index 000000000000..2fe89507c504
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-default-color-ref.html
@@ -0,0 +1,28 @@
+
+
+
+
+ CSS Filters: Drop Shadow Default Color
+
+
+
+
+ You should see a blue square with a green drop shadow.
+
+
+
+
diff --git a/layout/reftests/svg/filters/css-filters/drop-shadow-default-color.html b/layout/reftests/svg/filters/css-filters/drop-shadow-default-color.html
new file mode 100644
index 000000000000..ac9f8ecb122d
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-default-color.html
@@ -0,0 +1,31 @@
+
+
+
+
+ CSS Filters: Drop Shadow Default Color
+
+
+
+
+
+
+
+
+ You should see a blue square with a green drop shadow.
+
+
+
diff --git a/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset-ref.html b/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset-ref.html
new file mode 100644
index 000000000000..bf04c1d511fa
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset-ref.html
@@ -0,0 +1,31 @@
+
+
+
+
+CSS Filters: Negative Drop Shadow Offset
+
+
+
+
+ You should see a blue square with a green drop shadow in its top left corner.
+
+
+
+
diff --git a/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset.html b/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset.html
new file mode 100644
index 000000000000..79b301daba38
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset.html
@@ -0,0 +1,32 @@
+
+
+
+
+ CSS Filters: Negative Drop Shadow Offset
+
+
+
+
+
+
+
+ You should see a blue square with a green drop shadow in its top left corner.
+
+
+
diff --git a/layout/reftests/svg/filters/css-filters/drop-shadow-ref.html b/layout/reftests/svg/filters/css-filters/drop-shadow-ref.html
new file mode 100644
index 000000000000..211fbfbc4339
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-ref.html
@@ -0,0 +1,28 @@
+
+
+
+
+ CSS Filters: Drop Shadow on HTML Element
+
+
+
+
+ You should see a blue square with a green drop shadow.
+
+
+
+
diff --git a/layout/reftests/svg/filters/css-filters/drop-shadow.html b/layout/reftests/svg/filters/css-filters/drop-shadow.html
new file mode 100644
index 000000000000..1e4673465193
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow.html
@@ -0,0 +1,28 @@
+
+
+
+
+ CSS Filters: Drop Shadow on HTML Element
+
+
+
+
+
+
+
+ You should see a blue square with a green drop shadow.
+
+
+
diff --git a/layout/reftests/svg/filters/css-filters/reftest.list b/layout/reftests/svg/filters/css-filters/reftest.list
index 9226de0bed69..ca0e0385e437 100644
--- a/layout/reftests/svg/filters/css-filters/reftest.list
+++ b/layout/reftests/svg/filters/css-filters/reftest.list
@@ -7,3 +7,6 @@ default-preferences pref(layout.css.filters.enabled,true)
== blur.svg blur-ref.svg
== blur-zero-radius.html blur-zero-radius-ref.html
== blur-zoomed-page.html blur-zoomed-page-ref.html
+== drop-shadow.html drop-shadow-ref.html
+== drop-shadow-default-color.html drop-shadow-default-color-ref.html
+== drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
diff --git a/layout/svg/nsCSSFilterInstance.cpp b/layout/svg/nsCSSFilterInstance.cpp
index d4591ed71afc..94a6bae95dce 100644
--- a/layout/svg/nsCSSFilterInstance.cpp
+++ b/layout/svg/nsCSSFilterInstance.cpp
@@ -9,6 +9,7 @@
// Keep others in (case-insensitive) order:
#include "gfx2DGlue.h"
#include "gfxUtils.h"
+#include "nsIFrame.h"
#include "nsStyleStruct.h"
#include "nsTArray.h"
@@ -16,9 +17,11 @@ using namespace mozilla;
using namespace mozilla::gfx;
nsCSSFilterInstance::nsCSSFilterInstance(const nsStyleFilter& aFilter,
+ nsIFrame *aTargetFrame,
const nsIntRect& aTargetBBoxInFilterSpace,
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
: mFilter(aFilter)
+ , mTargetFrame(aTargetFrame)
, mTargetBBoxInFilterSpace(aTargetBBoxInFilterSpace)
, mFrameSpaceInCSSPxToFilterSpaceTransform(aFrameSpaceInCSSPxToFilterSpaceTransform)
{
@@ -38,6 +41,9 @@ nsCSSFilterInstance::BuildPrimitives(nsTArray& aPrim
case NS_STYLE_FILTER_BRIGHTNESS:
case NS_STYLE_FILTER_CONTRAST:
case NS_STYLE_FILTER_DROP_SHADOW:
+ descr = CreatePrimitiveDescription(PrimitiveType::DropShadow, aPrimitiveDescrs);
+ result = SetAttributesForDropShadow(descr);
+ break;
case NS_STYLE_FILTER_GRAYSCALE:
case NS_STYLE_FILTER_HUE_ROTATE:
case NS_STYLE_FILTER_INVERT:
@@ -78,17 +84,49 @@ nsCSSFilterInstance::CreatePrimitiveDescription(PrimitiveType aType,
nsresult
nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
{
- // Get the radius from the style.
- nsStyleCoord radiusStyleCoord = mFilter.GetFilterParameter();
- if (radiusStyleCoord.GetUnit() != eStyleUnit_Coord) {
+ const nsStyleCoord& radiusInFrameSpace = mFilter.GetFilterParameter();
+ if (radiusInFrameSpace.GetUnit() != eStyleUnit_Coord) {
NS_NOTREACHED("unexpected unit");
return NS_ERROR_FAILURE;
}
- // Get the radius in frame space.
- nscoord radiusInFrameSpace = radiusStyleCoord.GetCoordValue();
+ Size radiusInFilterSpace = BlurRadiusToFilterSpace(radiusInFrameSpace.GetCoordValue());
+ aDescr.Attributes().Set(eGaussianBlurStdDeviation, radiusInFilterSpace);
+ return NS_OK;
+}
+
+nsresult
+nsCSSFilterInstance::SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr)
+{
+ nsCSSShadowArray* shadows = mFilter.GetDropShadow();
+ if (!shadows || shadows->Length() != 1) {
+ NS_NOTREACHED("Exactly one drop shadow should have been parsed.");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCSSShadowItem* shadow = shadows->ShadowAt(0);
+
+ // Set drop shadow blur radius.
+ Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow->mRadius);
+ aDescr.Attributes().Set(eDropShadowStdDeviation, radiusInFilterSpace);
+
+ // Set offset.
+ IntPoint offsetInFilterSpace = OffsetToFilterSpace(shadow->mXOffset, shadow->mYOffset);
+ aDescr.Attributes().Set(eDropShadowOffset, offsetInFilterSpace);
+
+ // Set color. If unspecified, use the CSS color property.
+ nscolor shadowColor = shadow->mHasColor ?
+ shadow->mColor : mTargetFrame->StyleColor()->mColor;
+ aDescr.Attributes().Set(eDropShadowColor, ToAttributeColor(shadowColor));
+
+ return NS_OK;
+}
+
+Size
+nsCSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace)
+{
float radiusInFrameSpaceInCSSPx =
- nsPresContext::AppUnitsToFloatCSSPixels(radiusInFrameSpace);
+ nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace);
// Convert the radius to filter space.
gfxSize radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
@@ -101,15 +139,40 @@ nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
// Check the radius limits.
if (radiusInFilterSpace.width < 0 || radiusInFilterSpace.height < 0) {
NS_NOTREACHED("we shouldn't have parsed a negative radius in the style");
- return NS_ERROR_FAILURE;
+ return Size();
}
gfxFloat maxStdDeviation = (gfxFloat)kMaxStdDeviation;
radiusInFilterSpace.width = std::min(radiusInFilterSpace.width, maxStdDeviation);
radiusInFilterSpace.height = std::min(radiusInFilterSpace.height, maxStdDeviation);
- // Set the radius parameter.
- aDescr.Attributes().Set(eGaussianBlurStdDeviation, ToSize(radiusInFilterSpace));
- return NS_OK;
+ return ToSize(radiusInFilterSpace);
+}
+
+IntPoint
+nsCSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
+ nscoord aYOffsetInFrameSpace)
+{
+ gfxPoint offsetInFilterSpace(nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace),
+ nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace));
+
+ // Convert the radius to filter space.
+ gfxSize frameSpaceInCSSPxToFilterSpaceScale =
+ mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors(true);
+ offsetInFilterSpace.x *= frameSpaceInCSSPxToFilterSpaceScale.width;
+ offsetInFilterSpace.y *= frameSpaceInCSSPxToFilterSpaceScale.height;
+
+ return IntPoint(int32_t(offsetInFilterSpace.x), int32_t(offsetInFilterSpace.y));
+}
+
+Color
+nsCSSFilterInstance::ToAttributeColor(nscolor aColor)
+{
+ return Color(
+ NS_GET_R(aColor) / 255.0,
+ NS_GET_G(aColor) / 255.0,
+ NS_GET_B(aColor) / 255.0,
+ NS_GET_A(aColor) / 255.0
+ );
}
int32_t
diff --git a/layout/svg/nsCSSFilterInstance.h b/layout/svg/nsCSSFilterInstance.h
index 0e1248b6b6bb..3b2250c968cd 100644
--- a/layout/svg/nsCSSFilterInstance.h
+++ b/layout/svg/nsCSSFilterInstance.h
@@ -9,7 +9,11 @@
#include "FilterSupport.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/gfx/Types.h"
+#include "nsColor.h"
+class nsIFrame;
struct nsStyleFilter;
template class nsTArray;
@@ -20,8 +24,11 @@ template class nsTArray;
*/
class nsCSSFilterInstance
{
+ typedef mozilla::gfx::Color Color;
typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
+ typedef mozilla::gfx::IntPoint IntPoint;
typedef mozilla::gfx::PrimitiveType PrimitiveType;
+ typedef mozilla::gfx::Size Size;
public:
/**
@@ -34,6 +41,7 @@ public:
* the filtered element's frame space in CSS pixels to filter space.
*/
nsCSSFilterInstance(const nsStyleFilter& aFilter,
+ nsIFrame *aTargetFrame,
const nsIntRect& mTargetBBoxInFilterSpace,
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform);
@@ -55,6 +63,7 @@ private:
* Sets aDescr's attributes using the style info in mFilter.
*/
nsresult SetAttributesForBlur(FilterPrimitiveDescription& aDescr);
+ nsresult SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr);
/**
* Returns the index of the last result in the aPrimitiveDescrs, which we'll
@@ -71,11 +80,34 @@ private:
void SetBounds(FilterPrimitiveDescription& aDescr,
const nsTArray& aPrimitiveDescrs);
+ /**
+ * Converts an nscolor to a Color, suitable for use as a
+ * FilterPrimitiveDescription attribute.
+ */
+ Color ToAttributeColor(nscolor aColor);
+
+ /**
+ * Converts a blur radius in frame space to filter space.
+ */
+ Size BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace);
+
+ /**
+ * Converts a point defined by a pair of nscoord x, y coordinates from frame
+ * space to filter space.
+ */
+ IntPoint OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
+ nscoord aYOffsetInFrameSpace);
+
/**
* The CSS filter originally from the style system.
*/
const nsStyleFilter& mFilter;
+ /**
+ * The frame for the element that is currently being filtered.
+ */
+ nsIFrame* mTargetFrame;
+
/**
* The bounding box of the element being filtered, in filter space. Used for
* input bounds if this CSS filter is the first in the filter chain.
diff --git a/layout/svg/nsFilterInstance.cpp b/layout/svg/nsFilterInstance.cpp
index 2c94993d3489..a8b696244bf8 100644
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -260,7 +260,8 @@ nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter)
}
// Build primitives for a CSS filter.
- nsCSSFilterInstance cssFilterInstance(aFilter, mTargetBBoxInFilterSpace,
+ nsCSSFilterInstance cssFilterInstance(aFilter, mTargetFrame,
+ mTargetBBoxInFilterSpace,
mFrameSpaceInCSSPxToFilterSpaceTransform);
return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions);
}