diff --git a/content/svg/content/src/SVGFEDropShadowElement.cpp b/content/svg/content/src/SVGFEDropShadowElement.cpp new file mode 100644 index 000000000000..f6448858275f --- /dev/null +++ b/content/svg/content/src/SVGFEDropShadowElement.cpp @@ -0,0 +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/SVGFEDropShadowElement.h" +#include "mozilla/dom/SVGFEDropShadowElementBinding.h" +#include "nsSVGFilterInstance.h" + +NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEDropShadow) + +using namespace mozilla::gfx; + +namespace mozilla { +namespace dom { + +JSObject* +SVGFEDropShadowElement::WrapNode(JSContext* aCx, JS::Handle aScope) +{ + return SVGFEDropShadowElementBinding::Wrap(aCx, aScope, this); +} + +nsSVGElement::NumberInfo SVGFEDropShadowElement::sNumberInfo[2] = +{ + { &nsGkAtoms::dx, 2, false }, + { &nsGkAtoms::dy, 2, false } +}; + +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(SVGFEDropShadowElement) + +//---------------------------------------------------------------------- + +already_AddRefed +SVGFEDropShadowElement::In1() +{ + return mStringAttributes[IN1].ToDOMAnimatedString(this); +} + +already_AddRefed +SVGFEDropShadowElement::Dx() +{ + return mNumberAttributes[DX].ToDOMAnimatedNumber(this); +} + +already_AddRefed +SVGFEDropShadowElement::Dy() +{ + return mNumberAttributes[DY].ToDOMAnimatedNumber(this); +} + +already_AddRefed +SVGFEDropShadowElement::StdDeviationX() +{ + return mNumberPairAttributes[STD_DEV].ToDOMAnimatedNumber(nsSVGNumberPair::eFirst, this); +} + +already_AddRefed +SVGFEDropShadowElement::StdDeviationY() +{ + return mNumberPairAttributes[STD_DEV].ToDOMAnimatedNumber(nsSVGNumberPair::eSecond, this); +} + +void +SVGFEDropShadowElement::SetStdDeviation(float stdDeviationX, float stdDeviationY) +{ + mNumberPairAttributes[STD_DEV].SetBaseValues(stdDeviationX, stdDeviationY, this); +} + +FilterPrimitiveDescription +SVGFEDropShadowElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance, + const IntRect& aFilterSubregion, + const nsTArray& aInputsAreTainted, + nsTArray>& 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); + } + + 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 +SVGFEDropShadowElement::AttributeAffectsRendering(int32_t aNameSpaceID, + nsIAtom* aAttribute) const +{ + return SVGFEDropShadowElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) || + (aNameSpaceID == kNameSpaceID_None && + (aAttribute == nsGkAtoms::in || + aAttribute == nsGkAtoms::stdDeviation || + aAttribute == nsGkAtoms::dx || + aAttribute == nsGkAtoms::dy)); +} + +void +SVGFEDropShadowElement::GetSourceImageNames(nsTArray& 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 +SVGFEDropShadowElement::GetNumberPairInfo() +{ + return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo, + ArrayLength(sNumberPairInfo)); +} + +nsSVGElement::StringAttributesInfo +SVGFEDropShadowElement::GetStringInfo() +{ + return StringAttributesInfo(mStringAttributes, sStringInfo, + ArrayLength(sStringInfo)); +} + +} // namespace dom +} // namespace mozilla diff --git a/content/svg/content/src/SVGFEDropShadowElement.h b/content/svg/content/src/SVGFEDropShadowElement.h new file mode 100644 index 000000000000..c6913958a677 --- /dev/null +++ b/content/svg/content/src/SVGFEDropShadowElement.h @@ -0,0 +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_SVGFEDropShadowElement_h +#define mozilla_dom_SVGFEDropShadowElement_h + +#include "nsSVGFilters.h" +#include "nsSVGNumber2.h" +#include "nsSVGNumberPair.h" +#include "nsSVGString.h" + +nsresult NS_NewSVGFEDropShadowElement(nsIContent **aResult, + already_AddRefed aNodeInfo); + +namespace mozilla { +namespace dom { + +typedef nsSVGFE SVGFEDropShadowElementBase; + +class SVGFEDropShadowElement : public SVGFEDropShadowElementBase +{ + friend nsresult (::NS_NewSVGFEDropShadowElement(nsIContent **aResult, + already_AddRefed aNodeInfo)); +protected: + SVGFEDropShadowElement(already_AddRefed aNodeInfo) + : SVGFEDropShadowElementBase(aNodeInfo) + { + } + virtual JSObject* WrapNode(JSContext* aCx, + JS::Handle aScope) MOZ_OVERRIDE; + +public: + virtual FilterPrimitiveDescription + GetPrimitiveDescription(nsSVGFilterInstance* aInstance, + const IntRect& aFilterSubregion, + const nsTArray& aInputsAreTainted, + nsTArray>& 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& 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 In1(); + already_AddRefed Dx(); + already_AddRefed Dy(); + already_AddRefed StdDeviationX(); + already_AddRefed 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_SVGFEDropShadowElement_h diff --git a/content/svg/content/src/SVGFEGaussianBlurElement.cpp b/content/svg/content/src/SVGFEGaussianBlurElement.cpp index 9430f9f09418..7deefb5eb6b0 100644 --- a/content/svg/content/src/SVGFEGaussianBlurElement.cpp +++ b/content/svg/content/src/SVGFEGaussianBlurElement.cpp @@ -63,8 +63,6 @@ SVGFEGaussianBlurElement::SetStdDeviation(float stdDeviationX, float stdDeviatio mNumberPairAttributes[STD_DEV].SetBaseValues(stdDeviationX, stdDeviationY, this); } -static const float kMaxStdDeviation = 500; - FilterPrimitiveDescription SVGFEGaussianBlurElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance, const IntRect& aFilterSubregion, @@ -81,8 +79,6 @@ SVGFEGaussianBlurElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance 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; diff --git a/content/svg/content/src/moz.build b/content/svg/content/src/moz.build index 5d98a1de8cd0..e47fbe92ee87 100644 --- a/content/svg/content/src/moz.build +++ b/content/svg/content/src/moz.build @@ -45,6 +45,7 @@ EXPORTS.mozilla.dom += [ 'SVGFEDiffuseLightingElement.h', 'SVGFEDisplacementMapElement.h', 'SVGFEDistantLightElement.h', + 'SVGFEDropShadowElement.h', 'SVGFEFloodElement.h', 'SVGFEGaussianBlurElement.h', 'SVGFEImageElement.h', diff --git a/dom/webidl/SVGFEDropShadowElement.webidl b/dom/webidl/SVGFEDropShadowElement.webidl new file mode 100644 index 000000000000..becce186bbdf --- /dev/null +++ b/dom/webidl/SVGFEDropShadowElement.webidl @@ -0,0 +1,23 @@ +/* -*- Mode: IDL; 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/. + * + * 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 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); +}; + +SVGFEDropShadowElement implements SVGFilterPrimitiveStandardAttributes; diff --git a/gfx/src/FilterSupport.cpp b/gfx/src/FilterSupport.cpp index 9026b186817b..8dd3e9ae5171 100644 --- a/gfx/src/FilterSupport.cpp +++ b/gfx/src/FilterSupport.cpp @@ -95,6 +95,8 @@ namespace gfx { // Some convenience FilterNode creation functions. +static const float kMaxStdDeviation = 500; + namespace FilterWrappers { static TemporaryRef @@ -161,6 +163,28 @@ namespace FilterWrappers { return filter; } + static TemporaryRef + 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 filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR); + filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX); + filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter); + return filter; + } + RefPtr filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR); + RefPtr 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 Clear(DrawTarget* aDT) { @@ -815,22 +839,37 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio case FilterPrimitiveDescription::eGaussianBlur: { - Size stdDeviation = atts.GetSize(eGaussianBlurStdDeviation); - if (stdDeviation.width == stdDeviation.height) { - RefPtr 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 alpha = FilterWrappers::ToAlpha(aDT, aSources[0]); + RefPtr blur = FilterWrappers::GaussianBlur(aDT, alpha, + atts.GetSize(eDropShadowStdDeviation)); + RefPtr offsetBlur = FilterWrappers::Offset(aDT, blur, + atts.GetIntPoint(eDropShadowOffset)); + RefPtr 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 filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR); - RefPtr 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 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 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: @@ -1127,11 +1166,9 @@ UnionOfRegions(const nsTArray& aRegions) } 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)); } @@ -1200,6 +1237,18 @@ ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription, 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: { @@ -1418,6 +1467,19 @@ SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription, 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: { diff --git a/gfx/src/FilterSupport.h b/gfx/src/FilterSupport.h index d2e1fa1537fd..e28e6e9fcbb6 100644 --- a/gfx/src/FilterSupport.h +++ b/gfx/src/FilterSupport.h @@ -100,6 +100,9 @@ enum AttributeName { eConvolveMatrixKernelUnitLength, eConvolveMatrixPreserveAlpha, eOffsetOffset, + eDropShadowStdDeviation, + eDropShadowOffset, + eDropShadowColor, eDisplacementMapScale, eDisplacementMapXChannel, eDisplacementMapYChannel, @@ -231,6 +234,7 @@ public: eMerge, eImage, eGaussianBlur, + eDropShadow, eDiffuseLighting, eSpecularLighting }; diff --git a/layout/reftests/svg/filters/feDropShadow-01-ref.svg b/layout/reftests/svg/filters/feDropShadow-01-ref.svg new file mode 100644 index 000000000000..91da41bbbe14 --- /dev/null +++ b/layout/reftests/svg/filters/feDropShadow-01-ref.svg @@ -0,0 +1,68 @@ + + + + Reference for Filter Effects Module Level 1 feDropShadow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/filters/feDropShadow-01.svg b/layout/reftests/svg/filters/feDropShadow-01.svg new file mode 100644 index 000000000000..ce32e053dfa8 --- /dev/null +++ b/layout/reftests/svg/filters/feDropShadow-01.svg @@ -0,0 +1,43 @@ + + + + Testcase for Filter Effects Module Level 1 feDropShadow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +