Bug 847120: Move SVGFEConvolveMatrixElement to its own file r=Ms2ger

--HG--
rename : content/svg/content/src/nsSVGFilters.cpp => content/svg/content/src/SVGFEConvolveMatrixElement.cpp
rename : content/svg/content/src/nsSVGFilters.cpp => content/svg/content/src/SVGFEConvolveMatrixElement.h
This commit is contained in:
David Zbarsky 2013-03-25 02:26:06 -04:00
Родитель 9e1ac4e648
Коммит 8143ee8716
4 изменённых файлов: 550 добавлений и 521 удалений

Просмотреть файл

@ -81,6 +81,7 @@ CPPSRCS = \
SVGFEColorMatrixElement.cpp \ SVGFEColorMatrixElement.cpp \
SVGFEComponentTransferElement.cpp \ SVGFEComponentTransferElement.cpp \
SVGFECompositeElement.cpp \ SVGFECompositeElement.cpp \
SVGFEConvolveMatrixElement.cpp \
SVGFEDiffuseLightingElement.cpp \ SVGFEDiffuseLightingElement.cpp \
SVGFEDisplacementMapElement.cpp \ SVGFEDisplacementMapElement.cpp \
SVGFEDistantLightElement.cpp \ SVGFEDistantLightElement.cpp \
@ -192,6 +193,7 @@ EXPORTS_mozilla/dom = \
SVGFEColorMatrixElement.h \ SVGFEColorMatrixElement.h \
SVGFEComponentTransferElement.h \ SVGFEComponentTransferElement.h \
SVGFECompositeElement.h \ SVGFECompositeElement.h \
SVGFEConvolveMatrixElement.h \
SVGFEDiffuseLightingElement.h \ SVGFEDiffuseLightingElement.h \
SVGFEDisplacementMapElement.h \ SVGFEDisplacementMapElement.h \
SVGFEDistantLightElement.h \ SVGFEDistantLightElement.h \

Просмотреть файл

@ -0,0 +1,437 @@
/* 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/SVGFEConvolveMatrixElement.h"
namespace mozilla {
namespace dom {
nsSVGElement::NumberInfo nsSVGFEConvolveMatrixElement::sNumberInfo[2] =
{
{ &nsGkAtoms::divisor, 1, false },
{ &nsGkAtoms::bias, 0, false }
};
nsSVGElement::NumberPairInfo nsSVGFEConvolveMatrixElement::sNumberPairInfo[1] =
{
{ &nsGkAtoms::kernelUnitLength, 0, 0 }
};
nsSVGElement::IntegerInfo nsSVGFEConvolveMatrixElement::sIntegerInfo[2] =
{
{ &nsGkAtoms::targetX, 0 },
{ &nsGkAtoms::targetY, 0 }
};
nsSVGElement::IntegerPairInfo nsSVGFEConvolveMatrixElement::sIntegerPairInfo[1] =
{
{ &nsGkAtoms::order, 3, 3 }
};
nsSVGElement::BooleanInfo nsSVGFEConvolveMatrixElement::sBooleanInfo[1] =
{
{ &nsGkAtoms::preserveAlpha, false }
};
nsSVGEnumMapping nsSVGFEConvolveMatrixElement::sEdgeModeMap[] = {
{&nsGkAtoms::duplicate, nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_DUPLICATE},
{&nsGkAtoms::wrap, nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_WRAP},
{&nsGkAtoms::none, nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_NONE},
{nullptr, 0}
};
nsSVGElement::EnumInfo nsSVGFEConvolveMatrixElement::sEnumInfo[1] =
{
{ &nsGkAtoms::edgeMode,
sEdgeModeMap,
nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_DUPLICATE
}
};
nsSVGElement::StringInfo nsSVGFEConvolveMatrixElement::sStringInfo[2] =
{
{ &nsGkAtoms::result, kNameSpaceID_None, true },
{ &nsGkAtoms::in, kNameSpaceID_None, true }
};
nsSVGElement::NumberListInfo nsSVGFEConvolveMatrixElement::sNumberListInfo[1] =
{
{ &nsGkAtoms::kernelMatrix }
};
NS_IMPL_NS_NEW_SVG_ELEMENT(FEConvolveMatrix)
//----------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ADDREF_INHERITED(nsSVGFEConvolveMatrixElement,nsSVGFEConvolveMatrixElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGFEConvolveMatrixElement,nsSVGFEConvolveMatrixElementBase)
DOMCI_NODE_DATA(SVGFEConvolveMatrixElement, nsSVGFEConvolveMatrixElement)
NS_INTERFACE_TABLE_HEAD(nsSVGFEConvolveMatrixElement)
NS_NODE_INTERFACE_TABLE5(nsSVGFEConvolveMatrixElement, nsIDOMNode,
nsIDOMElement, nsIDOMSVGElement,
nsIDOMSVGFilterPrimitiveStandardAttributes,
nsIDOMSVGFEConvolveMatrixElement)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGFEConvolveMatrixElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGFEConvolveMatrixElementBase)
//----------------------------------------------------------------------
// nsIDOMNode methods
NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGFEConvolveMatrixElement)
//----------------------------------------------------------------------
// nsSVGFEConvolveMatrixElement methods
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetIn1(nsIDOMSVGAnimatedString * *aIn)
{
return mStringAttributes[IN1].ToDOMAnimatedString(aIn, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetOrderX(nsIDOMSVGAnimatedInteger * *aOrderX)
{
return mIntegerPairAttributes[ORDER].ToDOMAnimatedInteger(aOrderX, nsSVGIntegerPair::eFirst, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetOrderY(nsIDOMSVGAnimatedInteger * *aOrderY)
{
return mIntegerPairAttributes[ORDER].ToDOMAnimatedInteger(aOrderY, nsSVGIntegerPair::eSecond, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetKernelMatrix(nsISupports * *aKernelMatrix)
{
*aKernelMatrix = DOMSVGAnimatedNumberList::GetDOMWrapper(&mNumberListAttributes[KERNELMATRIX],
this, KERNELMATRIX).get();
return NS_OK;
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetTargetX(nsIDOMSVGAnimatedInteger * *aTargetX)
{
return mIntegerAttributes[TARGET_X].ToDOMAnimatedInteger(aTargetX, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetTargetY(nsIDOMSVGAnimatedInteger * *aTargetY)
{
return mIntegerAttributes[TARGET_Y].ToDOMAnimatedInteger(aTargetY, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetEdgeMode(nsIDOMSVGAnimatedEnumeration * *aEdgeMode)
{
return mEnumAttributes[EDGEMODE].ToDOMAnimatedEnum(aEdgeMode, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetPreserveAlpha(nsISupports * *aPreserveAlpha)
{
return mBooleanAttributes[PRESERVEALPHA].ToDOMAnimatedBoolean(aPreserveAlpha, this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetDivisor(nsIDOMSVGAnimatedNumber **aDivisor)
{
return mNumberAttributes[DIVISOR].ToDOMAnimatedNumber(aDivisor, this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetBias(nsIDOMSVGAnimatedNumber **aBias)
{
return mNumberAttributes[BIAS].ToDOMAnimatedNumber(aBias, this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetKernelUnitLengthX(nsIDOMSVGAnimatedNumber **aKernelX)
{
return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(aKernelX,
nsSVGNumberPair::eFirst,
this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetKernelUnitLengthY(nsIDOMSVGAnimatedNumber **aKernelY)
{
return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(aKernelY,
nsSVGNumberPair::eSecond,
this);
}
void
nsSVGFEConvolveMatrixElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
{
aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
}
nsIntRect
nsSVGFEConvolveMatrixElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance)
{
// XXX A more precise box is possible when 'bias' is zero and 'edgeMode' is
// 'none', but it requires analysis of 'kernelUnitLength', 'order' and
// 'targetX/Y', so it's quite a lot of work. Don't do it for now.
return GetMaxRect();
}
void
nsSVGFEConvolveMatrixElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
{
// XXX Precise results are possible but we're going to skip that work
// for now. Do nothing, which means the needed-box remains the
// source's output bounding box.
}
nsIntRect
nsSVGFEConvolveMatrixElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
// XXX Precise results are possible but we're going to skip that work
// for now.
return GetMaxRect();
}
static int32_t BoundInterval(int32_t aVal, int32_t aMax)
{
aVal = std::max(aVal, 0);
return std::min(aVal, aMax - 1);
}
static int32_t WrapInterval(int32_t aVal, int32_t aMax)
{
aVal = aVal % aMax;
return aVal < 0 ? aMax + aVal : aVal;
}
static void
ConvolvePixel(const uint8_t *aSourceData,
uint8_t *aTargetData,
int32_t aWidth, int32_t aHeight,
int32_t aStride,
int32_t aX, int32_t aY,
uint16_t aEdgeMode,
const float *aKernel,
float aDivisor, float aBias,
bool aPreserveAlpha,
int32_t aOrderX, int32_t aOrderY,
int32_t aTargetX, int32_t aTargetY)
{
float sum[4] = {0, 0, 0, 0};
aBias *= 255;
int32_t offsets[4] = {GFX_ARGB32_OFFSET_R,
GFX_ARGB32_OFFSET_G,
GFX_ARGB32_OFFSET_B,
GFX_ARGB32_OFFSET_A } ;
int32_t channels = aPreserveAlpha ? 3 : 4;
for (int32_t y = 0; y < aOrderY; y++) {
int32_t sampleY = aY + y - aTargetY;
bool overscanY = sampleY < 0 || sampleY >= aHeight;
for (int32_t x = 0; x < aOrderX; x++) {
int32_t sampleX = aX + x - aTargetX;
bool overscanX = sampleX < 0 || sampleX >= aWidth;
for (int32_t i = 0; i < channels; i++) {
if (overscanY || overscanX) {
switch (aEdgeMode) {
case nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_DUPLICATE:
sum[i] +=
aSourceData[BoundInterval(sampleY, aHeight) * aStride +
BoundInterval(sampleX, aWidth) * 4 + offsets[i]] *
aKernel[aOrderX * y + x];
break;
case nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_WRAP:
sum[i] +=
aSourceData[WrapInterval(sampleY, aHeight) * aStride +
WrapInterval(sampleX, aWidth) * 4 + offsets[i]] *
aKernel[aOrderX * y + x];
break;
default:
break;
}
} else {
sum[i] +=
aSourceData[sampleY * aStride + 4 * sampleX + offsets[i]] *
aKernel[aOrderX * y + x];
}
}
}
}
for (int32_t i = 0; i < channels; i++) {
aTargetData[aY * aStride + 4 * aX + offsets[i]] =
BoundInterval(static_cast<int32_t>(sum[i] / aDivisor + aBias), 256);
}
if (aPreserveAlpha) {
aTargetData[aY * aStride + 4 * aX + GFX_ARGB32_OFFSET_A] =
aSourceData[aY * aStride + 4 * aX + GFX_ARGB32_OFFSET_A];
}
}
nsresult
nsSVGFEConvolveMatrixElement::Filter(nsSVGFilterInstance *instance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& rect)
{
const SVGNumberList &kernelMatrix =
mNumberListAttributes[KERNELMATRIX].GetAnimValue();
uint32_t kmLength = kernelMatrix.Length();
int32_t orderX = mIntegerPairAttributes[ORDER].GetAnimValue(nsSVGIntegerPair::eFirst);
int32_t orderY = mIntegerPairAttributes[ORDER].GetAnimValue(nsSVGIntegerPair::eSecond);
if (orderX <= 0 || orderY <= 0 ||
static_cast<uint32_t>(orderX * orderY) != kmLength) {
return NS_ERROR_FAILURE;
}
int32_t targetX, targetY;
GetAnimatedIntegerValues(&targetX, &targetY, nullptr);
if (mIntegerAttributes[TARGET_X].IsExplicitlySet()) {
if (targetX < 0 || targetX >= orderX)
return NS_ERROR_FAILURE;
} else {
targetX = orderX / 2;
}
if (mIntegerAttributes[TARGET_Y].IsExplicitlySet()) {
if (targetY < 0 || targetY >= orderY)
return NS_ERROR_FAILURE;
} else {
targetY = orderY / 2;
}
if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
return NS_ERROR_FAILURE;
nsAutoArrayPtr<float> kernel(new float[orderX * orderY]);
if (!kernel)
return NS_ERROR_FAILURE;
for (uint32_t i = 0; i < kmLength; i++) {
kernel[kmLength - 1 - i] = kernelMatrix[i];
}
float divisor;
if (mNumberAttributes[DIVISOR].IsExplicitlySet()) {
divisor = mNumberAttributes[DIVISOR].GetAnimValue();
if (divisor == 0)
return NS_ERROR_FAILURE;
} else {
divisor = kernel[0];
for (uint32_t i = 1; i < kmLength; i++)
divisor += kernel[i];
if (divisor == 0)
divisor = 1;
}
ScaleInfo info = SetupScalingFilter(instance, aSources[0], aTarget, rect,
&mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
if (!info.mTarget)
return NS_ERROR_FAILURE;
uint16_t edgeMode = mEnumAttributes[EDGEMODE].GetAnimValue();
bool preserveAlpha = mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
float bias = mNumberAttributes[BIAS].GetAnimValue();
const nsIntRect& dataRect = info.mDataRect;
int32_t stride = info.mSource->Stride();
int32_t width = info.mSource->GetSize().width;
int32_t height = info.mSource->GetSize().height;
uint8_t *sourceData = info.mSource->Data();
uint8_t *targetData = info.mTarget->Data();
for (int32_t y = dataRect.y; y < dataRect.YMost(); y++) {
for (int32_t x = dataRect.x; x < dataRect.XMost(); x++) {
ConvolvePixel(sourceData, targetData,
width, height, stride,
x, y,
edgeMode, kernel, divisor, bias, preserveAlpha,
orderX, orderY, targetX, targetY);
}
}
FinishScalingFilter(&info);
return NS_OK;
}
bool
nsSVGFEConvolveMatrixElement::AttributeAffectsRendering(int32_t aNameSpaceID,
nsIAtom* aAttribute) const
{
return nsSVGFEConvolveMatrixElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
(aNameSpaceID == kNameSpaceID_None &&
(aAttribute == nsGkAtoms::in ||
aAttribute == nsGkAtoms::divisor ||
aAttribute == nsGkAtoms::bias ||
aAttribute == nsGkAtoms::kernelUnitLength ||
aAttribute == nsGkAtoms::targetX ||
aAttribute == nsGkAtoms::targetY ||
aAttribute == nsGkAtoms::order ||
aAttribute == nsGkAtoms::preserveAlpha||
aAttribute == nsGkAtoms::edgeMode ||
aAttribute == nsGkAtoms::kernelMatrix));
}
//----------------------------------------------------------------------
// nsSVGElement methods
nsSVGElement::NumberAttributesInfo
nsSVGFEConvolveMatrixElement::GetNumberInfo()
{
return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
ArrayLength(sNumberInfo));
}
nsSVGElement::NumberPairAttributesInfo
nsSVGFEConvolveMatrixElement::GetNumberPairInfo()
{
return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
ArrayLength(sNumberPairInfo));
}
nsSVGElement::IntegerAttributesInfo
nsSVGFEConvolveMatrixElement::GetIntegerInfo()
{
return IntegerAttributesInfo(mIntegerAttributes, sIntegerInfo,
ArrayLength(sIntegerInfo));
}
nsSVGElement::IntegerPairAttributesInfo
nsSVGFEConvolveMatrixElement::GetIntegerPairInfo()
{
return IntegerPairAttributesInfo(mIntegerPairAttributes, sIntegerPairInfo,
ArrayLength(sIntegerPairInfo));
}
nsSVGElement::BooleanAttributesInfo
nsSVGFEConvolveMatrixElement::GetBooleanInfo()
{
return BooleanAttributesInfo(mBooleanAttributes, sBooleanInfo,
ArrayLength(sBooleanInfo));
}
nsSVGElement::EnumAttributesInfo
nsSVGFEConvolveMatrixElement::GetEnumInfo()
{
return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
ArrayLength(sEnumInfo));
}
nsSVGElement::StringAttributesInfo
nsSVGFEConvolveMatrixElement::GetStringInfo()
{
return StringAttributesInfo(mStringAttributes, sStringInfo,
ArrayLength(sStringInfo));
}
nsSVGElement::NumberListAttributesInfo
nsSVGFEConvolveMatrixElement::GetNumberListInfo()
{
return NumberListAttributesInfo(mNumberListAttributes, sNumberListInfo,
ArrayLength(sNumberListInfo));
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,111 @@
/* 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_SVGFEConvolveMatrixElement_h
#define mozilla_dom_SVGFEConvolveMatrixElement_h
#include "nsSVGFilters.h"
namespace mozilla {
namespace dom {
typedef nsSVGFE nsSVGFEConvolveMatrixElementBase;
class nsSVGFEConvolveMatrixElement : public nsSVGFEConvolveMatrixElementBase,
public nsIDOMSVGFEConvolveMatrixElement
{
friend nsresult NS_NewSVGFEConvolveMatrixElement(nsIContent **aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
protected:
nsSVGFEConvolveMatrixElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsSVGFEConvolveMatrixElementBase(aNodeInfo) {}
public:
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
// FE Base
NS_FORWARD_NSIDOMSVGFILTERPRIMITIVESTANDARDATTRIBUTES(nsSVGFEConvolveMatrixElementBase::)
virtual nsresult Filter(nsSVGFilterInstance* aInstance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& aDataRect);
virtual bool AttributeAffectsRendering(
int32_t aNameSpaceID, nsIAtom* aAttribute) const;
virtual nsSVGString& GetResultImageName() { return mStringAttributes[RESULT]; }
virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources);
virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Color Matrix
NS_DECL_NSIDOMSVGFECONVOLVEMATRIXELEMENT
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFEConvolveMatrixElementBase::)
NS_FORWARD_NSIDOMNODE_TO_NSINODE
NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
virtual nsXPCClassInfo* GetClassInfo();
virtual nsIDOMNode* AsDOMNode() { return this; }
protected:
virtual bool OperatesOnPremultipledAlpha(int32_t) {
return !mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
}
virtual NumberAttributesInfo GetNumberInfo();
virtual NumberPairAttributesInfo GetNumberPairInfo();
virtual IntegerAttributesInfo GetIntegerInfo();
virtual IntegerPairAttributesInfo GetIntegerPairInfo();
virtual BooleanAttributesInfo GetBooleanInfo();
virtual EnumAttributesInfo GetEnumInfo();
virtual StringAttributesInfo GetStringInfo();
virtual NumberListAttributesInfo GetNumberListInfo();
enum { DIVISOR, BIAS };
nsSVGNumber2 mNumberAttributes[2];
static NumberInfo sNumberInfo[2];
enum { KERNEL_UNIT_LENGTH };
nsSVGNumberPair mNumberPairAttributes[1];
static NumberPairInfo sNumberPairInfo[1];
enum { TARGET_X, TARGET_Y };
nsSVGInteger mIntegerAttributes[2];
static IntegerInfo sIntegerInfo[2];
enum { ORDER };
nsSVGIntegerPair mIntegerPairAttributes[1];
static IntegerPairInfo sIntegerPairInfo[1];
enum { PRESERVEALPHA };
nsSVGBoolean mBooleanAttributes[1];
static BooleanInfo sBooleanInfo[1];
enum { EDGEMODE };
nsSVGEnum mEnumAttributes[1];
static nsSVGEnumMapping sEdgeModeMap[];
static EnumInfo sEnumInfo[1];
enum { RESULT, IN1 };
nsSVGString mStringAttributes[2];
static StringInfo sStringInfo[2];
enum { KERNELMATRIX };
SVGAnimatedNumberList mNumberListAttributes[1];
static NumberListInfo sNumberListInfo[1];
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_SVGFEConvolveMatrixElement_h

Просмотреть файл

@ -1518,527 +1518,6 @@ nsSVGFEMorphologyElement::GetStringInfo()
ArrayLength(sStringInfo)); ArrayLength(sStringInfo));
} }
//---------------------Convolve Matrix------------------------
typedef nsSVGFE nsSVGFEConvolveMatrixElementBase;
class nsSVGFEConvolveMatrixElement : public nsSVGFEConvolveMatrixElementBase,
public nsIDOMSVGFEConvolveMatrixElement
{
friend nsresult NS_NewSVGFEConvolveMatrixElement(nsIContent **aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
protected:
nsSVGFEConvolveMatrixElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsSVGFEConvolveMatrixElementBase(aNodeInfo) {}
public:
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
// FE Base
NS_FORWARD_NSIDOMSVGFILTERPRIMITIVESTANDARDATTRIBUTES(nsSVGFEConvolveMatrixElementBase::)
virtual nsresult Filter(nsSVGFilterInstance* aInstance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& aDataRect);
virtual bool AttributeAffectsRendering(
int32_t aNameSpaceID, nsIAtom* aAttribute) const;
virtual nsSVGString& GetResultImageName() { return mStringAttributes[RESULT]; }
virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources);
virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Color Matrix
NS_DECL_NSIDOMSVGFECONVOLVEMATRIXELEMENT
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFEConvolveMatrixElementBase::)
NS_FORWARD_NSIDOMNODE_TO_NSINODE
NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
virtual nsXPCClassInfo* GetClassInfo();
virtual nsIDOMNode* AsDOMNode() { return this; }
protected:
virtual bool OperatesOnPremultipledAlpha(int32_t) {
return !mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
}
virtual NumberAttributesInfo GetNumberInfo();
virtual NumberPairAttributesInfo GetNumberPairInfo();
virtual IntegerAttributesInfo GetIntegerInfo();
virtual IntegerPairAttributesInfo GetIntegerPairInfo();
virtual BooleanAttributesInfo GetBooleanInfo();
virtual EnumAttributesInfo GetEnumInfo();
virtual StringAttributesInfo GetStringInfo();
virtual NumberListAttributesInfo GetNumberListInfo();
enum { DIVISOR, BIAS };
nsSVGNumber2 mNumberAttributes[2];
static NumberInfo sNumberInfo[2];
enum { KERNEL_UNIT_LENGTH };
nsSVGNumberPair mNumberPairAttributes[1];
static NumberPairInfo sNumberPairInfo[1];
enum { TARGET_X, TARGET_Y };
nsSVGInteger mIntegerAttributes[2];
static IntegerInfo sIntegerInfo[2];
enum { ORDER };
nsSVGIntegerPair mIntegerPairAttributes[1];
static IntegerPairInfo sIntegerPairInfo[1];
enum { PRESERVEALPHA };
nsSVGBoolean mBooleanAttributes[1];
static BooleanInfo sBooleanInfo[1];
enum { EDGEMODE };
nsSVGEnum mEnumAttributes[1];
static nsSVGEnumMapping sEdgeModeMap[];
static EnumInfo sEnumInfo[1];
enum { RESULT, IN1 };
nsSVGString mStringAttributes[2];
static StringInfo sStringInfo[2];
enum { KERNELMATRIX };
SVGAnimatedNumberList mNumberListAttributes[1];
static NumberListInfo sNumberListInfo[1];
};
nsSVGElement::NumberInfo nsSVGFEConvolveMatrixElement::sNumberInfo[2] =
{
{ &nsGkAtoms::divisor, 1, false },
{ &nsGkAtoms::bias, 0, false }
};
nsSVGElement::NumberPairInfo nsSVGFEConvolveMatrixElement::sNumberPairInfo[1] =
{
{ &nsGkAtoms::kernelUnitLength, 0, 0 }
};
nsSVGElement::IntegerInfo nsSVGFEConvolveMatrixElement::sIntegerInfo[2] =
{
{ &nsGkAtoms::targetX, 0 },
{ &nsGkAtoms::targetY, 0 }
};
nsSVGElement::IntegerPairInfo nsSVGFEConvolveMatrixElement::sIntegerPairInfo[1] =
{
{ &nsGkAtoms::order, 3, 3 }
};
nsSVGElement::BooleanInfo nsSVGFEConvolveMatrixElement::sBooleanInfo[1] =
{
{ &nsGkAtoms::preserveAlpha, false }
};
nsSVGEnumMapping nsSVGFEConvolveMatrixElement::sEdgeModeMap[] = {
{&nsGkAtoms::duplicate, nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_DUPLICATE},
{&nsGkAtoms::wrap, nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_WRAP},
{&nsGkAtoms::none, nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_NONE},
{nullptr, 0}
};
nsSVGElement::EnumInfo nsSVGFEConvolveMatrixElement::sEnumInfo[1] =
{
{ &nsGkAtoms::edgeMode,
sEdgeModeMap,
nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_DUPLICATE
}
};
nsSVGElement::StringInfo nsSVGFEConvolveMatrixElement::sStringInfo[2] =
{
{ &nsGkAtoms::result, kNameSpaceID_None, true },
{ &nsGkAtoms::in, kNameSpaceID_None, true }
};
nsSVGElement::NumberListInfo nsSVGFEConvolveMatrixElement::sNumberListInfo[1] =
{
{ &nsGkAtoms::kernelMatrix }
};
NS_IMPL_NS_NEW_SVG_ELEMENT(FEConvolveMatrix)
//----------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ADDREF_INHERITED(nsSVGFEConvolveMatrixElement,nsSVGFEConvolveMatrixElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGFEConvolveMatrixElement,nsSVGFEConvolveMatrixElementBase)
DOMCI_NODE_DATA(SVGFEConvolveMatrixElement, nsSVGFEConvolveMatrixElement)
NS_INTERFACE_TABLE_HEAD(nsSVGFEConvolveMatrixElement)
NS_NODE_INTERFACE_TABLE5(nsSVGFEConvolveMatrixElement, nsIDOMNode,
nsIDOMElement, nsIDOMSVGElement,
nsIDOMSVGFilterPrimitiveStandardAttributes,
nsIDOMSVGFEConvolveMatrixElement)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGFEConvolveMatrixElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGFEConvolveMatrixElementBase)
//----------------------------------------------------------------------
// nsIDOMNode methods
NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGFEConvolveMatrixElement)
//----------------------------------------------------------------------
// nsSVGFEConvolveMatrixElement methods
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetIn1(nsIDOMSVGAnimatedString * *aIn)
{
return mStringAttributes[IN1].ToDOMAnimatedString(aIn, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetOrderX(nsIDOMSVGAnimatedInteger * *aOrderX)
{
return mIntegerPairAttributes[ORDER].ToDOMAnimatedInteger(aOrderX, nsSVGIntegerPair::eFirst, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetOrderY(nsIDOMSVGAnimatedInteger * *aOrderY)
{
return mIntegerPairAttributes[ORDER].ToDOMAnimatedInteger(aOrderY, nsSVGIntegerPair::eSecond, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetKernelMatrix(nsISupports * *aKernelMatrix)
{
*aKernelMatrix = DOMSVGAnimatedNumberList::GetDOMWrapper(&mNumberListAttributes[KERNELMATRIX],
this, KERNELMATRIX).get();
return NS_OK;
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetTargetX(nsIDOMSVGAnimatedInteger * *aTargetX)
{
return mIntegerAttributes[TARGET_X].ToDOMAnimatedInteger(aTargetX, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetTargetY(nsIDOMSVGAnimatedInteger * *aTargetY)
{
return mIntegerAttributes[TARGET_Y].ToDOMAnimatedInteger(aTargetY, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetEdgeMode(nsIDOMSVGAnimatedEnumeration * *aEdgeMode)
{
return mEnumAttributes[EDGEMODE].ToDOMAnimatedEnum(aEdgeMode, this);
}
NS_IMETHODIMP nsSVGFEConvolveMatrixElement::GetPreserveAlpha(nsISupports * *aPreserveAlpha)
{
return mBooleanAttributes[PRESERVEALPHA].ToDOMAnimatedBoolean(aPreserveAlpha, this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetDivisor(nsIDOMSVGAnimatedNumber **aDivisor)
{
return mNumberAttributes[DIVISOR].ToDOMAnimatedNumber(aDivisor, this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetBias(nsIDOMSVGAnimatedNumber **aBias)
{
return mNumberAttributes[BIAS].ToDOMAnimatedNumber(aBias, this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetKernelUnitLengthX(nsIDOMSVGAnimatedNumber **aKernelX)
{
return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(aKernelX,
nsSVGNumberPair::eFirst,
this);
}
NS_IMETHODIMP
nsSVGFEConvolveMatrixElement::GetKernelUnitLengthY(nsIDOMSVGAnimatedNumber **aKernelY)
{
return mNumberPairAttributes[KERNEL_UNIT_LENGTH].ToDOMAnimatedNumber(aKernelY,
nsSVGNumberPair::eSecond,
this);
}
void
nsSVGFEConvolveMatrixElement::GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources)
{
aSources.AppendElement(nsSVGStringInfo(&mStringAttributes[IN1], this));
}
nsIntRect
nsSVGFEConvolveMatrixElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance)
{
// XXX A more precise box is possible when 'bias' is zero and 'edgeMode' is
// 'none', but it requires analysis of 'kernelUnitLength', 'order' and
// 'targetX/Y', so it's quite a lot of work. Don't do it for now.
return GetMaxRect();
}
void
nsSVGFEConvolveMatrixElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
{
// XXX Precise results are possible but we're going to skip that work
// for now. Do nothing, which means the needed-box remains the
// source's output bounding box.
}
nsIntRect
nsSVGFEConvolveMatrixElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
// XXX Precise results are possible but we're going to skip that work
// for now.
return GetMaxRect();
}
static int32_t BoundInterval(int32_t aVal, int32_t aMax)
{
aVal = std::max(aVal, 0);
return std::min(aVal, aMax - 1);
}
static int32_t WrapInterval(int32_t aVal, int32_t aMax)
{
aVal = aVal % aMax;
return aVal < 0 ? aMax + aVal : aVal;
}
static void
ConvolvePixel(const uint8_t *aSourceData,
uint8_t *aTargetData,
int32_t aWidth, int32_t aHeight,
int32_t aStride,
int32_t aX, int32_t aY,
uint16_t aEdgeMode,
const float *aKernel,
float aDivisor, float aBias,
bool aPreserveAlpha,
int32_t aOrderX, int32_t aOrderY,
int32_t aTargetX, int32_t aTargetY)
{
float sum[4] = {0, 0, 0, 0};
aBias *= 255;
int32_t offsets[4] = {GFX_ARGB32_OFFSET_R,
GFX_ARGB32_OFFSET_G,
GFX_ARGB32_OFFSET_B,
GFX_ARGB32_OFFSET_A } ;
int32_t channels = aPreserveAlpha ? 3 : 4;
for (int32_t y = 0; y < aOrderY; y++) {
int32_t sampleY = aY + y - aTargetY;
bool overscanY = sampleY < 0 || sampleY >= aHeight;
for (int32_t x = 0; x < aOrderX; x++) {
int32_t sampleX = aX + x - aTargetX;
bool overscanX = sampleX < 0 || sampleX >= aWidth;
for (int32_t i = 0; i < channels; i++) {
if (overscanY || overscanX) {
switch (aEdgeMode) {
case nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_DUPLICATE:
sum[i] +=
aSourceData[BoundInterval(sampleY, aHeight) * aStride +
BoundInterval(sampleX, aWidth) * 4 + offsets[i]] *
aKernel[aOrderX * y + x];
break;
case nsSVGFEConvolveMatrixElement::SVG_EDGEMODE_WRAP:
sum[i] +=
aSourceData[WrapInterval(sampleY, aHeight) * aStride +
WrapInterval(sampleX, aWidth) * 4 + offsets[i]] *
aKernel[aOrderX * y + x];
break;
default:
break;
}
} else {
sum[i] +=
aSourceData[sampleY * aStride + 4 * sampleX + offsets[i]] *
aKernel[aOrderX * y + x];
}
}
}
}
for (int32_t i = 0; i < channels; i++) {
aTargetData[aY * aStride + 4 * aX + offsets[i]] =
BoundInterval(static_cast<int32_t>(sum[i] / aDivisor + aBias), 256);
}
if (aPreserveAlpha) {
aTargetData[aY * aStride + 4 * aX + GFX_ARGB32_OFFSET_A] =
aSourceData[aY * aStride + 4 * aX + GFX_ARGB32_OFFSET_A];
}
}
nsresult
nsSVGFEConvolveMatrixElement::Filter(nsSVGFilterInstance *instance,
const nsTArray<const Image*>& aSources,
const Image* aTarget,
const nsIntRect& rect)
{
const SVGNumberList &kernelMatrix =
mNumberListAttributes[KERNELMATRIX].GetAnimValue();
uint32_t kmLength = kernelMatrix.Length();
int32_t orderX = mIntegerPairAttributes[ORDER].GetAnimValue(nsSVGIntegerPair::eFirst);
int32_t orderY = mIntegerPairAttributes[ORDER].GetAnimValue(nsSVGIntegerPair::eSecond);
if (orderX <= 0 || orderY <= 0 ||
static_cast<uint32_t>(orderX * orderY) != kmLength) {
return NS_ERROR_FAILURE;
}
int32_t targetX, targetY;
GetAnimatedIntegerValues(&targetX, &targetY, nullptr);
if (mIntegerAttributes[TARGET_X].IsExplicitlySet()) {
if (targetX < 0 || targetX >= orderX)
return NS_ERROR_FAILURE;
} else {
targetX = orderX / 2;
}
if (mIntegerAttributes[TARGET_Y].IsExplicitlySet()) {
if (targetY < 0 || targetY >= orderY)
return NS_ERROR_FAILURE;
} else {
targetY = orderY / 2;
}
if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
return NS_ERROR_FAILURE;
nsAutoArrayPtr<float> kernel(new float[orderX * orderY]);
if (!kernel)
return NS_ERROR_FAILURE;
for (uint32_t i = 0; i < kmLength; i++) {
kernel[kmLength - 1 - i] = kernelMatrix[i];
}
float divisor;
if (mNumberAttributes[DIVISOR].IsExplicitlySet()) {
divisor = mNumberAttributes[DIVISOR].GetAnimValue();
if (divisor == 0)
return NS_ERROR_FAILURE;
} else {
divisor = kernel[0];
for (uint32_t i = 1; i < kmLength; i++)
divisor += kernel[i];
if (divisor == 0)
divisor = 1;
}
ScaleInfo info = SetupScalingFilter(instance, aSources[0], aTarget, rect,
&mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
if (!info.mTarget)
return NS_ERROR_FAILURE;
uint16_t edgeMode = mEnumAttributes[EDGEMODE].GetAnimValue();
bool preserveAlpha = mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
float bias = mNumberAttributes[BIAS].GetAnimValue();
const nsIntRect& dataRect = info.mDataRect;
int32_t stride = info.mSource->Stride();
int32_t width = info.mSource->GetSize().width;
int32_t height = info.mSource->GetSize().height;
uint8_t *sourceData = info.mSource->Data();
uint8_t *targetData = info.mTarget->Data();
for (int32_t y = dataRect.y; y < dataRect.YMost(); y++) {
for (int32_t x = dataRect.x; x < dataRect.XMost(); x++) {
ConvolvePixel(sourceData, targetData,
width, height, stride,
x, y,
edgeMode, kernel, divisor, bias, preserveAlpha,
orderX, orderY, targetX, targetY);
}
}
FinishScalingFilter(&info);
return NS_OK;
}
bool
nsSVGFEConvolveMatrixElement::AttributeAffectsRendering(int32_t aNameSpaceID,
nsIAtom* aAttribute) const
{
return nsSVGFEConvolveMatrixElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||
(aNameSpaceID == kNameSpaceID_None &&
(aAttribute == nsGkAtoms::in ||
aAttribute == nsGkAtoms::divisor ||
aAttribute == nsGkAtoms::bias ||
aAttribute == nsGkAtoms::kernelUnitLength ||
aAttribute == nsGkAtoms::targetX ||
aAttribute == nsGkAtoms::targetY ||
aAttribute == nsGkAtoms::order ||
aAttribute == nsGkAtoms::preserveAlpha||
aAttribute == nsGkAtoms::edgeMode ||
aAttribute == nsGkAtoms::kernelMatrix));
}
//----------------------------------------------------------------------
// nsSVGElement methods
nsSVGElement::NumberAttributesInfo
nsSVGFEConvolveMatrixElement::GetNumberInfo()
{
return NumberAttributesInfo(mNumberAttributes, sNumberInfo,
ArrayLength(sNumberInfo));
}
nsSVGElement::NumberPairAttributesInfo
nsSVGFEConvolveMatrixElement::GetNumberPairInfo()
{
return NumberPairAttributesInfo(mNumberPairAttributes, sNumberPairInfo,
ArrayLength(sNumberPairInfo));
}
nsSVGElement::IntegerAttributesInfo
nsSVGFEConvolveMatrixElement::GetIntegerInfo()
{
return IntegerAttributesInfo(mIntegerAttributes, sIntegerInfo,
ArrayLength(sIntegerInfo));
}
nsSVGElement::IntegerPairAttributesInfo
nsSVGFEConvolveMatrixElement::GetIntegerPairInfo()
{
return IntegerPairAttributesInfo(mIntegerPairAttributes, sIntegerPairInfo,
ArrayLength(sIntegerPairInfo));
}
nsSVGElement::BooleanAttributesInfo
nsSVGFEConvolveMatrixElement::GetBooleanInfo()
{
return BooleanAttributesInfo(mBooleanAttributes, sBooleanInfo,
ArrayLength(sBooleanInfo));
}
nsSVGElement::EnumAttributesInfo
nsSVGFEConvolveMatrixElement::GetEnumInfo()
{
return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
ArrayLength(sEnumInfo));
}
nsSVGElement::StringAttributesInfo
nsSVGFEConvolveMatrixElement::GetStringInfo()
{
return StringAttributesInfo(mStringAttributes, sStringInfo,
ArrayLength(sStringInfo));
}
nsSVGElement::NumberListAttributesInfo
nsSVGFEConvolveMatrixElement::GetNumberListInfo()
{
return NumberListAttributesInfo(mNumberListAttributes, sNumberListInfo,
ArrayLength(sNumberListInfo));
}
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// //
nsSVGElement::NumberInfo nsSVGFELightingElement::sNumberInfo[4] = nsSVGElement::NumberInfo nsSVGFELightingElement::sNumberInfo[4] =