Bug 948265 - Support SourceAlpha keyword in SVG filter chains. r=mstange

This commit is contained in:
Max Vujovic 2014-07-15 11:37:00 +02:00
parent 4f90ee5e92
commit 3a832415cc
7 changed files with 151 additions and 3 deletions

View File

@ -966,6 +966,11 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
return transform;
}
case PrimitiveType::ToAlpha:
{
return FilterWrappers::ToAlpha(aDT, aSources[0]);
}
default:
return nullptr;
}
@ -1001,6 +1006,7 @@ InputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
switch (aDescr.Type()) {
case PrimitiveType::Tile:
case PrimitiveType::Offset:
case PrimitiveType::ToAlpha:
return aOriginalAlphaModel;
case PrimitiveType::ColorMatrix:
@ -1196,6 +1202,7 @@ ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
case PrimitiveType::ColorMatrix:
case PrimitiveType::ComponentTransfer:
case PrimitiveType::ToAlpha:
return aInputChangeRegions[0];
case PrimitiveType::Morphology:
@ -1425,6 +1432,7 @@ SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
case PrimitiveType::Merge:
case PrimitiveType::ColorMatrix:
case PrimitiveType::ComponentTransfer:
case PrimitiveType::ToAlpha:
return aResultNeededRegion;
case PrimitiveType::Morphology:

View File

@ -270,6 +270,7 @@ MOZ_BEGIN_ENUM_CLASS(PrimitiveType)
DropShadow,
DiffuseLighting,
SpecularLighting,
ToAlpha,
Max
MOZ_END_ENUM_CLASS(PrimitiveType)

View File

@ -9,5 +9,6 @@ default-preferences pref(layout.css.filters.enabled,true)
== intersecting-filter-regions.svg intersecting-filter-regions-ref.svg
== long-chain.svg simple-chain-ref.svg
== multiple-primitives-per-filter.svg simple-chain-ref.svg
== second-filter-uses-SourceAlpha.svg second-filter-uses-SourceAlpha.svg
== second-filter-uses-SourceGraphic.svg simple-chain-ref.svg
== simple-chain.svg simple-chain-ref.svg

View File

@ -0,0 +1,29 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg id="svg-root"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="testmeta">
<title>SVG Filter Chains: Second Filter Uses SourceAlpha</title>
<link rel="copyright"
href="http://www.w3.org/Graphics/SVG/Test/Copyright"/>
<link rel="license"
href="http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html"/>
<link rel="author"
title="Max Vujovic"
href="mailto:mvujovic@adobe.com"/>
<link rel="help"
href="http://dev.w3.org/fxtf/filters/#FilterPrimitiveSubRegion"/>
<metadata class="flags">namespace svg</metadata>
</g>
<g id="test-body-content">
<filter id="blur">
<feGaussianBlur stdDeviation="3"/>
</filter>
<rect x="100" y="100" width="100" height="100" filter="url(#blur)" fill="#00ff00"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 969 B

View File

@ -0,0 +1,49 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg id="svg-root"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="testmeta">
<title>SVG Filter Chains: Second Filter Uses SourceAlpha</title>
<link rel="copyright"
href="http://www.w3.org/Graphics/SVG/Test/Copyright"/>
<link rel="license"
href="http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html"/>
<link rel="author"
title="Max Vujovic"
href="mailto:mvujovic@adobe.com"/>
<link rel="help"
href="http://dev.w3.org/fxtf/filters/#FilterPrimitiveSubRegion"/>
<link rel="match"
href="second-filter-uses-SourceAlpha.svg" />
<metadata class="flags">namespace svg</metadata>
<desc class="assert">
In an SVG filter chain, this test verifies that a filter receives the
correct SourceAlpha input from the previous filter in the chain. If the
test passes, you should see a blurred green square.
</desc>
</g>
<g id="test-body-content">
<filter id="blur">
<feGaussianBlur stdDeviation="3"/>
</filter>
<filter id="add-green">
<!--
This filter receives transparent black and the alpha channel of the
previous blur filter. Then, it adds to the green channel where the alpha
channel is set, resulting in a blurred green square.
-->
<feComponentTransfer in="SourceAlpha">
<feFuncR type="identity"/>
<feFuncG type="table" tableValues="1 1"/>
<feFuncB type="identity"/>
<feFuncA type="identity"/>
</feComponentTransfer>
</filter>
<rect x="100" y="100" width="100" height="100" filter="url(#blur) url(#add-green)" fill="red"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -34,6 +34,7 @@ nsSVGFilterInstance::nsSVGFilterInstance(const nsStyleFilter& aFilter,
mTargetBBox(aTargetBBox),
mUserSpaceToFilterSpaceScale(aUserSpaceToFilterSpaceScale),
mFilterSpaceToUserSpaceScale(aFilterSpaceToUserSpaceScale),
mSourceAlphaAvailable(false),
mInitialized(false) {
// Get the filter frame.
@ -288,9 +289,46 @@ GetLastResultIndex(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
numPrimitiveDescrs - 1;
}
int32_t
nsSVGFilterInstance::GetOrCreateSourceAlphaIndex(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
{
// If the SourceAlpha index has already been determined or created for this
// SVG filter, just return it.
if (mSourceAlphaAvailable)
return mSourceAlphaIndex;
// If this is the first filter in the chain, we can just use the
// kPrimitiveIndexSourceAlpha keyword to refer to the SourceAlpha of the
// original image.
if (mSourceGraphicIndex < 0) {
mSourceAlphaIndex = FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha;
mSourceAlphaAvailable = true;
return mSourceAlphaIndex;
}
// Otherwise, create a primitive description to turn the previous filter's
// output into a SourceAlpha input.
FilterPrimitiveDescription descr(PrimitiveType::ToAlpha);
descr.SetInputPrimitive(0, mSourceGraphicIndex);
const FilterPrimitiveDescription& sourcePrimitiveDescr =
aPrimitiveDescrs[mSourceGraphicIndex];
descr.SetPrimitiveSubregion(sourcePrimitiveDescr.PrimitiveSubregion());
descr.SetIsTainted(sourcePrimitiveDescr.IsTainted());
ColorSpace colorSpace = sourcePrimitiveDescr.OutputColorSpace();
descr.SetInputColorSpace(0, colorSpace);
descr.SetOutputColorSpace(colorSpace);
aPrimitiveDescrs.AppendElement(descr);
mSourceAlphaIndex = aPrimitiveDescrs.Length() - 1;
mSourceAlphaAvailable = true;
return mSourceAlphaIndex;
}
nsresult
nsSVGFilterInstance::GetSourceIndices(nsSVGFE* aPrimitiveElement,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
nsTArray<int32_t>& aSourceIndices)
{
@ -305,7 +343,7 @@ nsSVGFilterInstance::GetSourceIndices(nsSVGFE* aPrimitiveElement,
if (str.EqualsLiteral("SourceGraphic")) {
sourceIndex = mSourceGraphicIndex;
} else if (str.EqualsLiteral("SourceAlpha")) {
sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha;
sourceIndex = GetOrCreateSourceAlphaIndex(aPrimitiveDescrs);
} else if (str.EqualsLiteral("FillPaint")) {
sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexFillPaint;
} else if (str.EqualsLiteral("StrokePaint")) {

View File

@ -173,6 +173,16 @@ private:
*/
gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const;
/**
* Appends a new FilterPrimitiveDescription to aPrimitiveDescrs that
* converts the FilterPrimitiveDescription at mSourceGraphicIndex into
* a SourceAlpha input for the next FilterPrimitiveDescription.
*
* The new FilterPrimitiveDescription zeros out the SourceGraphic's RGB
* channels and keeps the alpha channel intact.
*/
int32_t GetOrCreateSourceAlphaIndex(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
/**
* Finds the index in aPrimitiveDescrs of each input to aPrimitiveElement.
* For example, if aPrimitiveElement is:
@ -181,7 +191,7 @@ private:
* FilterPrimitiveDescription representing "another-primitive".
*/
nsresult GetSourceIndices(nsSVGFE* aPrimitiveElement,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
nsTArray<int32_t>& aSourceIndices);
@ -240,6 +250,18 @@ private:
*/
int32_t mSourceGraphicIndex;
/**
* The index of the FilterPrimitiveDescription that this SVG filter should use
* as its SourceAlpha, or the SourceAlpha keyword index if this is the first
* filter in a chain.
*/
int32_t mSourceAlphaIndex;
/**
* SourceAlpha is available if GetOrCreateSourceAlphaIndex has been called.
*/
int32_t mSourceAlphaAvailable;
bool mInitialized;
};