Bug 544809 - nsSVGPatternFrame::GetPatternWithAttr and callers should take account of SMIL animation, r=longsonr, a=roc

This commit is contained in:
Brian Birtles 2011-01-16 16:36:34 +09:00
Родитель c870c206b2
Коммит 4037072a35
15 изменённых файлов: 519 добавлений и 110 удалений

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

@ -237,6 +237,7 @@ SVGAnimatedPreserveAspectRatio::SetBaseValueString(
}
mBaseVal = val;
mIsBaseSet = PR_TRUE;
if (!mIsAnimated) {
mAnimVal = mBaseVal;
}
@ -281,6 +282,7 @@ SVGAnimatedPreserveAspectRatio::SetBaseAlign(PRUint16 aAlign,
{
nsresult rv = mBaseVal.SetAlign(aAlign);
NS_ENSURE_SUCCESS(rv, rv);
mIsBaseSet = PR_TRUE;
mAnimVal.mAlign = mBaseVal.mAlign;
aSVGElement->DidChangePreserveAspectRatio(PR_TRUE);
@ -299,6 +301,7 @@ SVGAnimatedPreserveAspectRatio::SetBaseMeetOrSlice(PRUint16 aMeetOrSlice,
{
nsresult rv = mBaseVal.SetMeetOrSlice(aMeetOrSlice);
NS_ENSURE_SUCCESS(rv, rv);
mIsBaseSet = PR_TRUE;
mAnimVal.mMeetOrSlice = mBaseVal.mMeetOrSlice;
aSVGElement->DidChangePreserveAspectRatio(PR_TRUE);

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

@ -100,6 +100,7 @@ public:
mBaseVal.mDefer = PR_FALSE;
mAnimVal = mBaseVal;
mIsAnimated = PR_FALSE;
mIsBaseSet = PR_FALSE;
}
nsresult SetBaseValueString(const nsAString& aValue,
@ -117,6 +118,8 @@ public:
{ return mAnimVal; }
PRBool IsAnimated() const
{ return mIsAnimated; }
PRBool IsExplicitlySet() const
{ return mIsAnimated || mIsBaseSet; }
nsresult ToDOMAnimatedPreserveAspectRatio(
nsIDOMSVGAnimatedPreserveAspectRatio **aResult,
@ -131,6 +134,7 @@ private:
SVGPreserveAspectRatio mAnimVal;
SVGPreserveAspectRatio mBaseVal;
PRPackedBool mIsAnimated;
PRPackedBool mIsBaseSet;
nsresult ToDOMBaseVal(nsIDOMSVGPreserveAspectRatio **aResult,
nsSVGElement* aSVGElement);

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

@ -136,6 +136,31 @@ nsSVGAnimatedTransformList::DidModifySVGObservable (nsISVGValue* observable,
return NS_OK;
}
//----------------------------------------------------------------------
// Misc nsSVGAnimatedTransformList methods
PRBool
nsSVGAnimatedTransformList::IsExplicitlySet() const
{
// XXX Dummy implementation until bug 602759 is fixed.
// Like other methods of this name, we need to know when a transform value has
// been explicitly set (either by markup, a DOM call, or animation).
// Given our current implementation, we can say that's the case so long as
// mBaseVal has something in it or mAnimVal exists.
// It's not quite right because, for example, if we have transform="" we
// should probably behave as if the value is set, but for now it will do until
// bug 602759 is fixed.
if (mAnimVal)
return PR_TRUE;
if (!mBaseVal)
return PR_FALSE;
PRUint32 numItems = 0;
nsIDOMSVGTransformList *list = mBaseVal.get();
list->GetNumberOfItems(&numItems);
return numItems > 0;
}
////////////////////////////////////////////////////////////////////////
// Exported creation functions:

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

@ -80,6 +80,8 @@ public:
// nsISupportsWeakReference
// implementation inherited from nsSupportsWeakReference
PRBool IsExplicitlySet() const;
protected:
friend class nsSVGTransformSMILAttr;

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

@ -79,6 +79,7 @@ nsSVGEnum::SetBaseValueString(const nsAString& aValue,
while (mapping && mapping->mKey) {
if (valAtom == *(mapping->mKey)) {
mIsBaseSet = PR_TRUE;
if (mBaseVal != mapping->mVal) {
mBaseVal = mapping->mVal;
if (!mIsAnimated) {
@ -127,6 +128,7 @@ nsSVGEnum::SetBaseValue(PRUint16 aValue,
while (mapping && mapping->mKey) {
if (mapping->mVal == aValue) {
mIsBaseSet = PR_TRUE;
if (mBaseVal != PRUint8(aValue)) {
mBaseVal = PRUint8(aValue);
if (!mIsAnimated) {

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

@ -55,6 +55,7 @@ public:
mAnimVal = mBaseVal = PRUint8(aValue);
mAttrEnum = aAttrEnum;
mIsAnimated = PR_FALSE;
mIsBaseSet = PR_FALSE;
}
nsresult SetBaseValueString(const nsAString& aValue,
@ -72,6 +73,8 @@ public:
void SetAnimValue(PRUint16 aValue, nsSVGElement *aSVGElement);
PRUint16 GetAnimValue() const
{ return mAnimVal; }
PRBool IsExplicitlySet() const
{ return mIsAnimated || mIsBaseSet; }
nsresult ToDOMAnimatedEnum(nsIDOMSVGAnimatedEnumeration **aResult,
nsSVGElement* aSVGElement);
@ -85,6 +88,7 @@ private:
nsSVGEnumValue mBaseVal;
PRUint8 mAttrEnum; // element specified tracking for attribute
PRPackedBool mIsAnimated;
PRPackedBool mIsBaseSet;
nsSVGEnumMapping *GetMapping(nsSVGElement *aSVGElement);

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

@ -97,7 +97,7 @@ public:
// explicitly set by markup or a DOM call), PR_FALSE otherwise.
// If this returns PR_FALSE, the animated value is still valid, that is,
// useable, and represents the default base value of the attribute.
PRBool IsAnimValSet() const
PRBool IsExplicitlySet() const
{ return mIsAnimated || mIsBaseSet; }
nsresult ToDOMAnimatedLength(nsIDOMSVGAnimatedLength **aResult,

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

@ -192,8 +192,8 @@ nsSVGRectElement::ConstructPath(gfxContext *aCtx)
/* If either the 'rx' or the 'ry' attribute isn't set, then we
have to set it to the value of the other. */
PRBool hasRx = mLengthAttributes[RX].IsAnimValSet();
PRBool hasRy = mLengthAttributes[RY].IsAnimValSet();
PRBool hasRx = mLengthAttributes[RX].IsExplicitlySet();
PRBool hasRy = mLengthAttributes[RY].IsExplicitlySet();
if (hasRx && !hasRy)
ry = rx;
else if (hasRy && !hasRx)

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

@ -0,0 +1,103 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 600">
<!-- 1. patternUnits -->
<defs>
<pattern id="patternUnits" width="80" height="80"
patternUnits="userSpaceOnUse">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<rect width="100" height="100" stroke="black" fill="url(#patternUnits)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#patternUnits)"/>
</g>
<!-- 2. patternContentUnits -->
<defs>
<pattern id="patternContentUnits" width="1" height="1"
patternContentUnits="objectBoundingBox">
<rect width="0.5" height="0.5" fill="blue"/>
<rect x="0.5" width="0.5" height="0.5" fill="red"/>
<rect y="0.5" width="0.5" height="0.5" fill="red"/>
<rect x="0.5" y="0.5" width="0.5" height="0.5" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 100)">
<rect width="100" height="100" stroke="black"
fill="url(#patternContentUnits)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black"
fill="url(#patternContentUnits)"/>
</g>
</g>
<!-- 3. patternTransform -->
<defs>
<pattern id="patternTransform" width="1" height="1"
patternTransform="rotate(45 50 50)">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 200)">
<rect width="100" height="100" stroke="black"
fill="url(#patternTransform)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black"
fill="url(#patternTransform)"/>
</g>
</g>
<!-- 4. preserveAspectRatio -->
<defs>
<pattern id="par" width="1" height="1" viewBox="0.1 0.1 0.6 0.85"
preserveAspectRatio="none">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 300)">
<rect width="100" height="100" stroke="black" fill="url(#par)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#par)"/>
</g>
</g>
<!-- 5. viewBox -->
<defs>
<pattern id="viewBox" width="1" height="1" viewBox="0.1 0.1 0.6 0.85"
preserveAspectRatio="none">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 400)">
<rect width="100" height="100" stroke="black" fill="url(#viewBox)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#viewBox)"/>
</g>
</g>
<!-- 6. xlink:href -->
<defs>
<pattern id="xlink" xlink:href="#xlinkRef"/>
<pattern id="xlinkRef" width="1" height="1">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 500)">
<rect width="100" height="100" stroke="black" fill="url(#xlink)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#xlink)"/>
</g>
</g>
<!-- If adding more tests here, be sure to update the viewBox on the root svg
element -->
</svg>

После

Ширина:  |  Высота:  |  Размер: 3.9 KiB

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

@ -0,0 +1,138 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 600">
<!-- Bug 544809 - nsSVGPatternFrame::GetPatternWithAttr and callers should
take account of SMIL animation.
Test animating pattern 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 pattern 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 pattern named (attName) that refers to the
base pattern 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. patternUnits: defaults to objectBoundingBox -->
<defs>
<pattern xlink:href="#patternUnitsRef" id="patternUnits"/>
<pattern id="patternUnitsRef" width="80" height="80">
<set attributeName="patternUnits" to="userSpaceOnUse"/>
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<rect width="100" height="100" stroke="black" fill="url(#patternUnits)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#patternUnitsRef)"/>
</g>
<!-- 2. patternContentUnits: defaults to userSpaceOnUse -->
<defs>
<pattern xlink:href="#patternContentUnitsRef" id="patternContentUnits"/>
<pattern id="patternContentUnitsRef" width="1" height="1">
<set attributeName="patternContentUnits" to="objectBoundingBox"/>
<rect width="0.5" height="0.5" fill="blue"/>
<rect x="0.5" width="0.5" height="0.5" fill="red"/>
<rect y="0.5" width="0.5" height="0.5" fill="red"/>
<rect x="0.5" y="0.5" width="0.5" height="0.5" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 100)">
<rect width="100" height="100" stroke="black"
fill="url(#patternContentUnits)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black"
fill="url(#patternContentUnitsRef)"/>
</g>
</g>
<!-- 3. patternTransform: defaults to identity -->
<defs>
<pattern xlink:href="#patternTransformRef" id="patternTransform"/>
<pattern id="patternTransformRef" width="1" height="1">
<animateTransform attributeName="patternTransform" type="rotate"
values="45 50 50" fill="freeze"/>
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 200)">
<rect width="100" height="100" stroke="black"
fill="url(#patternTransform)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black"
fill="url(#patternTransformRef)"/>
</g>
</g>
<!-- 4. preserveAspectRatio: defaults to xMidYMid meet -->
<defs>
<pattern xlink:href="#parRef" id="par"/>
<pattern id="parRef" width="1" height="1" viewBox="0.1 0.1 0.6 0.85">
<set attributeName="preserveAspectRatio" to="none"/>
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 300)">
<rect width="100" height="100" stroke="black" fill="url(#par)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#parRef)"/>
</g>
</g>
<!-- 5. viewBox -->
<defs>
<pattern xlink:href="#viewBoxRef" id="viewBox"/>
<pattern id="viewBoxRef" width="1" height="1"
preserveAspectRatio="none">
<set attributeName="viewBox" to="0.1 0.1 0.6 0.85"/>
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 400)">
<rect width="100" height="100" stroke="black" fill="url(#viewBox)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#viewBoxRef)"/>
</g>
</g>
<!-- 6. xlink:href
This attribute is not affected by bug 544809, i.e. it doesn't use
nsSVGPatternFrame::GetPatternWithAttr, but we test it here for completeness
-->
<defs>
<pattern id="xlink">
<set attributeName="xlink:href" to="#xlinkRef"/>
</pattern>
<pattern id="xlinkRef" width="1" height="1">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 500)">
<rect width="100" height="100" stroke="black" fill="url(#xlink)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#xlinkRef)"/>
</g>
</g>
<!-- If adding more tests here, be sure to update the viewBox on the root svg
element -->
</svg>

После

Ширина:  |  Высота:  |  Размер: 5.8 KiB

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

@ -0,0 +1,35 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200">
<!-- 1. x, y -->
<defs>
<pattern id="xy" width="1" height="1" x="0.1" y="-0.1">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g>
<rect width="100" height="100" stroke="black" fill="url(#xy)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#xy)"/>
</g>
</g>
<!-- 2. width, height -->
<defs>
<pattern id="widthHeight" width="1" height="1">
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 100)">
<rect width="100" height="100" stroke="black" fill="url(#widthHeight)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#widthHeight)"/>
</g>
</g>
<!-- If adding more tests here, be sure to update the viewBox on the root svg
element -->
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.3 KiB

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

@ -0,0 +1,52 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200">
<!-- Bug 544809 - nsSVGPatternFrame::GetPatternWithAttr and callers should
take account of SMIL animation.
This test is a continuation of anim-pattern-attr-presence-01.svg but is
separated because it currently fails due to bug 621651. Once that bug is
resolved the tests in this file should be merged into
anim-pattern-attr-presence-01.svg
-->
<!-- 1. x, y: defaults to 0 -->
<!-- Currently broken by bug 621651 -->
<defs>
<pattern xlink:href="#xyRef" id="xy"/>
<pattern id="xyRef" width="1" height="1">
<set attributeName="x" to="0.1"/>
<set attributeName="y" to="-0.1"/>
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g>
<rect width="100" height="100" stroke="black" fill="url(#xy)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black" fill="url(#xyRef)"/>
</g>
</g>
<!-- 2. width, height: defaults to 0 (disables rendering) -->
<!-- Currently broken by bug 621651 -->
<defs>
<pattern xlink:href="#widthHeightRef" id="widthHeight"/>
<pattern id="widthHeightRef">
<set attributeName="width" to="1"/>
<set attributeName="height" to="1"/>
<rect width="50" height="50" fill="blue"/>
<rect x="50" width="50" height="50" fill="red"/>
<rect y="50" width="50" height="50" fill="red"/>
<rect x="50" y="50" width="50" height="50" fill="blue"/>
</pattern>
</defs>
<g transform="translate(0 100)">
<rect width="100" height="100" stroke="black" fill="url(#widthHeight)"/>
<g transform="translate(100)">
<rect width="100" height="100" stroke="black"
fill="url(#widthHeightRef)"/>
</g>
</g>
<!-- If adding more tests here, be sure to update the viewBox on the root svg
element -->
</svg>

После

Ширина:  |  Высота:  |  Размер: 2.1 KiB

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

@ -197,7 +197,11 @@ random == anim-text-x-y-dx-dy-01.svg anim-text-x-y-dx-dy-01-ref.svg # bug 579588
== anim-y-interp-5.svg anim-y-interp-5-ref.svg
== anim-y-interp-6.svg anim-y-interp-6-ref.svg
# Test we don't rely on HasAttr to see if an attribute has been set
== anim-rect-rxry-1.svg anim-rect-rxry-1-ref.svg
== 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
== api-sanity-1.svg lime.svg

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

@ -51,6 +51,7 @@
#include "nsSVGPatternElement.h"
#include "nsSVGGeometryFrame.h"
#include "nsSVGPatternFrame.h"
#include "nsSVGAnimatedTransformList.h"
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "gfxPattern.h"
@ -58,6 +59,27 @@
using namespace mozilla;
//----------------------------------------------------------------------
// Helper classes
class nsSVGPatternFrame::AutoPatternReferencer
{
public:
AutoPatternReferencer(nsSVGPatternFrame *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 = PR_TRUE;
}
~AutoPatternReferencer() {
mFrame->mLoopFlag = PR_FALSE;
}
private:
nsSVGPatternFrame *mFrame;
};
//----------------------------------------------------------------------
// Implementation
@ -331,48 +353,64 @@ nsSVGPatternFrame::GetPatternFirstChild(nsIFrame **kid)
return NS_OK;
// No, see if we chain to someone who does
nsSVGPatternFrame *next = GetReferencedPattern();
AutoPatternReferencer patternRef(this);
mLoopFlag = PR_TRUE;
if (!next || next->mLoopFlag) {
mLoopFlag = PR_FALSE;
nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
if (!next)
return NS_ERROR_FAILURE;
}
nsresult rv = next->GetPatternFirstChild(kid);
mLoopFlag = PR_FALSE;
return rv;
return next->GetPatternFirstChild(kid);
}
PRUint16
nsSVGPatternFrame::GetPatternUnits()
nsSVGPatternFrame::GetEnumValue(PRUint32 aIndex, nsIContent *aDefault)
{
// See if we need to get the value from another pattern
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::patternUnits, mContent);
return patternElement->mEnumAttributes[nsSVGPatternElement::PATTERNUNITS].GetAnimValue();
nsSVGEnum& thisEnum =
static_cast<nsSVGPatternElement *>(mContent)->mEnumAttributes[aIndex];
if (thisEnum.IsExplicitlySet())
return thisEnum.GetAnimValue();
AutoPatternReferencer patternRef(this);
nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
return next ? next->GetEnumValue(aIndex, aDefault) :
static_cast<nsSVGPatternElement *>(aDefault)->
mEnumAttributes[aIndex].GetAnimValue();
}
PRUint16
nsSVGPatternFrame::GetPatternContentUnits()
nsIDOMSVGAnimatedTransformList*
nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
{
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::patternContentUnits, mContent);
return patternElement->mEnumAttributes[nsSVGPatternElement::PATTERNCONTENTUNITS].GetAnimValue();
nsIDOMSVGAnimatedTransformList *thisTransformList =
static_cast<nsSVGPatternElement *>(mContent)->mPatternTransform.get();
// XXX We should be able to do something cleaner than this casting once
// bug 602759 is fixed and we have a proper animated transform list class
const nsSVGAnimatedTransformList *thisListAsConcreteType =
static_cast<const nsSVGAnimatedTransformList *>(thisTransformList);
if (thisListAsConcreteType && thisListAsConcreteType->IsExplicitlySet())
return thisTransformList;
AutoPatternReferencer patternRef(this);
nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
return next ? next->GetPatternTransformList(aDefault) :
static_cast<nsSVGPatternElement *>(aDefault)->mPatternTransform.get();
}
gfxMatrix
nsSVGPatternFrame::GetPatternTransform()
{
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::patternTransform, mContent);
nsIDOMSVGAnimatedTransformList* transformList =
GetPatternTransformList(mContent);
static const gfxMatrix identityMatrix;
if (!patternElement->mPatternTransform) {
if (!transformList) {
return identityMatrix;
}
nsCOMPtr<nsIDOMSVGTransformList> lTrans;
patternElement->mPatternTransform->GetAnimVal(getter_AddRefs(lTrans));
transformList->GetAnimVal(getter_AddRefs(lTrans));
nsCOMPtr<nsIDOMSVGMatrix> patternTransform =
nsSVGTransformList::GetConsolidationMatrix(lTrans);
if (!patternTransform) {
@ -382,49 +420,51 @@ nsSVGPatternFrame::GetPatternTransform()
}
const nsSVGViewBox &
nsSVGPatternFrame::GetViewBox()
nsSVGPatternFrame::GetViewBox(nsIContent* aDefault)
{
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::viewBox, mContent);
const nsSVGViewBox &thisViewBox =
static_cast<nsSVGPatternElement *>(mContent)->mViewBox;
return patternElement->mViewBox;
if (thisViewBox.IsValid())
return thisViewBox;
AutoPatternReferencer patternRef(this);
nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
return next ? next->GetViewBox(aDefault) :
static_cast<nsSVGPatternElement *>(aDefault)->mViewBox;
}
const SVGAnimatedPreserveAspectRatio &
nsSVGPatternFrame::GetPreserveAspectRatio()
nsSVGPatternFrame::GetPreserveAspectRatio(nsIContent *aDefault)
{
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::preserveAspectRatio, mContent);
const SVGAnimatedPreserveAspectRatio &thisPar =
static_cast<nsSVGPatternElement *>(mContent)->mPreserveAspectRatio;
return patternElement->mPreserveAspectRatio;
if (thisPar.IsExplicitlySet())
return thisPar;
AutoPatternReferencer patternRef(this);
nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
return next ? next->GetPreserveAspectRatio(aDefault) :
static_cast<nsSVGPatternElement *>(aDefault)->mPreserveAspectRatio;
}
const nsSVGLength2 *
nsSVGPatternFrame::GetX()
nsSVGPatternFrame::GetLengthValue(PRUint32 aIndex, nsIContent *aDefault)
{
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::x, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::X];
}
const nsSVGLength2 *thisLength =
&static_cast<nsSVGPatternElement *>(mContent)->mLengthAttributes[aIndex];
const nsSVGLength2 *
nsSVGPatternFrame::GetY()
{
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::y, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::Y];
}
if (thisLength->IsExplicitlySet())
return thisLength;
const nsSVGLength2 *
nsSVGPatternFrame::GetWidth()
{
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::width, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::WIDTH];
}
AutoPatternReferencer patternRef(this);
const nsSVGLength2 *
nsSVGPatternFrame::GetHeight()
{
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::height, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::HEIGHT];
nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
return next ? next->GetLengthValue(aIndex, aDefault) :
&static_cast<nsSVGPatternElement *>(aDefault)->mLengthAttributes[aIndex];
}
// Private (helper) methods
@ -470,33 +510,20 @@ nsSVGPatternFrame::GetReferencedPattern()
return static_cast<nsSVGPatternFrame*>(result);
}
nsSVGPatternElement *
nsSVGPatternFrame::GetPatternWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
nsSVGPatternFrame *
nsSVGPatternFrame::GetReferencedPatternIfNotInUse()
{
// XXX TODO: this method needs to take account of SMIL animation, since it
// the requested attribute may be animated even if it is not set in the DOM.
// The callers also need to be fixed up to then ask for the right thing from
// the pattern we return! Do we neet to call mContent->FlushAnimations()?
nsSVGPatternFrame *referenced = GetReferencedPattern();
if (!referenced)
return nsnull;
if (mContent->HasAttr(kNameSpaceID_None, aAttrName))
return static_cast<nsSVGPatternElement *>(mContent);
if (referenced->mLoopFlag) {
// XXXjwatt: we should really send an error to the JavaScript Console here:
NS_WARNING("pattern reference loop detected while inheriting attribute!");
return nsnull;
}
nsSVGPatternElement *pattern = static_cast<nsSVGPatternElement *>(aDefault);
nsSVGPatternFrame *next = GetReferencedPattern();
if (!next)
return pattern;
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
mLoopFlag = PR_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)
pattern = next->GetPatternWithAttr(aAttrName, aDefault);
mLoopFlag = PR_FALSE;
return pattern;
return referenced;
}
// -------------------------------------------------------------------------
@ -509,17 +536,17 @@ nsSVGPatternFrame::GetPatternRect(const gfxRect &aTargetBBox,
nsIFrame *aTarget)
{
// Get our type
PRUint16 type = GetPatternUnits();
PRUint16 type = GetEnumValue(nsSVGPatternElement::PATTERNUNITS);
// We need to initialize our box
float x,y,width,height;
// Get the pattern x,y,width, and height
const nsSVGLength2 *tmpX, *tmpY, *tmpHeight, *tmpWidth;
tmpX = GetX();
tmpY = GetY();
tmpHeight = GetHeight();
tmpWidth = GetWidth();
tmpX = GetLengthValue(nsSVGPatternElement::X);
tmpY = GetLengthValue(nsSVGPatternElement::Y);
tmpHeight = GetLengthValue(nsSVGPatternElement::HEIGHT);
tmpWidth = GetLengthValue(nsSVGPatternElement::WIDTH);
if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
x = nsSVGUtils::ObjectSpace(aTargetBBox, tmpX);
@ -547,7 +574,7 @@ nsSVGPatternFrame::ConstructCTM(const gfxRect &callerBBox,
nsIContent* targetContent = aTarget->GetContent();
// The objectBoundingBox conversion must be handled in the CTM:
if (GetPatternContentUnits() ==
if (GetEnumValue(nsSVGPatternElement::PATTERNCONTENTUNITS) ==
nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
tCTM.Scale(callerBBox.Width(), callerBBox.Height());
} else {
@ -569,16 +596,20 @@ nsSVGPatternFrame::ConstructCTM(const gfxRect &callerBBox,
// If we're dealing with an SVG target only retrieve the context once.
// Calling the nsIFrame* variant of GetAnimValue would look it up on
// every call.
viewportWidth = GetWidth()->GetAnimValue(ctx);
viewportHeight = GetHeight()->GetAnimValue(ctx);
refX = GetX()->GetAnimValue(ctx);
refY = GetY()->GetAnimValue(ctx);
viewportWidth =
GetLengthValue(nsSVGPatternElement::WIDTH)->GetAnimValue(ctx);
viewportHeight =
GetLengthValue(nsSVGPatternElement::HEIGHT)->GetAnimValue(ctx);
refX = GetLengthValue(nsSVGPatternElement::X)->GetAnimValue(ctx);
refY = GetLengthValue(nsSVGPatternElement::Y)->GetAnimValue(ctx);
} else {
// No SVG target, call the nsIFrame* variant of GetAnimValue.
viewportWidth = GetWidth()->GetAnimValue(aTarget);
viewportHeight = GetHeight()->GetAnimValue(aTarget);
refX = GetX()->GetAnimValue(aTarget);
refY = GetY()->GetAnimValue(aTarget);
viewportWidth =
GetLengthValue(nsSVGPatternElement::WIDTH)->GetAnimValue(aTarget);
viewportHeight =
GetLengthValue(nsSVGPatternElement::HEIGHT)->GetAnimValue(aTarget);
refX = GetLengthValue(nsSVGPatternElement::X)->GetAnimValue(aTarget);
refY = GetLengthValue(nsSVGPatternElement::Y)->GetAnimValue(aTarget);
}
gfxMatrix viewBoxTM = nsSVGUtils::GetViewBoxTransform(patternElement,
viewportWidth, viewportHeight,
@ -605,7 +636,7 @@ nsSVGPatternFrame::GetPatternMatrix(const gfxRect &bbox,
float minx = bbox.X();
float miny = bbox.Y();
PRUint16 type = GetPatternContentUnits();
PRUint16 type = GetEnumValue(nsSVGPatternElement::PATTERNCONTENTUNITS);
if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
minx += callerBBox.X();
miny += callerBBox.Y();
@ -627,7 +658,7 @@ nsSVGPatternFrame::GetTargetGeometry(gfxMatrix *aCTM,
*aBBox = aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aTarget);
// Sanity check
PRUint16 type = GetPatternUnits();
PRUint16 type = GetEnumValue(nsSVGPatternElement::PATTERNUNITS);
if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
if (aBBox->Width() <= 0 || aBBox->Height() <= 0) {
return NS_ERROR_FAILURE;

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

@ -110,25 +110,31 @@ public:
protected:
// Internal methods for handling referenced patterns
class AutoPatternReferencer;
nsSVGPatternFrame* GetReferencedPattern();
// Helper to look at our pattern and then along its reference chain (if any)
// to find the first pattern with the specified attribute. Returns
// null if there isn't one.
nsSVGPatternElement* GetPatternWithAttr(nsIAtom *aAttrName, nsIContent *aDefault);
nsSVGPatternFrame* GetReferencedPatternIfNotInUse();
//
const nsSVGLength2 *GetX();
const nsSVGLength2 *GetY();
const nsSVGLength2 *GetWidth();
const nsSVGLength2 *GetHeight();
PRUint16 GetPatternUnits();
PRUint16 GetPatternContentUnits();
// Accessors to lookup pattern attributes
PRUint16 GetEnumValue(PRUint32 aIndex, nsIContent *aDefault);
PRUint16 GetEnumValue(PRUint32 aIndex)
{
return GetEnumValue(aIndex, mContent);
}
nsIDOMSVGAnimatedTransformList* GetPatternTransformList(nsIContent* aDefault);
gfxMatrix GetPatternTransform();
const nsSVGViewBox &GetViewBox();
const SVGAnimatedPreserveAspectRatio &GetPreserveAspectRatio();
const nsSVGViewBox &GetViewBox(nsIContent *aDefault);
const nsSVGViewBox &GetViewBox() { return GetViewBox(mContent); }
const SVGAnimatedPreserveAspectRatio &GetPreserveAspectRatio(
nsIContent *aDefault);
const SVGAnimatedPreserveAspectRatio &GetPreserveAspectRatio()
{
return GetPreserveAspectRatio(mContent);
}
const nsSVGLength2 *GetLengthValue(PRUint32 aIndex, nsIContent *aDefault);
const nsSVGLength2 *GetLengthValue(PRUint32 aIndex)
{
return GetLengthValue(aIndex, mContent);
}
nsresult PaintPattern(gfxASurface **surface,
gfxMatrix *patternMatrix,