зеркало из https://github.com/mozilla/gecko-dev.git
Bug 608161 - Don't rely on HasAttr to detect whether gradient attributes have values; r=longsonr
This commit is contained in:
Родитель
d877788df3
Коммит
ea818a8a3c
|
@ -0,0 +1,142 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 900">
|
||||
<!-- 1. gradientUnits -->
|
||||
<defs>
|
||||
<linearGradient id="gradientUnits" x1="0" y1="0" x2="100" y2="0"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="100" height="100" fill="url(#gradientUnits)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#gradientUnits)"/>
|
||||
</g>
|
||||
<!-- 2. gradientTransform -->
|
||||
<defs>
|
||||
<linearGradient id="gradientTransform"
|
||||
gradientTransform="rotate(90 0.5 0.5)">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 100)">
|
||||
<rect width="100" height="100" fill="url(#gradientTransform)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#gradientTransform)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 3. x1, x2 -->
|
||||
<defs>
|
||||
<linearGradient id="x1x2" x1="40%" x2="60%">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 200)">
|
||||
<rect width="100" height="100" fill="url(#x1x2)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#x1x2)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 4. y1, y2 -->
|
||||
<defs>
|
||||
<linearGradient id="y1y2" x2="0%" y1="40%" y2="60%">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 300)">
|
||||
<rect width="100" height="100" fill="url(#y1y2)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#y1y2)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 5. cx, cy -->
|
||||
<defs>
|
||||
<radialGradient id="cxcy" cx="0%" cy="100%">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 400)">
|
||||
<rect width="100" height="100" fill="url(#cxcy)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#cxcy)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 6. r -->
|
||||
<defs>
|
||||
<radialGradient id="r" r="100%">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 500)">
|
||||
<rect width="100" height="100" fill="url(#r)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#r)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 7. fx, fy -->
|
||||
<defs>
|
||||
<radialGradient id="fxfy" fx="20%" fy="80%">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 600)">
|
||||
<rect width="100" height="100" fill="url(#fxfy)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#fxfy)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 8. spreadMethod -->
|
||||
<defs>
|
||||
<linearGradient id="spreadMethod" x1="50%" spreadMethod="reflect">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 700)">
|
||||
<rect width="100" height="100" fill="url(#spreadMethod)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#spreadMethod)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 9. xlink:href -->
|
||||
<defs>
|
||||
<linearGradient id="xlink" xlink:href="#xlinkRef"/>
|
||||
<linearGradient id="xlinkRef">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 800)">
|
||||
<rect width="100" height="100" fill="url(#xlink)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#xlinkRef)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- We were getting random but very minor anti-aliasing differences on OSX
|
||||
and OSX64 along the edges of these gradients so we draw a thick stroke
|
||||
over all the edges. -->
|
||||
<path stroke="black" stroke-width="3" stroke-linecap="square" fill="none"
|
||||
d="M0 0H200V900H0V0
|
||||
M0 100H200
|
||||
M0 200H200
|
||||
M0 300H200
|
||||
M0 400H200
|
||||
M0 500H200
|
||||
M0 600H200
|
||||
M0 700H200
|
||||
M0 800H200
|
||||
M0 900H200
|
||||
M100 0V900"/>
|
||||
<!-- If adding more tests here, be sure to update the viewBox on the root svg
|
||||
element -->
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 4.5 KiB |
|
@ -0,0 +1,193 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 900">
|
||||
<!-- Bug 608161 - SVG SMIL: Don't use HasAttr to test for presence of animated
|
||||
attributes.
|
||||
|
||||
Test animating gradient attributes doesn't rely on the presence of
|
||||
attributes in the DOM, but also correctly detects attributes set by
|
||||
animation.
|
||||
|
||||
The format of each test is that we have a base gradient named
|
||||
(attName)Ref which does NOT specify the attribute under test, but instead
|
||||
sets the attribute to a non-default value using animation.
|
||||
|
||||
Then we have a referencing gradient named (attName) that refers to the
|
||||
base gradient and also does NOT specify the attribute under test.
|
||||
|
||||
When we go to look up the attribute under test we begin at (attName),
|
||||
notice the attribute isn't specified (either in the DOM or by animation),
|
||||
then go to (attName)Ref and detect that the attribute is specified there
|
||||
by animation and use that value.
|
||||
|
||||
To the right of each test we also include a rect that directly references
|
||||
(attName)Ref. The two rectangles should be identical but prior to fixing
|
||||
this bug they were not.
|
||||
-->
|
||||
<!-- 1. gradientUnits: defaults to objectBoundingBox -->
|
||||
<defs>
|
||||
<linearGradient xlink:href="#gradientUnitsRef" id="gradientUnits"/>
|
||||
<linearGradient id="gradientUnitsRef" x1="0" y1="0" x2="100" y2="0">
|
||||
<set attributeName="gradientUnits" to="userSpaceOnUse"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="100" height="100" fill="url(#gradientUnits)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#gradientUnitsRef)"/>
|
||||
</g>
|
||||
<!-- 2. gradientTransform: defaults to identity -->
|
||||
<defs>
|
||||
<linearGradient xlink:href="#gradientTransformRef" id="gradientTransform"/>
|
||||
<linearGradient id="gradientTransformRef">
|
||||
<animateTransform attributeName="gradientTransform" type="rotate"
|
||||
values="90 0.5 0.5" fill="freeze"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 100)">
|
||||
<rect width="100" height="100" fill="url(#gradientTransform)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#gradientTransformRef)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 3. x1: defaults to 0%
|
||||
x2: defaults to 100% -->
|
||||
<defs>
|
||||
<linearGradient xlink:href="#x1x2Ref" id="x1x2"/>
|
||||
<linearGradient id="x1x2Ref">
|
||||
<set attributeName="x1" to="40%"/>
|
||||
<set attributeName="x2" to="60%"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 200)">
|
||||
<rect width="100" height="100" fill="url(#x1x2)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#x1x2Ref)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 4. y1: defaults to 0%
|
||||
y2: defaults to 0% -->
|
||||
<defs>
|
||||
<linearGradient xlink:href="#y1y2Ref" id="y1y2"/>
|
||||
<linearGradient id="y1y2Ref" x2="0%">
|
||||
<set attributeName="y1" to="40%"/>
|
||||
<set attributeName="y2" to="60%"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 300)">
|
||||
<rect width="100" height="100" fill="url(#y1y2)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#y1y2Ref)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 5. cx: defaults to 50%
|
||||
cy: defaults to 50% -->
|
||||
<defs>
|
||||
<radialGradient xlink:href="#cxcyRef" id="cxcy"/>
|
||||
<radialGradient id="cxcyRef">
|
||||
<set attributeName="cx" to="0%"/>
|
||||
<set attributeName="cy" to="100%"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 400)">
|
||||
<rect width="100" height="100" fill="url(#cxcy)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#cxcyRef)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 6. r: defaults to 50% -->
|
||||
<defs>
|
||||
<radialGradient xlink:href="#rRef" id="r"/>
|
||||
<radialGradient id="rRef">
|
||||
<set attributeName="r" to="100%"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 500)">
|
||||
<rect width="100" height="100" fill="url(#r)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#rRef)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 7. fx: defaults to cx
|
||||
fy: defaults to cy -->
|
||||
<defs>
|
||||
<radialGradient xlink:href="#fxfyRef" id="fxfy"/>
|
||||
<radialGradient id="fxfyRef">
|
||||
<set attributeName="fx" to="20%"/>
|
||||
<set attributeName="fy" to="80%"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 600)">
|
||||
<rect width="100" height="100" fill="url(#fxfy)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#fxfyRef)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 8. spreadMethod: defaults to pad -->
|
||||
<defs>
|
||||
<linearGradient xlink:href="#spreadMethodRef" id="spreadMethod"/>
|
||||
<linearGradient id="spreadMethodRef" x1="50%">
|
||||
<set attributeName="spreadMethod" to="reflect"/>
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 700)">
|
||||
<rect width="100" height="100" fill="url(#spreadMethod)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#spreadMethodRef)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- 9. xlink:href
|
||||
This attribute is not affected by bug 608161 but we test it here for
|
||||
completeness.
|
||||
-->
|
||||
<defs>
|
||||
<linearGradient id="xlink">
|
||||
<set attributeName="xlink:href" to="#xlinkRef"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="xlinkRef">
|
||||
<stop offset="0%" stop-color="#F60" />
|
||||
<stop offset="100%" stop-color="#FF6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(0 800)">
|
||||
<rect width="100" height="100" fill="url(#xlink)"/>
|
||||
<g transform="translate(100)">
|
||||
<rect width="100" height="100" fill="url(#xlinkRef)"/>
|
||||
</g>
|
||||
</g>
|
||||
<!-- We were getting random but very minor anti-aliasing differences on OSX
|
||||
and OSX64 along the edges of these gradients so we draw a thick stroke
|
||||
over all the edges. -->
|
||||
<path stroke="black" stroke-width="3" stroke-linecap="square" fill="none"
|
||||
d="M0 0H200V900H0V0
|
||||
M0 100H200
|
||||
M0 200H200
|
||||
M0 300H200
|
||||
M0 400H200
|
||||
M0 500H200
|
||||
M0 600H200
|
||||
M0 700H200
|
||||
M0 800H200
|
||||
M0 900H200
|
||||
M100 0V900"/>
|
||||
<!-- If adding more tests here, be sure to update the viewBox on the root svg
|
||||
element -->
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 6.9 KiB |
|
@ -226,6 +226,7 @@ random == anim-text-x-y-dx-dy-01.svg anim-text-x-y-dx-dy-01-ref.svg # bug 579588
|
|||
== anim-pattern-attr-presence-01.svg anim-pattern-attr-presence-01-ref.svg
|
||||
fails == anim-pattern-attr-presence-02.svg anim-pattern-attr-presence-02-ref.svg
|
||||
# ^ bug 621651
|
||||
== anim-gradient-attr-presence-01.svg anim-gradient-attr-presence-01-ref.svg
|
||||
|
||||
== api-sanity-1.svg lime.svg
|
||||
|
||||
|
|
|
@ -51,6 +51,27 @@
|
|||
|
||||
using mozilla::SVGAnimatedTransformList;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
|
||||
class nsSVGGradientFrame::AutoGradientReferencer
|
||||
{
|
||||
public:
|
||||
AutoGradientReferencer(nsSVGGradientFrame *aFrame)
|
||||
: mFrame(aFrame)
|
||||
{
|
||||
// Reference loops should normally be detected in advance and handled, so
|
||||
// we're not expecting to encounter them here
|
||||
NS_ABORT_IF_FALSE(!mFrame->mLoopFlag, "Undetected reference loop!");
|
||||
mFrame->mLoopFlag = true;
|
||||
}
|
||||
~AutoGradientReferencer() {
|
||||
mFrame->mLoopFlag = false;
|
||||
}
|
||||
private:
|
||||
nsSVGGradientFrame *mFrame;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
|
@ -134,6 +155,40 @@ nsSVGGradientFrame::GetStopInformation(PRInt32 aIndex,
|
|||
*aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity;
|
||||
}
|
||||
|
||||
PRUint16
|
||||
nsSVGGradientFrame::GetEnumValue(PRUint32 aIndex, nsIContent *aDefault)
|
||||
{
|
||||
const nsSVGEnum& thisEnum =
|
||||
static_cast<nsSVGGradientElement *>(mContent)->mEnumAttributes[aIndex];
|
||||
|
||||
if (thisEnum.IsExplicitlySet())
|
||||
return thisEnum.GetAnimValue();
|
||||
|
||||
AutoGradientReferencer gradientRef(this);
|
||||
|
||||
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
||||
return next ? next->GetEnumValue(aIndex, aDefault) :
|
||||
static_cast<nsSVGGradientElement *>(aDefault)->
|
||||
mEnumAttributes[aIndex].GetAnimValue();
|
||||
}
|
||||
|
||||
const SVGAnimatedTransformList*
|
||||
nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault)
|
||||
{
|
||||
SVGAnimatedTransformList *thisTransformList =
|
||||
static_cast<nsSVGGradientElement *>(mContent)->GetAnimatedTransformList();
|
||||
|
||||
if (thisTransformList->IsExplicitlySet())
|
||||
return thisTransformList;
|
||||
|
||||
AutoGradientReferencer gradientRef(this);
|
||||
|
||||
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
||||
return next ? next->GetGradientTransformList(aDefault) :
|
||||
static_cast<const nsSVGGradientElement *>(aDefault)
|
||||
->mGradientTransform.get();
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
|
||||
const gfxRect *aOverrideBounds)
|
||||
|
@ -150,19 +205,19 @@ nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
|
|||
else
|
||||
mSource = aSource;
|
||||
} else {
|
||||
NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
||||
"Unknown gradientUnits type");
|
||||
NS_ASSERTION(
|
||||
gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
||||
"Unknown gradientUnits type");
|
||||
// objectBoundingBox is the default anyway
|
||||
|
||||
gfxRect bbox = aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aSource);
|
||||
bboxMatrix = gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
|
||||
gfxRect bbox =
|
||||
aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aSource);
|
||||
bboxMatrix =
|
||||
gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
|
||||
}
|
||||
|
||||
nsSVGGradientElement *element =
|
||||
GetGradientWithAttr(nsGkAtoms::gradientTransform, mContent);
|
||||
|
||||
SVGAnimatedTransformList* animTransformList =
|
||||
element->GetAnimatedTransformList();
|
||||
const SVGAnimatedTransformList* animTransformList =
|
||||
GetGradientTransformList(mContent);
|
||||
if (!animTransformList)
|
||||
return bboxMatrix;
|
||||
|
||||
|
@ -171,13 +226,32 @@ nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
|
|||
return bboxMatrix.PreMultiply(gradientTransform);
|
||||
}
|
||||
|
||||
PRUint16
|
||||
nsSVGGradientFrame::GetSpreadMethod()
|
||||
nsSVGLinearGradientElement *
|
||||
nsSVGGradientFrame::GetLinearGradientWithLength(PRUint32 aIndex,
|
||||
nsSVGLinearGradientElement* aDefault)
|
||||
{
|
||||
nsSVGGradientElement *element =
|
||||
GetGradientWithAttr(nsGkAtoms::spreadMethod, mContent);
|
||||
// If this was a linear gradient with the required length, we would have
|
||||
// already found it in nsSVGLinearGradientFrame::GetLinearGradientWithLength.
|
||||
// Since we didn't find the length, continue looking down the chain.
|
||||
|
||||
return element->mEnumAttributes[nsSVGGradientElement::SPREADMETHOD].GetAnimValue();
|
||||
AutoGradientReferencer gradientRef(this);
|
||||
|
||||
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
||||
return next ? next->GetLinearGradientWithLength(aIndex, aDefault) : aDefault;
|
||||
}
|
||||
|
||||
nsSVGRadialGradientElement *
|
||||
nsSVGGradientFrame::GetRadialGradientWithLength(PRUint32 aIndex,
|
||||
nsSVGRadialGradientElement* aDefault)
|
||||
{
|
||||
// If this was a radial gradient with the required length, we would have
|
||||
// already found it in nsSVGRadialGradientFrame::GetRadialGradientWithLength.
|
||||
// Since we didn't find the length, continue looking down the chain.
|
||||
|
||||
AutoGradientReferencer gradientRef(this);
|
||||
|
||||
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
||||
return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -289,53 +363,20 @@ nsSVGGradientFrame::GetReferencedGradient()
|
|||
return static_cast<nsSVGGradientFrame*>(result);
|
||||
}
|
||||
|
||||
nsSVGGradientElement *
|
||||
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
|
||||
nsSVGGradientFrame *
|
||||
nsSVGGradientFrame::GetReferencedGradientIfNotInUse()
|
||||
{
|
||||
if (mContent->HasAttr(kNameSpaceID_None, aAttrName))
|
||||
return static_cast<nsSVGGradientElement *>(mContent);
|
||||
nsSVGGradientFrame *referenced = GetReferencedGradient();
|
||||
if (!referenced)
|
||||
return nsnull;
|
||||
|
||||
nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
|
||||
if (referenced->mLoopFlag) {
|
||||
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
||||
NS_WARNING("gradient reference loop detected while inheriting attribute!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsSVGGradientFrame *next = GetReferencedGradient();
|
||||
if (!next)
|
||||
return grad;
|
||||
|
||||
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
|
||||
mLoopFlag = true;
|
||||
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
||||
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
|
||||
"while inheriting attribute!");
|
||||
if (!next->mLoopFlag)
|
||||
grad = next->GetGradientWithAttr(aAttrName, aDefault);
|
||||
mLoopFlag = false;
|
||||
|
||||
return grad;
|
||||
}
|
||||
|
||||
nsSVGGradientElement *
|
||||
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType,
|
||||
nsIContent *aDefault)
|
||||
{
|
||||
if (GetType() == aGradType && mContent->HasAttr(kNameSpaceID_None, aAttrName))
|
||||
return static_cast<nsSVGGradientElement *>(mContent);
|
||||
|
||||
nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
|
||||
|
||||
nsSVGGradientFrame *next = GetReferencedGradient();
|
||||
if (!next)
|
||||
return grad;
|
||||
|
||||
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
|
||||
mLoopFlag = true;
|
||||
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
||||
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
|
||||
"while inheriting attribute!");
|
||||
if (!next->mLoopFlag)
|
||||
grad = next->GetGradientWithAttr(aAttrName, aGradType, aDefault);
|
||||
mLoopFlag = false;
|
||||
|
||||
return grad;
|
||||
return referenced;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
|
@ -359,33 +400,12 @@ nsSVGGradientFrame::GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame)
|
|||
|
||||
// Our gradient element doesn't have stops - try to "inherit" them
|
||||
|
||||
nsSVGGradientFrame *next = GetReferencedGradient();
|
||||
if (!next) {
|
||||
if (aStopFrame)
|
||||
*aStopFrame = nsnull;
|
||||
return 0;
|
||||
}
|
||||
AutoGradientReferencer gradientRef(this);
|
||||
nsSVGGradientFrame* next = GetReferencedGradientIfNotInUse();
|
||||
if (!next)
|
||||
return nsnull;
|
||||
|
||||
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
|
||||
mLoopFlag = true;
|
||||
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
||||
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
|
||||
"while inheriting stop!");
|
||||
if (!next->mLoopFlag)
|
||||
stopCount = next->GetStopFrame(aIndex, aStopFrame);
|
||||
mLoopFlag = false;
|
||||
|
||||
return stopCount;
|
||||
}
|
||||
|
||||
PRUint16
|
||||
nsSVGGradientFrame::GetGradientUnits()
|
||||
{
|
||||
// This getter is called every time the others are called - maybe cache it?
|
||||
|
||||
nsSVGGradientElement *element =
|
||||
GetGradientWithAttr(nsGkAtoms::gradientUnits, mContent);
|
||||
return element->mEnumAttributes[nsSVGGradientElement::GRADIENTUNITS].GetAnimValue();
|
||||
return next->GetStopFrame(aIndex, aStopFrame);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -431,11 +451,16 @@ nsSVGLinearGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||
//----------------------------------------------------------------------
|
||||
|
||||
float
|
||||
nsSVGLinearGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
|
||||
PRUint16 aEnumName)
|
||||
nsSVGLinearGradientFrame::GetLengthValue(PRUint32 aIndex)
|
||||
{
|
||||
nsSVGLinearGradientElement *element =
|
||||
GetLinearGradientWithAttr(aAtomName, mContent);
|
||||
nsSVGLinearGradientElement* lengthElement =
|
||||
GetLinearGradientWithLength(aIndex,
|
||||
static_cast<nsSVGLinearGradientElement *>(mContent));
|
||||
// We passed in mContent as a fallback, so, assuming mContent is non-null, the
|
||||
// return value should also be non-null.
|
||||
NS_ABORT_IF_FALSE(lengthElement,
|
||||
"Got unexpected null element from GetLinearGradientWithLength");
|
||||
const nsSVGLength2 &length = lengthElement->mLengthAttributes[aIndex];
|
||||
|
||||
// Object bounding box units are handled by setting the appropriate
|
||||
// transform in GetGradientTransform, but we need to handle user
|
||||
|
@ -443,15 +468,30 @@ nsSVGLinearGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
|
|||
|
||||
PRUint16 gradientUnits = GetGradientUnits();
|
||||
if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
|
||||
return nsSVGUtils::UserSpace(mSource,
|
||||
&element->mLengthAttributes[aEnumName]);
|
||||
return nsSVGUtils::UserSpace(mSource, &length);
|
||||
}
|
||||
|
||||
NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
||||
"Unknown gradientUnits type");
|
||||
NS_ASSERTION(
|
||||
gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
||||
"Unknown gradientUnits type");
|
||||
|
||||
return element->mLengthAttributes[aEnumName].
|
||||
GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
|
||||
return length.GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
|
||||
}
|
||||
|
||||
nsSVGLinearGradientElement *
|
||||
nsSVGLinearGradientFrame::GetLinearGradientWithLength(PRUint32 aIndex,
|
||||
nsSVGLinearGradientElement* aDefault)
|
||||
{
|
||||
nsSVGLinearGradientElement* thisElement =
|
||||
static_cast<nsSVGLinearGradientElement *>(mContent);
|
||||
const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
|
||||
|
||||
if (length.IsExplicitlySet()) {
|
||||
return thisElement;
|
||||
}
|
||||
|
||||
return nsSVGLinearGradientFrameBase::GetLinearGradientWithLength(aIndex,
|
||||
aDefault);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxPattern>
|
||||
|
@ -459,10 +499,10 @@ nsSVGLinearGradientFrame::CreateGradient()
|
|||
{
|
||||
float x1, y1, x2, y2;
|
||||
|
||||
x1 = GradientLookupAttribute(nsGkAtoms::x1, nsSVGLinearGradientElement::X1);
|
||||
y1 = GradientLookupAttribute(nsGkAtoms::y1, nsSVGLinearGradientElement::Y1);
|
||||
x2 = GradientLookupAttribute(nsGkAtoms::x2, nsSVGLinearGradientElement::X2);
|
||||
y2 = GradientLookupAttribute(nsGkAtoms::y2, nsSVGLinearGradientElement::Y2);
|
||||
x1 = GetLengthValue(nsSVGLinearGradientElement::X1);
|
||||
y1 = GetLengthValue(nsSVGLinearGradientElement::Y1);
|
||||
x2 = GetLengthValue(nsSVGLinearGradientElement::X2);
|
||||
y2 = GetLengthValue(nsSVGLinearGradientElement::Y2);
|
||||
|
||||
gfxPattern *pattern = new gfxPattern(x1, y1, x2, y2);
|
||||
NS_IF_ADDREF(pattern);
|
||||
|
@ -513,17 +553,33 @@ nsSVGRadialGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||
//----------------------------------------------------------------------
|
||||
|
||||
float
|
||||
nsSVGRadialGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
|
||||
PRUint16 aEnumName,
|
||||
nsSVGRadialGradientElement *aElement)
|
||||
nsSVGRadialGradientFrame::GetLengthValue(PRUint32 aIndex)
|
||||
{
|
||||
nsSVGRadialGradientElement *element;
|
||||
nsSVGRadialGradientElement* lengthElement =
|
||||
GetRadialGradientWithLength(aIndex,
|
||||
static_cast<nsSVGRadialGradientElement *>(mContent));
|
||||
// We passed in mContent as a fallback, so, assuming mContent is non-null,
|
||||
// the return value should also be non-null.
|
||||
NS_ABORT_IF_FALSE(lengthElement,
|
||||
"Got unexpected null element from GetRadialGradientWithLength");
|
||||
return GetLengthValueFromElement(aIndex, *lengthElement);
|
||||
}
|
||||
|
||||
if (aElement) {
|
||||
element = aElement;
|
||||
} else {
|
||||
element = GetRadialGradientWithAttr(aAtomName, mContent);
|
||||
}
|
||||
float
|
||||
nsSVGRadialGradientFrame::GetLengthValue(PRUint32 aIndex, float aDefaultValue)
|
||||
{
|
||||
nsSVGRadialGradientElement* lengthElement =
|
||||
GetRadialGradientWithLength(aIndex, nsnull);
|
||||
|
||||
return lengthElement ? GetLengthValueFromElement(aIndex, *lengthElement)
|
||||
: aDefaultValue;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGRadialGradientFrame::GetLengthValueFromElement(PRUint32 aIndex,
|
||||
nsSVGRadialGradientElement& aElement)
|
||||
{
|
||||
const nsSVGLength2 &length = aElement.mLengthAttributes[aIndex];
|
||||
|
||||
// Object bounding box units are handled by setting the appropriate
|
||||
// transform in GetGradientTransform, but we need to handle user
|
||||
|
@ -531,15 +587,30 @@ nsSVGRadialGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
|
|||
|
||||
PRUint16 gradientUnits = GetGradientUnits();
|
||||
if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
|
||||
return nsSVGUtils::UserSpace(mSource,
|
||||
&element->mLengthAttributes[aEnumName]);
|
||||
return nsSVGUtils::UserSpace(mSource, &length);
|
||||
}
|
||||
|
||||
NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
||||
"Unknown gradientUnits type");
|
||||
NS_ASSERTION(
|
||||
gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
||||
"Unknown gradientUnits type");
|
||||
|
||||
return element->mLengthAttributes[aEnumName].
|
||||
GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
|
||||
return length.GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
|
||||
}
|
||||
|
||||
nsSVGRadialGradientElement *
|
||||
nsSVGRadialGradientFrame::GetRadialGradientWithLength(PRUint32 aIndex,
|
||||
nsSVGRadialGradientElement* aDefault)
|
||||
{
|
||||
nsSVGRadialGradientElement* thisElement =
|
||||
static_cast<nsSVGRadialGradientElement *>(mContent);
|
||||
const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
|
||||
|
||||
if (length.IsExplicitlySet()) {
|
||||
return thisElement;
|
||||
}
|
||||
|
||||
return nsSVGRadialGradientFrameBase::GetRadialGradientWithLength(aIndex,
|
||||
aDefault);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxPattern>
|
||||
|
@ -547,21 +618,12 @@ nsSVGRadialGradientFrame::CreateGradient()
|
|||
{
|
||||
float cx, cy, r, fx, fy;
|
||||
|
||||
cx = GradientLookupAttribute(nsGkAtoms::cx, nsSVGRadialGradientElement::CX);
|
||||
cy = GradientLookupAttribute(nsGkAtoms::cy, nsSVGRadialGradientElement::CY);
|
||||
r = GradientLookupAttribute(nsGkAtoms::r, nsSVGRadialGradientElement::R);
|
||||
|
||||
nsSVGRadialGradientElement *gradient;
|
||||
|
||||
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fx, nsnull)))
|
||||
fx = cx; // if fx isn't set, we must use cx
|
||||
else
|
||||
fx = GradientLookupAttribute(nsGkAtoms::fx, nsSVGRadialGradientElement::FX, gradient);
|
||||
|
||||
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fy, nsnull)))
|
||||
fy = cy; // if fy isn't set, we must use cy
|
||||
else
|
||||
fy = GradientLookupAttribute(nsGkAtoms::fy, nsSVGRadialGradientElement::FY, gradient);
|
||||
cx = GetLengthValue(nsSVGRadialGradientElement::CX);
|
||||
cy = GetLengthValue(nsSVGRadialGradientElement::CY);
|
||||
r = GetLengthValue(nsSVGRadialGradientElement::R);
|
||||
// If fx or fy are not set, use cx/cy instead
|
||||
fx = GetLengthValue(nsSVGRadialGradientElement::FX, cx);
|
||||
fy = GetLengthValue(nsSVGRadialGradientElement::FY, cy);
|
||||
|
||||
if (fx != cx || fy != cy) {
|
||||
// The focal point (fFx and fFy) must be clamped to be *inside* - not on -
|
||||
|
|
|
@ -86,45 +86,48 @@ private:
|
|||
// the referenced gradient's frame if available, null otherwise.
|
||||
nsSVGGradientFrame* GetReferencedGradient();
|
||||
|
||||
// Helpers to look at our gradient and then along its reference chain (if any)
|
||||
// to find the first gradient with the specified attribute.
|
||||
// Returns aDefault if no content with that attribute is found
|
||||
nsSVGGradientElement* GetGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault);
|
||||
|
||||
// Some attributes are only valid on one type of gradient, and we *must* get
|
||||
// the right type or we won't have the data structures we require.
|
||||
// Returns aDefault if no content with that attribute is found
|
||||
nsSVGGradientElement* GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType,
|
||||
nsIContent *aDefault);
|
||||
|
||||
// Optionally get a stop frame (returns stop index/count)
|
||||
PRInt32 GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame);
|
||||
|
||||
PRUint16 GetSpreadMethod();
|
||||
PRUint32 GetStopCount();
|
||||
void GetStopInformation(PRInt32 aIndex,
|
||||
float *aOffset, nscolor *aColor, float *aStopOpacity);
|
||||
|
||||
const mozilla::SVGAnimatedTransformList* GetGradientTransformList(
|
||||
nsIContent* aDefault);
|
||||
// Will be singular for gradientUnits="objectBoundingBox" with an empty bbox.
|
||||
gfxMatrix GetGradientTransform(nsIFrame *aSource, const gfxRect *aOverrideBounds);
|
||||
gfxMatrix GetGradientTransform(nsIFrame *aSource,
|
||||
const gfxRect *aOverrideBounds);
|
||||
|
||||
protected:
|
||||
virtual already_AddRefed<gfxPattern> CreateGradient() = 0;
|
||||
|
||||
// Use these inline methods instead of GetGradientWithAttr(..., aGradType)
|
||||
nsSVGLinearGradientElement* GetLinearGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
|
||||
// Internal methods for handling referenced gradients
|
||||
class AutoGradientReferencer;
|
||||
nsSVGGradientFrame* GetReferencedGradientIfNotInUse();
|
||||
|
||||
// Accessors to lookup gradient attributes
|
||||
PRUint16 GetEnumValue(PRUint32 aIndex, nsIContent *aDefault);
|
||||
PRUint16 GetEnumValue(PRUint32 aIndex)
|
||||
{
|
||||
return static_cast<nsSVGLinearGradientElement*>(
|
||||
GetGradientWithAttr(aAttrName, nsGkAtoms::svgLinearGradientFrame, aDefault));
|
||||
return GetEnumValue(aIndex, mContent);
|
||||
}
|
||||
nsSVGRadialGradientElement* GetRadialGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
|
||||
PRUint16 GetGradientUnits()
|
||||
{
|
||||
return static_cast<nsSVGRadialGradientElement*>(
|
||||
GetGradientWithAttr(aAttrName, nsGkAtoms::svgRadialGradientFrame, aDefault));
|
||||
// This getter is called every time the others are called - maybe cache it?
|
||||
return GetEnumValue(nsSVGGradientElement::GRADIENTUNITS);
|
||||
}
|
||||
PRUint16 GetSpreadMethod()
|
||||
{
|
||||
return GetEnumValue(nsSVGGradientElement::SPREADMETHOD);
|
||||
}
|
||||
|
||||
// Get the value of our gradientUnits attribute
|
||||
PRUint16 GetGradientUnits();
|
||||
// Gradient-type-specific lookups since the length values differ between
|
||||
// linear and radial gradients
|
||||
virtual nsSVGLinearGradientElement * GetLinearGradientWithLength(
|
||||
PRUint32 aIndex, nsSVGLinearGradientElement* aDefault);
|
||||
virtual nsSVGRadialGradientElement * GetRadialGradientWithLength(
|
||||
PRUint32 aIndex, nsSVGRadialGradientElement* aDefault);
|
||||
|
||||
// The frame our gradient is (currently) being applied to
|
||||
nsIFrame* mSource;
|
||||
|
@ -178,7 +181,9 @@ public:
|
|||
#endif // DEBUG
|
||||
|
||||
protected:
|
||||
float GradientLookupAttribute(nsIAtom *aAtomName, PRUint16 aEnumName);
|
||||
float GetLengthValue(PRUint32 aIndex);
|
||||
virtual nsSVGLinearGradientElement * GetLinearGradientWithLength(
|
||||
PRUint32 aIndex, nsSVGLinearGradientElement* aDefault);
|
||||
virtual already_AddRefed<gfxPattern> CreateGradient();
|
||||
};
|
||||
|
||||
|
@ -220,8 +225,12 @@ public:
|
|||
#endif // DEBUG
|
||||
|
||||
protected:
|
||||
float GradientLookupAttribute(nsIAtom *aAtomName, PRUint16 aEnumName,
|
||||
nsSVGRadialGradientElement *aElement = nsnull);
|
||||
float GetLengthValue(PRUint32 aIndex);
|
||||
float GetLengthValue(PRUint32 aIndex, float aDefaultValue);
|
||||
float GetLengthValueFromElement(PRUint32 aIndex,
|
||||
nsSVGRadialGradientElement& aElement);
|
||||
virtual nsSVGRadialGradientElement * GetRadialGradientWithLength(
|
||||
PRUint32 aIndex, nsSVGRadialGradientElement* aDefault);
|
||||
virtual already_AddRefed<gfxPattern> CreateGradient();
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче