From 5e8bf8ecda29652b4dcc93b0a94e1f265d0422dc Mon Sep 17 00:00:00 2001 From: "tor%cs.brown.edu" Date: Wed, 9 Mar 2005 19:24:18 +0000 Subject: [PATCH] Bug 276316 - gradients should be "live". Patch by scootermorris@comcast.net, r=afri. --- content/svg/content/src/nsISVGValue.h | 3 +- layout/svg/base/src/Makefile.in | 1 + layout/svg/base/src/nsSVGGlyphFrame.cpp | 143 +++- layout/svg/base/src/nsSVGGradient.h | 14 +- layout/svg/base/src/nsSVGGradientFrame.cpp | 707 ++++++++++++------ layout/svg/base/src/nsSVGGradientFrame.h | 14 +- .../svg/base/src/nsSVGPathGeometryFrame.cpp | 92 ++- layout/svg/base/src/nsSVGPathGeometryFrame.h | 3 + layout/svg/base/src/nsSVGStopFrame.cpp | 108 +++ 9 files changed, 783 insertions(+), 302 deletions(-) create mode 100644 layout/svg/base/src/nsSVGStopFrame.cpp diff --git a/content/svg/content/src/nsISVGValue.h b/content/svg/content/src/nsISVGValue.h index bdc083ec6c5..b42baed1abb 100644 --- a/content/svg/content/src/nsISVGValue.h +++ b/content/svg/content/src/nsISVGValue.h @@ -67,7 +67,8 @@ class nsISVGValue : public nsISupports public: enum modificationType { mod_other = 0, - mod_context + mod_context, + mod_die }; NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISVGVALUE_IID) diff --git a/layout/svg/base/src/Makefile.in b/layout/svg/base/src/Makefile.in index 29233d9ecea..d4f53b5e32d 100644 --- a/layout/svg/base/src/Makefile.in +++ b/layout/svg/base/src/Makefile.in @@ -85,6 +85,7 @@ CPPSRCS = \ nsSVGPolygonFrame.cpp \ nsSVGPolylineFrame.cpp \ nsSVGRectFrame.cpp \ + nsSVGStopFrame.cpp \ nsSVGTSpanFrame.cpp \ nsSVGTextFrame.cpp \ nsSVGUseFrame.cpp \ diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index effdf0ce220..b6bb7e5098f 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -49,7 +49,8 @@ #include "nsISVGRendererRegion.h" #include "nsISVGContainerFrame.h" #include "nsISVGTextContainerFrame.h" -#include "nsSVGGradientFrame.h" +#include "nsSVGGradient.h" +#include "nsISVGValueUtils.h" #include "nsReadableUtils.h" #include "nsCRT.h" #include "prdtoa.h" @@ -66,6 +67,8 @@ typedef nsFrame nsSVGGlyphFrameBase; class nsSVGGlyphFrame : public nsSVGGlyphFrameBase, + public nsISVGValueObserver, + public nsSupportsWeakReference, public nsISVGGlyphGeometrySource, // : nsISVGGlyphMetricsSource : nsISVGGeometrySource public nsISVGGlyphFragmentLeaf, // : nsISVGGlyphFragmentNode public nsISVGChildFrame @@ -104,6 +107,12 @@ public: NS_IMETHOD GetSelected(PRBool *aSelected) const; NS_IMETHOD IsSelectable(PRBool* aIsSelectable, PRUint8* aSelectStyle); + // nsISVGValueObserver + NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable, + nsISVGValue::modificationType aModType); + NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable, + nsISVGValue::modificationType aModType); + // nsISVGChildFrame interface: NS_IMETHOD Paint(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips); NS_IMETHOD GetFrameForPoint(float x, float y, nsIFrame** hit); @@ -157,15 +166,18 @@ protected: nsISVGOuterSVGFrame *GetOuterSVGFrame(); nsISVGTextFrame *GetTextFrame(); void TransformPoint(float& x, float& y); + NS_IMETHOD Update(PRUint32 aFlags); nsCOMPtr mGeometry; nsCOMPtr mMetrics; float mX, mY; - PRUint32 mCharOffset; PRUint32 mGeometryUpdateFlags; PRUint32 mMetricsUpdateFlags; + PRUint32 mCharOffset; PRBool mFragmentTreeDirty; nsString mCharacterData; + nsCOMPtr mFillGradient; + nsCOMPtr mStrokeGradient; }; //---------------------------------------------------------------------- @@ -204,7 +216,12 @@ nsSVGGlyphFrame::nsSVGGlyphFrame() nsSVGGlyphFrame::~nsSVGGlyphFrame() { - + if (mFillGradient) { + NS_ADD_SVGVALUE_OBSERVER(mFillGradient); + } + if (mStrokeGradient) { + NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient); + } } @@ -217,6 +234,8 @@ NS_INTERFACE_MAP_BEGIN(nsSVGGlyphFrame) NS_INTERFACE_MAP_ENTRY(nsISVGGlyphGeometrySource) NS_INTERFACE_MAP_ENTRY(nsISVGGlyphFragmentLeaf) NS_INTERFACE_MAP_ENTRY(nsISVGGlyphFragmentNode) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver) NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame) NS_INTERFACE_MAP_END_INHERITING(nsSVGGlyphFrameBase) @@ -263,9 +282,15 @@ NS_IMETHODIMP nsSVGGlyphFrame::CharacterDataChanged(nsPresContext* aPresContext, nsIContent* aChild, PRBool aAppend) +{ + return Update(nsISVGGeometrySource::UPDATEMASK_ALL); +} + +NS_IMETHODIMP +nsSVGGlyphFrame::Update(PRUint32 aFlags) { #ifdef DEBUG -// printf("** nsSVGGlyphFrame::CharacterDataChanged\n"); +// printf("** nsSVGGlyphFrame::Update\n"); #endif nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame(); if (!outerSVGFrame) { @@ -275,8 +300,8 @@ nsSVGGlyphFrame::CharacterDataChanged(nsPresContext* aPresContext, outerSVGFrame->SuspendRedraw(); UpdateFragmentTree(); - UpdateMetrics(nsISVGGeometrySource::UPDATEMASK_ALL); - UpdateGeometry(nsISVGGeometrySource::UPDATEMASK_ALL); + UpdateMetrics(aFlags); + UpdateGeometry(aFlags); outerSVGFrame->UnsuspendRedraw(); return NS_OK; @@ -285,7 +310,18 @@ nsSVGGlyphFrame::CharacterDataChanged(nsPresContext* aPresContext, NS_IMETHODIMP nsSVGGlyphFrame::DidSetStyleContext(nsPresContext* aPresContext) { - return CharacterDataChanged(aPresContext, NULL, PR_FALSE); + // One of the styles that might have been changed are the urls that + // point to gradients, etc. Drop our cached values to those + if (mFillGradient) { + NS_ADD_SVGVALUE_OBSERVER(mFillGradient); + mFillGradient = nsnull; + } + if (mStrokeGradient) { + NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient); + mStrokeGradient = nsnull; + } + + return CharacterDataChanged(aPresContext, nsnull, PR_FALSE); } NS_IMETHODIMP @@ -339,6 +375,44 @@ nsSVGGlyphFrame::IsSelectable(PRBool* aIsSelectable, return rv; } +//---------------------------------------------------------------------- +// nsISVGValueObserver methods: + +NS_IMETHODIMP +nsSVGGlyphFrame::WillModifySVGObservable(nsISVGValue* observable, + nsISVGValue::modificationType aModType) +{ + return NS_OK; +} + + +NS_IMETHODIMP +nsSVGGlyphFrame::DidModifySVGObservable (nsISVGValue* observable, + nsISVGValue::modificationType aModType) +{ + // Is this a gradient? + nsCOMPtrval = do_QueryInterface(observable); + if (val) { + // Yes, we need to handle this differently + nsCOMPtrfill = do_QueryInterface(mFillGradient); + if (fill == val) { + if (aModType == nsISVGValue::mod_die) { + mFillGradient = nsnull; + } + return Update(nsISVGGeometrySource::UPDATEMASK_FILL_PAINT); + } else { + // No real harm in assuming a stroke gradient at this point + if (aModType == nsISVGValue::mod_die) { + mStrokeGradient = nsnull; + } + return Update(nsISVGGeometrySource::UPDATEMASK_STROKE_PAINT); + } + } else { + // No, all of our other observables update the canvastm by default + return Update(nsISVGGeometrySource::UPDATEMASK_CANVAS_TM); + } + return NS_OK; +} //---------------------------------------------------------------------- // nsISVGChildFrame methods @@ -418,19 +492,7 @@ nsSVGGlyphFrame::GetCoveredRegion() NS_IMETHODIMP nsSVGGlyphFrame::InitialUpdate() { - nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame(); - if (!outerSVGFrame) { - NS_ERROR("No outerSVGFrame"); - return NS_ERROR_FAILURE; - } - - outerSVGFrame->SuspendRedraw(); - UpdateFragmentTree(); - UpdateMetrics(nsISVGGeometrySource::UPDATEMASK_ALL); - UpdateGeometry(nsISVGGeometrySource::UPDATEMASK_ALL); - outerSVGFrame->UnsuspendRedraw(); - - return NS_OK; + return Update(nsISVGGeometrySource::UPDATEMASK_ALL); } NS_IMETHODIMP @@ -660,12 +722,19 @@ nsSVGGlyphFrame::GetStrokePaint(nscolor *aStrokePaint) NS_IMETHODIMP nsSVGGlyphFrame::GetStrokeGradient(nsISVGGradient **aGrad) { - nsIURI *aServer; - aServer = GetStyleSVG()->mStroke.mPaint.mPaintServer; - if (aServer == nsnull) - return NS_ERROR_FAILURE; - // Now have the URI. Get the gradient - return NS_GetSVGGradient(aGrad, aServer, mContent, nsSVGGlyphFrameBase::GetPresContext()->PresShell()); + nsresult rv = NS_OK; + if (!mStrokeGradient) { + nsIURI *aServer; + aServer = GetStyleSVG()->mStroke.mPaint.mPaintServer; + if (aServer == nsnull) + return NS_ERROR_FAILURE; + // Now have the URI. Get the gradient + rv = NS_GetSVGGradient(getter_AddRefs(mStrokeGradient), aServer, mContent, + nsSVGGlyphFrameBase::GetPresContext()->PresShell()); + NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient); + } + *aGrad = mStrokeGradient; + return rv; } /* readonly attribute unsigned short fillPaintType; */ @@ -684,19 +753,25 @@ nsSVGGlyphFrame::GetFillPaint(nscolor *aFillPaint) return NS_OK; } -/* [noscript] void GetStrokeGradient(nsISVGGradient **aGrad); */ +/* [noscript] void GetFillGradient(nsISVGGradient **aGrad); */ NS_IMETHODIMP nsSVGGlyphFrame::GetFillGradient(nsISVGGradient **aGrad) { - nsIURI *aServer; - aServer = GetStyleSVG()->mFill.mPaint.mPaintServer; - if (aServer == nsnull) - return NS_ERROR_FAILURE; - // Now have the URI. Get the gradient - return NS_GetSVGGradient(aGrad, aServer, mContent, nsSVGGlyphFrameBase::GetPresContext()->PresShell()); + nsresult rv = NS_OK; + if (!mFillGradient) { + nsIURI *aServer; + aServer = GetStyleSVG()->mFill.mPaint.mPaintServer; + if (aServer == nsnull) + return NS_ERROR_FAILURE; + // Now have the URI. Get the gradient + rv = NS_GetSVGGradient(getter_AddRefs(mFillGradient), aServer, mContent, + nsSVGGlyphFrameBase::GetPresContext()->PresShell()); + NS_ADD_SVGVALUE_OBSERVER(mFillGradient); + } + *aGrad = mFillGradient; + return rv; } - /* [noscript] boolean isClipChild; */ NS_IMETHODIMP nsSVGGlyphFrame::IsClipChild(PRBool *_retval) diff --git a/layout/svg/base/src/nsSVGGradient.h b/layout/svg/base/src/nsSVGGradient.h index d9341fe7058..d499a14e80b 100644 --- a/layout/svg/base/src/nsSVGGradient.h +++ b/layout/svg/base/src/nsSVGGradient.h @@ -43,6 +43,18 @@ #include "nsIURI.h" #include "nsIContent.h" -nsresult NS_NewSVGGradient(nsISVGGradient **result, nsIURI *uri, nsIContent *aContent); +nsresult NS_GetSVGGradient(nsISVGGradient** result, + nsIURI* aURI, + nsIContent* aContent, + nsIPresShell* aPresShell); + +nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, + nsIContent* aContent, + nsIFrame** aNewFrame); + +nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, + nsIContent* aContent, + nsIFrame** aNewFrame); + #endif // __NS_SVGGRADIENT_H__ diff --git a/layout/svg/base/src/nsSVGGradientFrame.cpp b/layout/svg/base/src/nsSVGGradientFrame.cpp index d3bb5474348..5656d869b92 100644 --- a/layout/svg/base/src/nsSVGGradientFrame.cpp +++ b/layout/svg/base/src/nsSVGGradientFrame.cpp @@ -37,39 +37,45 @@ * ***** END LICENSE BLOCK ***** */ #include "nsContainerFrame.h" -#include "nsSVGGradientFrame.h" +#include "nsSVGGradient.h" #include "nsWeakReference.h" #include "nsIDOMDocument.h" #include "nsIDocument.h" #include "nsIDOMSVGStopElement.h" #include "nsSVGAtoms.h" -#include "nsIDOMSVGAnimatedLength.h" #include "nsIDOMSVGLength.h" +#include "nsIDOMSVGAnimatedEnum.h" +#include "nsIDOMSVGAnimatedLength.h" #include "nsIDOMSVGAnimatedNumber.h" #include "nsIDOMSVGAnimatedString.h" -#include "nsIDOMSVGAnimatedEnum.h" #include "nsIDOMSVGAnimTransformList.h" #include "nsIDOMSVGTransformList.h" #include "nsIDOMSVGNumber.h" #include "nsIDOMSVGGradientElement.h" #include "nsIDOMSVGURIReference.h" #include "nsISVGValue.h" -#include "nsISVGValueObserver.h" +#include "nsISVGValueUtils.h" #include "nsStyleContext.h" +#include "nsISVGValueObserver.h" +#include "nsSVGValue.h" #include "nsNetUtil.h" #include "nsINameSpaceManager.h" #include "nsISVGChildFrame.h" #include "nsIDOMSVGRect.h" #include "nsSVGMatrix.h" #include "nsISVGGeometrySource.h" - -nsresult NS_NewSVGGenericContainerFrame(nsIPresShell *aPresShell, nsIContent *aContent, nsIFrame **aNewFrame); -static nsresult GetSVGGradient(nsISVGGradient **result, nsCAutoString& aSpec, - nsIContent *aContent, nsIPresShell *aPresShell); - -typedef nsContainerFrame nsSVGGradientFrameBase; +#include "nsISVGGradient.h" +#include "nsIURI.h" +#include "nsIContent.h" +#include "nsSVGNumber.h" +#include "nsIDOMSVGStopElement.h" + +typedef nsContainerFrame nsSVGGradientFrameBase; class nsSVGGradientFrame : public nsSVGGradientFrameBase, + public nsSVGValue, + public nsISVGValueObserver, + public nsSupportsWeakReference, public nsISVGGradient { protected: @@ -94,9 +100,6 @@ protected: public: // nsISupports interface: - // NS_DECL_ISUPPORTS - - // nsISupports interface: NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } @@ -104,65 +107,207 @@ public: // nsISVGGradient interface: NS_DECL_NSISVGGRADIENT - // Add destructor that releases all stop elements + // nsISVGValue interface: + NS_IMETHOD SetValueString(const nsAString &aValue) { return NS_OK; } + NS_IMETHOD GetValueString(nsAString& aValue) { return NS_ERROR_NOT_IMPLEMENTED; } + + // nsISVGValueObserver interface: + NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable, + nsISVGValue::modificationType aModType); + NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable, + nsISVGValue::modificationType aModType); + + // nsIFrame interface: + NS_IMETHOD DidSetStyleContext(nsPresContext* aPresContext); + +protected: + virtual ~nsSVGGradientFrame(); + + // Internal methods for handling referenced gradients PRBool checkURITarget(nsIAtom *); PRBool checkURITarget(); + // + NS_IMETHOD PrivateGetGradientUnits(nsIDOMSVGAnimatedEnumeration * *aEnum); + NS_IMETHOD PrivateGetGradientTransform(nsIDOMSVGMatrix * *aValue, + nsISVGGeometrySource *aSource); + NS_IMETHOD PrivateGetSpreadMethod(nsIDOMSVGAnimatedEnumeration * *aValue); + // + nsSVGGradientFrame *mNextGrad; - nsISVGGradient *mNextGrad; - nsAutoString mNextGradStr; +private: + // Cached values + nsCOMPtr mGradientUnits; + nsCOMPtr mGradientTransform; + nsCOMPtr mSpreadMethod; + + nsAutoString mNextGradStr; + + PRInt32 GetStopElement(PRInt32 aIndex, + nsIDOMSVGStopElement * *aStopElement, + nsIFrame * *aStopFrame); }; -//---------------------------------------------------------------------- -// nsISupports methods +// ------------------------------------------------------------------------- +// Linear Gradients +// ------------------------------------------------------------------------- -NS_INTERFACE_MAP_BEGIN(nsSVGGradientFrame) - NS_INTERFACE_MAP_ENTRY(nsISVGGradient) -NS_INTERFACE_MAP_END_INHERITING(nsSVGGradientFrameBase) +typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase; + +class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase, + public nsISVGLinearGradient +{ +public: + // nsISupports interface: + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } + NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } + + // nsISVGLinearGradient interface: + NS_DECL_NSISVGLINEARGRADIENT + + // nsISVGGradient interface gets inherited from nsSVGGradientFrame + +protected: + virtual ~nsSVGLinearGradientFrame(); + + NS_IMETHOD PrivateGetX1(nsIDOMSVGLength * *aX1); + NS_IMETHOD PrivateGetX2(nsIDOMSVGLength * *aX2); + NS_IMETHOD PrivateGetY1(nsIDOMSVGLength * *aY1); + NS_IMETHOD PrivateGetY2(nsIDOMSVGLength * *aY2); + +private: + nsCOMPtr mX1; + nsCOMPtr mX2; + nsCOMPtr mY1; + nsCOMPtr mY2; +}; + +// ------------------------------------------------------------------------- +// Radial Gradients +// ------------------------------------------------------------------------- + +typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase; + +class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase, + public nsISVGRadialGradient +{ +public: + // nsISupports interface: + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } + NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } + + // nsISVGRadialGradient interface: + NS_DECL_NSISVGRADIALGRADIENT + + // nsISVGGradient interface gets inherited from nsSVGGradientFrame + +protected: + virtual ~nsSVGRadialGradientFrame(); + + NS_IMETHOD PrivateGetCx(nsIDOMSVGLength * *aCx); + NS_IMETHOD PrivateGetCy(nsIDOMSVGLength * *aCy); + NS_IMETHOD PrivateGetFx(nsIDOMSVGLength * *aFx); + NS_IMETHOD PrivateGetFy(nsIDOMSVGLength * *aFy); + NS_IMETHOD PrivateGetR(nsIDOMSVGLength * *aR); + +private: + nsCOMPtr mCx; + nsCOMPtr mCy; + nsCOMPtr mFx; + nsCOMPtr mFy; + nsCOMPtr mR; + +}; + +static nsresult GetSVGGradient(nsSVGGradientFrame **result, nsCAutoString& aSpec, + nsIContent *aContent, nsIPresShell *aPresShell); //---------------------------------------------------------------------- // Implementation +nsSVGGradientFrame::~nsSVGGradientFrame() +{ + WillModify(); + // Notify the world that we're dying + DidModify(mod_die); + + // Remove observers on gradient attributes + if (mGradientUnits) NS_REMOVE_SVGVALUE_OBSERVER(mGradientUnits); + if (mGradientTransform) NS_REMOVE_SVGVALUE_OBSERVER(mGradientTransform); + if (mSpreadMethod) NS_REMOVE_SVGVALUE_OBSERVER(mSpreadMethod); +} + +//---------------------------------------------------------------------- +// nsISupports methods: + +NS_INTERFACE_MAP_BEGIN(nsSVGGradientFrame) + NS_INTERFACE_MAP_ENTRY(nsISVGValue) + NS_INTERFACE_MAP_ENTRY(nsISVGGradient) + NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver) + NS_INTERFACE_MAP_ENTRY(nsSupportsWeakReference) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue) +NS_INTERFACE_MAP_END_INHERITING(nsSVGGradientFrameBase) + +//---------------------------------------------------------------------- +// nsISVGValueObserver methods: +NS_IMETHODIMP +nsSVGGradientFrame::WillModifySVGObservable(nsISVGValue* observable, + modificationType aModType) +{ + WillModify(aModType); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGGradientFrame::DidModifySVGObservable(nsISVGValue* observable, + nsISVGValue::modificationType aModType) +{ + // Something we depend on was modified -- pass it on! + DidModify(aModType); + return NS_OK; +} + +//---------------------------------------------------------------------- +// nsIFrame methods: + +NS_IMETHODIMP +nsSVGGradientFrame::DidSetStyleContext(nsPresContext* aPresContext) +{ + WillModify(mod_other); + DidModify(mod_other); + return NS_OK; +} + +//---------------------------------------------------------------------- +// nsISVGGradient implementation +//---------------------------------------------------------------------- + NS_IMETHODIMP nsSVGGradientFrame::GetStopCount(PRUint32 *aStopCount) { - PRInt32 stopCount = 0; + nsresult rv = NS_OK; nsIDOMSVGStopElement *stopElement = nsnull; - for (nsIFrame* stopFrame = mFrames.FirstChild(); stopFrame; - stopFrame = stopFrame->GetNextSibling()) { - stopFrame->GetContent()->QueryInterface(NS_GET_IID(nsIDOMSVGStopElement),(void**)&stopElement); - if (stopElement) stopCount++; - } - if (stopCount == 0) { + *aStopCount = GetStopElement(-1, &stopElement, nsnull); + if (*aStopCount == 0) { // No stops? check for URI target if (checkURITarget()) - return mNextGrad->GetStopCount(aStopCount); + rv = mNextGrad->GetStopCount(aStopCount); } - *aStopCount = stopCount; - return NS_OK; + return rv; } NS_IMETHODIMP nsSVGGradientFrame::GetStopOffset(PRInt32 aIndex, float *aOffset) { - PRInt32 stopCount = 0; nsIDOMSVGStopElement *stopElement = nsnull; - for (nsIFrame* stopFrame = mFrames.FirstChild(); stopFrame; - stopFrame = stopFrame->GetNextSibling()) { - stopFrame->GetContent()->QueryInterface(NS_GET_IID(nsIDOMSVGStopElement),(void**)&stopElement); - if (stopElement) { - // Is this the one we're looking for? - if (stopCount == aIndex) - break; // Yes, break out of the loop - stopCount++; - } - } - if (stopCount == 0) { + PRInt32 stopCount = GetStopElement(aIndex, &stopElement, nsnull); + if (stopCount == 0 && !stopElement) { // No stops? check for URI target if (checkURITarget()) return mNextGrad->GetStopOffset(aIndex, aOffset); } - if (!stopElement) { *aOffset = nsnull; return NS_ERROR_FAILURE; @@ -178,22 +323,12 @@ nsSVGGradientFrame::GetStopOffset(PRInt32 aIndex, float *aOffset) } NS_IMETHODIMP -nsSVGGradientFrame::GetStopColorType(PRInt32 aIndex, PRUint16 *aStopColorType) { - PRInt32 stopCount = 0; +nsSVGGradientFrame::GetStopColorType(PRInt32 aIndex, PRUint16 *aStopColorType) +{ nsIDOMSVGStopElement *stopElement = nsnull; - nsIFrame* stopFrame = nsnull; - for (stopFrame = mFrames.FirstChild(); stopFrame; - stopFrame = stopFrame->GetNextSibling()) { - nsIDOMSVGStopElement *stopElement; - stopFrame->GetContent()->QueryInterface(NS_GET_IID(nsIDOMSVGStopElement),(void**)&stopElement); - if (stopElement) { - // Is this the one we're looking for? - if (stopCount == aIndex) - break; // Yes, break out of the loop - stopCount++; - } - } - if (stopCount == 0) { + nsIFrame *stopFrame = nsnull; + PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); + if (stopCount == 0 && !stopElement) { // No stops? check for URI target if (checkURITarget()) return mNextGrad->GetStopColorType(aIndex, aStopColorType); @@ -208,22 +343,12 @@ nsSVGGradientFrame::GetStopColorType(PRInt32 aIndex, PRUint16 *aStopColorType) { } NS_IMETHODIMP -nsSVGGradientFrame::GetStopColor(PRInt32 aIndex, nscolor *aStopColor) { - PRInt32 stopCount = 0; +nsSVGGradientFrame::GetStopColor(PRInt32 aIndex, nscolor *aStopColor) +{ + nsIDOMSVGStopElement *stopElement = nsnull; nsIFrame *stopFrame = nsnull; - for (stopFrame = mFrames.FirstChild(); stopFrame; - stopFrame = stopFrame->GetNextSibling()) { - nsIDOMSVGStopElement *stopElement; - stopFrame->GetContent()->QueryInterface(NS_GET_IID(nsIDOMSVGStopElement),(void**)&stopElement); - if (stopElement) { - // Is this the one we're looking for? - if (stopCount == aIndex) { - break; // Yes, break out of the loop - } - stopCount++; - } - } - if (stopCount == 0) { + PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); + if (stopCount == 0 && !stopElement) { // No stops? check for URI target if (checkURITarget()) return mNextGrad->GetStopColor(aIndex, aStopColor); @@ -238,21 +363,12 @@ nsSVGGradientFrame::GetStopColor(PRInt32 aIndex, nscolor *aStopColor) { } NS_IMETHODIMP -nsSVGGradientFrame::GetStopOpacity(PRInt32 aIndex, float *aStopOpacity) { - PRInt32 stopCount = 0; +nsSVGGradientFrame::GetStopOpacity(PRInt32 aIndex, float *aStopOpacity) +{ + nsIDOMSVGStopElement *stopElement = nsnull; nsIFrame *stopFrame = nsnull; - for (stopFrame = mFrames.FirstChild(); stopFrame; - stopFrame = stopFrame->GetNextSibling()) { - nsIDOMSVGStopElement *stopElement; - stopFrame->GetContent()->QueryInterface(NS_GET_IID(nsIDOMSVGStopElement),(void**)&stopElement); - if (stopElement) { - // Is this the one we're looking for? - if (stopCount == aIndex) - break; // Yes, break out of the loop - stopCount++; - } - } - if (stopCount == 0) { + PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); + if (stopCount == 0 && !stopElement) { // No stops? check for URI target if (checkURITarget()) return mNextGrad->GetStopOpacity(aIndex, aStopOpacity); @@ -287,7 +403,52 @@ nsSVGGradientFrame::GetGradientType(PRUint32 *aType) NS_IMETHODIMP nsSVGGradientFrame::GetGradientUnits(PRUint16 *aUnits) { - nsCOMPtr aEnum; + if (!mGradientUnits) { + PrivateGetGradientUnits(getter_AddRefs(mGradientUnits)); + if (!mGradientUnits) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mGradientUnits); + } + mGradientUnits->GetAnimVal(aUnits); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, + nsISVGGeometrySource *aSource) +{ + if (!mGradientTransform) { + PrivateGetGradientTransform(getter_AddRefs(mGradientTransform),aSource); + if (!mGradientTransform) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mGradientTransform); + } + *aGradientTransform = mGradientTransform; + NS_ADDREF(*aGradientTransform); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGGradientFrame::GetSpreadMethod(PRUint16 *aSpreadMethod) +{ + if (!mSpreadMethod) { + PrivateGetSpreadMethod(getter_AddRefs(mSpreadMethod)); + if (!mSpreadMethod) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mSpreadMethod); + } + mSpreadMethod->GetAnimVal(aSpreadMethod); + return NS_OK; +} + +// ------------------------------------------------------------- +// Protected versions of the various "Get" routines. These need +// to be used to allow for the ability to delegate to referenced +// gradients +// ------------------------------------------------------------- +NS_IMETHODIMP +nsSVGGradientFrame::PrivateGetGradientUnits(nsIDOMSVGAnimatedEnumeration * *aEnum) +{ nsCOMPtr aGrad = do_QueryInterface(mContent); NS_ASSERTION(aGrad, "Wrong content element (not gradient)"); if (aGrad == nsnull) { @@ -296,18 +457,17 @@ nsSVGGradientFrame::GetGradientUnits(PRUint16 *aUnits) // See if we need to get the value from another gradient if (!checkURITarget(nsSVGAtoms::gradientUnits)) { // No, return the values - aGrad->GetGradientUnits(getter_AddRefs(aEnum)); - aEnum->GetAnimVal(aUnits); + aGrad->GetGradientUnits(aEnum); } else { // Yes, get it from the target - mNextGrad->GetGradientUnits(aUnits); + mNextGrad->PrivateGetGradientUnits(aEnum); } return NS_OK; } NS_IMETHODIMP -nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, - nsISVGGeometrySource *aSource) +nsSVGGradientFrame::PrivateGetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, + nsISVGGeometrySource *aSource) { *aGradientTransform = nsnull; nsCOMPtr aTrans; @@ -356,7 +516,7 @@ nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, lTrans->GetConsolidationMatrix(getter_AddRefs(gradientTransform)); } else { // Yes, get it from the target - mNextGrad->GetGradientTransform(getter_AddRefs(gradientTransform), nsnull); + mNextGrad->PrivateGetGradientTransform(getter_AddRefs(gradientTransform), nsnull); } bboxTransform->Multiply(gradientTransform, aGradientTransform); @@ -364,9 +524,8 @@ nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, } NS_IMETHODIMP -nsSVGGradientFrame::GetSpreadMethod(PRUint16 *aSpreadMethod) +nsSVGGradientFrame::PrivateGetSpreadMethod(nsIDOMSVGAnimatedEnumeration * *aEnum) { - nsCOMPtr aEnum; nsCOMPtr aGrad = do_QueryInterface(mContent); NS_ASSERTION(aGrad, "Wrong content element (not gradient)"); if (aGrad == nsnull) { @@ -375,11 +534,10 @@ nsSVGGradientFrame::GetSpreadMethod(PRUint16 *aSpreadMethod) // See if we need to get the value from another gradient if (!checkURITarget(nsSVGAtoms::spreadMethod)) { // No, return the values - aGrad->GetSpreadMethod(getter_AddRefs(aEnum)); - aEnum->GetAnimVal(aSpreadMethod); + aGrad->GetSpreadMethod(aEnum); } else { // Yes, get it from the target - mNextGrad->GetSpreadMethod(aSpreadMethod); + mNextGrad->PrivateGetSpreadMethod(aEnum); } return NS_OK; } @@ -416,6 +574,7 @@ nsSVGGradientFrame::checkURITarget(nsIAtom *attr) { PRBool nsSVGGradientFrame::checkURITarget(void) { + nsSVGGradientFrame *aNextGrad; // Have we already figured out the next Gradient? if (mNextGrad != nsnull) { return PR_TRUE; @@ -431,33 +590,49 @@ nsSVGGradientFrame::checkURITarget(void) { CopyUTF16toUTF8(mNextGradStr, aGradStr); // Note that we are using *our* frame tree for this call, otherwise we're going to have // to get the PresShell in each call - if (GetSVGGradient(&mNextGrad, aGradStr, mContent, GetPresContext()->PresShell()) == NS_OK) { + if (GetSVGGradient(&aNextGrad, aGradStr, mContent, GetPresContext()->PresShell()) == NS_OK) { + mNextGrad = aNextGrad; + // Add ourselves to the observer list + if (mNextGrad) { + // Can't use the NS_ADD macro here because of nsISupports ambiguity + mNextGrad->AddObserver(this); + } return PR_TRUE; } return PR_FALSE; } +// ------------------------------------------------------------------------- +// Private helper method to simplify getting stop elements +// returns non-addrefed stop element +// ------------------------------------------------------------------------- +PRInt32 +nsSVGGradientFrame::GetStopElement(PRInt32 aIndex, nsIDOMSVGStopElement * *aStopElement, + nsIFrame * *aStopFrame) +{ + PRInt32 stopCount = 0; + nsIFrame *stopFrame; + for (stopFrame = mFrames.FirstChild(); stopFrame; + stopFrame = stopFrame->GetNextSibling()) { + nsCOMPtrstopElement = do_QueryInterface(stopFrame->GetContent()); + if (stopElement) { + // Is this the one we're looking for? + if (stopCount == aIndex) { + *aStopElement = stopElement; + break; // Yes, break out of the loop + } + stopCount++; + } + } + if (aStopFrame) + *aStopFrame = stopFrame; + return stopCount; +} + // ------------------------------------------------------------------------- // Linear Gradients // ------------------------------------------------------------------------- -typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase; - -class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase, - public nsISVGLinearGradient -{ -public: - // nsISupports interface: - NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); - NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } - NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } - - // nsISVGLinearGradient interface: - NS_DECL_NSISVGLINEARGRADIENT - - // nsISVGGradient interface gets inherited from nsSVGGradientFrame -}; - //---------------------------------------------------------------------- // nsISupports methods @@ -466,8 +641,16 @@ NS_INTERFACE_MAP_BEGIN(nsSVGLinearGradientFrame) NS_INTERFACE_MAP_END_INHERITING(nsSVGLinearGradientFrameBase) // Implementation +nsSVGLinearGradientFrame::~nsSVGLinearGradientFrame() +{ + if (mX1) NS_REMOVE_SVGVALUE_OBSERVER(mX1); + if (mY1) NS_REMOVE_SVGVALUE_OBSERVER(mY1); + if (mX2) NS_REMOVE_SVGVALUE_OBSERVER(mX2); + if (mY2) NS_REMOVE_SVGVALUE_OBSERVER(mY2); +} + nsresult -nsSVGLinearGradientFrame::GetX1(float *aX1) +nsSVGLinearGradientFrame::PrivateGetX1(nsIDOMSVGLength * *aX1) { nsCOMPtr aLgrad = do_QueryInterface(mContent); NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)"); @@ -479,8 +662,8 @@ nsSVGLinearGradientFrame::GetX1(float *aX1) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { - nsCOMPtr aLNgrad = do_QueryInterface(aNextGrad); - aLNgrad->GetX1(aX1); + nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; + aLNgrad->PrivateGetX1(aX1); return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -489,14 +672,12 @@ nsSVGLinearGradientFrame::GetX1(float *aX1) // No, return the values nsCOMPtr aLen; aLgrad->GetX1(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aX1); + aLen->GetAnimVal(aX1); return NS_OK; } nsresult -nsSVGLinearGradientFrame::GetY1(float *aY1) +nsSVGLinearGradientFrame::PrivateGetY1(nsIDOMSVGLength * *aY1) { nsCOMPtr aLgrad = do_QueryInterface(mContent); NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)"); @@ -508,8 +689,8 @@ nsSVGLinearGradientFrame::GetY1(float *aY1) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { - nsCOMPtr aLNgrad = do_QueryInterface(aNextGrad); - aLNgrad->GetY1(aY1); + nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; + aLNgrad->PrivateGetY1(aY1); return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -518,14 +699,12 @@ nsSVGLinearGradientFrame::GetY1(float *aY1) // No, return the values nsCOMPtr aLen; aLgrad->GetY1(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aY1); + aLen->GetAnimVal(aY1); return NS_OK; } nsresult -nsSVGLinearGradientFrame::GetX2(float *aX2) +nsSVGLinearGradientFrame::PrivateGetX2(nsIDOMSVGLength * *aX2) { nsCOMPtr aLgrad = do_QueryInterface(mContent); NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)"); @@ -537,8 +716,8 @@ nsSVGLinearGradientFrame::GetX2(float *aX2) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { - nsCOMPtr aLNgrad = do_QueryInterface(aNextGrad); - aLNgrad->GetX2(aX2); + nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; + aLNgrad->PrivateGetX2(aX2); return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -547,14 +726,12 @@ nsSVGLinearGradientFrame::GetX2(float *aX2) // No, return the values nsCOMPtr aLen; aLgrad->GetX2(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aX2); + aLen->GetAnimVal(aX2); return NS_OK; } nsresult -nsSVGLinearGradientFrame::GetY2(float *aY2) +nsSVGLinearGradientFrame::PrivateGetY2(nsIDOMSVGLength * *aY2) { nsCOMPtr aLgrad = do_QueryInterface(mContent); NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)"); @@ -566,8 +743,8 @@ nsSVGLinearGradientFrame::GetY2(float *aY2) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { - nsCOMPtr aLNgrad = do_QueryInterface(aNextGrad); - aLNgrad->GetX1(aY2); + nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; + aLNgrad->PrivateGetY2(aY2); return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -576,34 +753,67 @@ nsSVGLinearGradientFrame::GetY2(float *aY2) // No, return the values nsCOMPtr aLen; aLgrad->GetY2(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aY2); + aLen->GetAnimVal(aY2); return NS_OK; } +// nsISVGLinearGradient +NS_IMETHODIMP +nsSVGLinearGradientFrame::GetX1(float *aX1) +{ + if (!mX1) { + PrivateGetX1(getter_AddRefs(mX1)); + if (!mX1) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mX1); + } + mX1->GetValue(aX1); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGLinearGradientFrame::GetY1(float *aY1) +{ + if (!mY1) { + PrivateGetY1(getter_AddRefs(mY1)); + if (!mY1) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mY1); + } + mY1->GetValue(aY1); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGLinearGradientFrame::GetX2(float *aX2) +{ + if (!mX2) { + PrivateGetX2(getter_AddRefs(mX2)); + if (!mX2) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mX2); + } + mX2->GetValue(aX2); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGLinearGradientFrame::GetY2(float *aY2) +{ + if (!mY2) { + PrivateGetY2(getter_AddRefs(mY2)); + if (!mY2) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mY2); + } + mY2->GetValue(aY2); + return NS_OK; +} // ------------------------------------------------------------------------- // Radial Gradients // ------------------------------------------------------------------------- -typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase; - -class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase, - public nsISVGRadialGradient -{ -public: - // nsISupports interface: - NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); - NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } - NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } - - // nsISVGRadialGradient interface: - NS_DECL_NSISVGRADIALGRADIENT - - // nsISVGGradient interface gets inherited from nsSVGGradientFrame -}; - //---------------------------------------------------------------------- // nsISupports methods @@ -612,8 +822,18 @@ NS_INTERFACE_MAP_BEGIN(nsSVGRadialGradientFrame) NS_INTERFACE_MAP_END_INHERITING(nsSVGRadialGradientFrameBase) // Implementation +nsSVGRadialGradientFrame::~nsSVGRadialGradientFrame() +{ + if (mCx) NS_REMOVE_SVGVALUE_OBSERVER(mCx); + if (mCy) NS_REMOVE_SVGVALUE_OBSERVER(mCy); + if (mFx) NS_REMOVE_SVGVALUE_OBSERVER(mFx); + if (mFy) NS_REMOVE_SVGVALUE_OBSERVER(mFy); + if (mR) NS_REMOVE_SVGVALUE_OBSERVER(mR); +} + + nsresult -nsSVGRadialGradientFrame::GetCx(float *aCx) +nsSVGRadialGradientFrame::PrivateGetCx(nsIDOMSVGLength * *aCx) { nsCOMPtr aRgrad = do_QueryInterface(mContent); NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)"); @@ -625,8 +845,8 @@ nsSVGRadialGradientFrame::GetCx(float *aCx) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { - nsCOMPtr aRNgrad = do_QueryInterface(aNextGrad); - aRNgrad->GetCx(aCx); + nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; + aRNgrad->PrivateGetCx(aCx); return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -635,14 +855,12 @@ nsSVGRadialGradientFrame::GetCx(float *aCx) // No, return the values nsCOMPtr aLen; aRgrad->GetCx(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aCx); + aLen->GetAnimVal(aCx); return NS_OK; } nsresult -nsSVGRadialGradientFrame::GetCy(float *aCy) +nsSVGRadialGradientFrame::PrivateGetCy(nsIDOMSVGLength * *aCy) { nsCOMPtr aRgrad = do_QueryInterface(mContent); NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)"); @@ -654,8 +872,8 @@ nsSVGRadialGradientFrame::GetCy(float *aCy) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { - nsCOMPtr aRNgrad = do_QueryInterface(aNextGrad); - aRNgrad->GetCy(aCy); + nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; + aRNgrad->PrivateGetCy(aCy); return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -664,14 +882,12 @@ nsSVGRadialGradientFrame::GetCy(float *aCy) // No, return the values nsCOMPtr aLen; aRgrad->GetCy(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aCy); + aLen->GetAnimVal(aCy); return NS_OK; } nsresult -nsSVGRadialGradientFrame::GetR(float *aR) +nsSVGRadialGradientFrame::PrivateGetR(nsIDOMSVGLength * *aR) { nsCOMPtr aRgrad = do_QueryInterface(mContent); NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)"); @@ -683,8 +899,8 @@ nsSVGRadialGradientFrame::GetR(float *aR) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { - nsCOMPtr aRNgrad = do_QueryInterface(aNextGrad); - aRNgrad->GetR(aR); + nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; + aRNgrad->PrivateGetR(aR); return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -693,14 +909,12 @@ nsSVGRadialGradientFrame::GetR(float *aR) // No, return the values nsCOMPtr aLen; aRgrad->GetR(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aR); + aLen->GetAnimVal(aR); return NS_OK; } nsresult -nsSVGRadialGradientFrame::GetFx(float *aFx) +nsSVGRadialGradientFrame::PrivateGetFx(nsIDOMSVGLength * *aFx) { nsCOMPtr aRgrad = do_QueryInterface(mContent); NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)"); @@ -712,26 +926,24 @@ nsSVGRadialGradientFrame::GetFx(float *aFx) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { - nsCOMPtr aRNgrad = do_QueryInterface(aNextGrad); - aRNgrad->GetFx(aFx); + nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; + aRNgrad->PrivateGetFx(aFx); return NS_OK; } // There are no gradients in the list with our type -- the spec // states that if there is no explicit fx value, we return the cx value // see http://www.w3.org/TR/SVG11/pservers.html#RadialGradients - return GetCx(aFx); + return PrivateGetCx(aFx); } // No, return the values nsCOMPtr aLen; aRgrad->GetFx(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aFx); + aLen->GetAnimVal(aFx); return NS_OK; } nsresult -nsSVGRadialGradientFrame::GetFy(float *aFy) +nsSVGRadialGradientFrame::PrivateGetFy(nsIDOMSVGLength * *aFy) { nsCOMPtr aRgrad = do_QueryInterface(mContent); NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)"); @@ -743,21 +955,85 @@ nsSVGRadialGradientFrame::GetFy(float *aFy) // Yes, get it from the target nsISVGGradient *aNextGrad; if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { - nsCOMPtr aRNgrad = do_QueryInterface(aNextGrad); - aRNgrad->GetFy(aFy); + nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; + aRNgrad->PrivateGetFy(aFy); return NS_OK; } // There are no gradients in the list with our type -- the spec // states that if there is no explicit fy value, we return the cy value // see http://www.w3.org/TR/SVG11/pservers.html#RadialGradients - return GetCy(aFy); + return PrivateGetCy(aFy); } // No, return the values nsCOMPtr aLen; aRgrad->GetFy(getter_AddRefs(aLen)); - nsCOMPtr sLen; - aLen->GetAnimVal(getter_AddRefs(sLen)); - sLen->GetValue(aFy); + aLen->GetAnimVal(aFy); + return NS_OK; +} + +// nsISVGRadialGradient +NS_IMETHODIMP +nsSVGRadialGradientFrame::GetFx(float *aFx) +{ + if (!mFx) { + PrivateGetFx(getter_AddRefs(mFx)); + if (!mFx) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mFx); + } + mFx->GetValue(aFx); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGRadialGradientFrame::GetFy(float *aFy) +{ + if (!mFy) { + PrivateGetFy(getter_AddRefs(mFy)); + if (!mFy) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mFy); + } + mFy->GetValue(aFy); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGRadialGradientFrame::GetCx(float *aCx) +{ + if (!mCx) { + PrivateGetCx(getter_AddRefs(mCx)); + if (!mCx) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mCx); + } + mCx->GetValue(aCx); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGRadialGradientFrame::GetCy(float *aCy) +{ + if (!mCy) { + PrivateGetCy(getter_AddRefs(mCy)); + if (!mCy) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mCy); + } + mCy->GetValue(aCy); + return NS_OK; +} + +NS_IMETHODIMP +nsSVGRadialGradientFrame::GetR(float *aR) +{ + if (!mR) { + PrivateGetR(getter_AddRefs(mR)); + if (!mR) + return NS_ERROR_FAILURE; + NS_ADD_SVGVALUE_OBSERVER(mR); + } + mR->GetValue(aR); return NS_OK; } @@ -769,10 +1045,6 @@ nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame) { - -#ifdef DEBUG_scooter - printf("NS_NewSVGLinearGradientFrame called\n"); -#endif *aNewFrame = nsnull; nsCOMPtr grad = do_QueryInterface(aContent); @@ -792,7 +1064,7 @@ nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, // Get the hRef nsCOMPtr aHref; aRef->GetHref(getter_AddRefs(aHref)); - // We *really* want an observer on this + nsAutoString aStr; aHref->GetAnimVal(aStr); it->mNextGradStr = aStr; @@ -808,9 +1080,6 @@ nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame) { -#ifdef DEBUG_scooter - printf("NS_NewSVGRadialGradientFrame called\n"); -#endif *aNewFrame = nsnull; nsCOMPtr grad = do_QueryInterface(aContent); @@ -830,7 +1099,7 @@ nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, // Get the hRef nsCOMPtr aHref; aRef->GetHref(getter_AddRefs(aHref)); - // We *really* want an observer on this + nsAutoString aStr; aHref->GetAnimVal(aStr); it->mNextGradStr = aStr; @@ -842,41 +1111,25 @@ nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, return NS_OK; } -nsresult NS_NewSVGStopFrame(nsIPresShell* aPresShell, - nsIContent* aContent, - nsIFrame* aParentFrame, - nsIFrame** aNewFrame) -{ - *aNewFrame = nsnull; - - nsCOMPtr grad = do_QueryInterface(aContent); - NS_ASSERTION(grad, "NS_NewSVGStopFrame -- Content doesn't support nsIDOMSVGStopElement"); - if (!grad) - return NS_ERROR_FAILURE; - - // Create an anonymous frame for ourselves (we only use it for style information) - nsresult rv = NS_NewSVGGenericContainerFrame(aPresShell, aContent, aNewFrame); - if (!NS_SUCCEEDED(rv) || *aNewFrame == nsnull) - return rv; - - return NS_OK; -} - // Public function to locate the SVGGradientFrame structure pointed to by a URI // and return a nsISVGGradient -nsresult NS_GetSVGGradient(nsISVGGradient **result, nsIURI *aURI, nsIContent *aContent, +nsresult NS_GetSVGGradient(nsISVGGradient **aGrad, nsIURI *aURI, nsIContent *aContent, nsIPresShell *aPresShell) { - *result = nsnull; + *aGrad = nsnull; // Get the spec from the URI nsCAutoString uriSpec; aURI->GetSpec(uriSpec); - return GetSVGGradient(result, uriSpec, aContent, aPresShell); + nsSVGGradientFrame *result; + nsresult rv = GetSVGGradient(&result, uriSpec, aContent, aPresShell); + *aGrad = (nsISVGGradient*)result; + + return rv; } // Static (helper) function to get a gradient from URI spec -static nsresult GetSVGGradient(nsISVGGradient **result, nsCAutoString& aSpec, nsIContent *aContent, +static nsresult GetSVGGradient(nsSVGGradientFrame **result, nsCAutoString& aSpec, nsIContent *aContent, nsIPresShell *aPresShell) { nsresult rv = NS_OK; @@ -906,7 +1159,6 @@ static nsresult GetSVGGradient(nsISVGGradient **result, nsCAutoString& aSpec, ns // Get the gradient element nsCOMPtr element; - nsIFrame *grad; rv = domDoc->GetElementById(aURIName, getter_AddRefs(element)); if (!NS_SUCCEEDED(rv) || element == nsnull) { return rv; @@ -928,10 +1180,9 @@ static nsresult GetSVGGradient(nsISVGGradient **result, nsCAutoString& aSpec, ns NS_ASSERTION(aPresShell, "svg get gradient -- no pres shell provided"); if (!aPresShell) return NS_ERROR_FAILURE; + nsIFrame *grad; rv = aPresShell->GetPrimaryFrameFor(aGContent, &grad); - nsCOMPtr aGrad = do_QueryInterface(grad); - *result = aGrad; + *result = (nsSVGGradientFrame *)grad; return rv; } - diff --git a/layout/svg/base/src/nsSVGGradientFrame.h b/layout/svg/base/src/nsSVGGradientFrame.h index 029f00fcdf1..baa1835732d 100644 --- a/layout/svg/base/src/nsSVGGradientFrame.h +++ b/layout/svg/base/src/nsSVGGradientFrame.h @@ -39,9 +39,9 @@ #ifndef __NS_SVGGRADIENTFRAME_H__ #define __NS_SVGGRADIENTFRAME_H__ -#include "nsISVGGradient.h" -#include "nsIURI.h" +#include "nsIFrame.h" #include "nsIContent.h" +#include "nsIPresShell.h" nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, nsIContent* aContent, @@ -50,15 +50,5 @@ nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame); - -nsresult NS_NewSVGStopFrame(nsIPresShell* aPresShell, - nsIContent* aContent, - nsIFrame* aParentFrame, - nsIFrame** aNewFrame); - -nsresult NS_GetSVGGradient(nsISVGGradient** result, - nsIURI* aURI, - nsIContent* aContent, - nsIPresShell* aPresShell); #endif // __NS_SVGGRADIENTFRAME_H__ diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index 9a524290225..bc3f18cf875 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -47,7 +47,6 @@ #include "nsIDOMSVGAnimTransformList.h" #include "nsIDOMSVGTransformList.h" #include "nsISVGContainerFrame.h" -#include "nsSVGGradientFrame.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsSVGAtoms.h" @@ -66,7 +65,8 @@ // nsSVGPathGeometryFrame nsSVGPathGeometryFrame::nsSVGPathGeometryFrame() - : mUpdateFlags(0), mPropagateTransform(PR_TRUE) + : mUpdateFlags(0), mPropagateTransform(PR_TRUE), + mFillGradient(nsnull), mStrokeGradient(nsnull) { #ifdef DEBUG // printf("nsSVGPathGeometryFrame %p CTOR\n", this); @@ -83,8 +83,13 @@ nsSVGPathGeometryFrame::~nsSVGPathGeometryFrame() NS_ASSERTION(transformable, "wrong content element"); nsCOMPtr transforms; transformable->GetTransform(getter_AddRefs(transforms)); - nsCOMPtr value = do_QueryInterface(transforms); NS_REMOVE_SVGVALUE_OBSERVER(transforms); + if (mFillGradient) { + NS_REMOVE_SVGVALUE_OBSERVER(mFillGradient); + } + if (mStrokeGradient) { + NS_REMOVE_SVGVALUE_OBSERVER(mStrokeGradient); + } } //---------------------------------------------------------------------- @@ -108,9 +113,6 @@ nsSVGPathGeometryFrame::Init(nsPresContext* aPresContext, nsStyleContext* aContext, nsIFrame* aPrevInFlow) { -// rv = nsSVGPathGeometryFrameBase::Init(aPresContext, aContent, aParent, -// aContext, aPrevInFlow); - mContent = aContent; NS_IF_ADDREF(mContent); mParent = aParent; @@ -147,6 +149,17 @@ nsSVGPathGeometryFrame::AttributeChanged(nsIContent* aChild, NS_IMETHODIMP nsSVGPathGeometryFrame::DidSetStyleContext(nsPresContext* aPresContext) { + // One of the styles that might have been changed are the urls that + // point to gradients, etc. Drop our cached values to those + if (mFillGradient) { + NS_REMOVE_SVGVALUE_OBSERVER(mFillGradient); + mFillGradient = nsnull; + } + if (mStrokeGradient) { + NS_REMOVE_SVGVALUE_OBSERVER(mStrokeGradient); + mStrokeGradient = nsnull; + } + // XXX: we'd like to use the style_hint mechanism and the // ContentStateChanged/AttributeChanged functions for style changes // to get slightly finer granularity, but unfortunately the @@ -407,11 +420,27 @@ NS_IMETHODIMP nsSVGPathGeometryFrame::DidModifySVGObservable (nsISVGValue* observable, nsISVGValue::modificationType aModType) { - // the observables we're listening in on affect the canvastm by - // default. We can specialize in the subclasses when needed. - - UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_CANVAS_TM); - + // Is this a gradient? + nsCOMPtrval = do_QueryInterface(observable); + if (val) { + // Yes, we need to handle this differently + nsCOMPtrfill = do_QueryInterface(mFillGradient); + if (fill == val) { + if (aModType == nsISVGValue::mod_die) { + mFillGradient = nsnull; + } + UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_FILL_PAINT); + } else { + // No real harm in assuming a stroke gradient at this point + if (aModType == nsISVGValue::mod_die) { + mStrokeGradient = nsnull; + } + UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_STROKE_PAINT); + } + } else { + // No, all of our other observables update the canvastm by default + UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_CANVAS_TM); + } return NS_OK; } @@ -586,12 +615,19 @@ nsSVGPathGeometryFrame::GetStrokePaint(nscolor *aStrokePaint) NS_IMETHODIMP nsSVGPathGeometryFrame::GetStrokeGradient(nsISVGGradient **aGrad) { - nsIURI *aServer; - aServer = GetStyleSVG()->mStroke.mPaint.mPaintServer; - if (aServer == nsnull) - return NS_ERROR_FAILURE; - // Now have the URI. Get the gradient - return NS_GetSVGGradient(aGrad, aServer, mContent, nsSVGPathGeometryFrameBase::GetPresContext()->PresShell()); + nsresult rv = NS_OK; + if (!mStrokeGradient) { + nsIURI *aServer; + aServer = GetStyleSVG()->mStroke.mPaint.mPaintServer; + if (aServer == nsnull) + return NS_ERROR_FAILURE; + // Now have the URI. Get the gradient + rv = NS_GetSVGGradient(getter_AddRefs(mStrokeGradient), aServer, mContent, + nsSVGPathGeometryFrameBase::GetPresContext()->PresShell()); + NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient); + } + *aGrad = mStrokeGradient; + return rv; } /* readonly attribute unsigned short fillPaintType; */ @@ -614,12 +650,19 @@ nsSVGPathGeometryFrame::GetFillPaint(nscolor *aFillPaint) NS_IMETHODIMP nsSVGPathGeometryFrame::GetFillGradient(nsISVGGradient **aGrad) { - nsIURI *aServer; - aServer = GetStyleSVG()->mFill.mPaint.mPaintServer; - if (aServer == nsnull) - return NS_ERROR_FAILURE; - // Now have the URI. Get the gradient - return NS_GetSVGGradient(aGrad, aServer, mContent, nsSVGPathGeometryFrameBase::GetPresContext()->PresShell()); + nsresult rv = NS_OK; + if (!mFillGradient) { + nsIURI *aServer; + aServer = GetStyleSVG()->mFill.mPaint.mPaintServer; + if (aServer == nsnull) + return NS_ERROR_FAILURE; + // Now have the URI. Get the gradient + rv = NS_GetSVGGradient(getter_AddRefs(mFillGradient), aServer, mContent, + nsSVGPathGeometryFrameBase::GetPresContext()->PresShell()); + NS_ADD_SVGVALUE_OBSERVER(mFillGradient); + } + *aGrad = mFillGradient; + return rv; } /* [noscript] boolean isClipChild; */ @@ -712,9 +755,6 @@ nsSVGPathGeometryFrame::GetShapeRendering(PRUint16 *aShapeRendering) nsresult nsSVGPathGeometryFrame::Init() { -// nsresult rv = nsSVGPathGeometryFrameBase::Init(); -// if (NS_FAILED(rv)) return rv; - // all path geometry frames listen in on changes to their // corresponding content element's transform attribute: nsCOMPtr transformable = do_QueryInterface(mContent); diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.h b/layout/svg/base/src/nsSVGPathGeometryFrame.h index b0e48e4d11b..e38903f4b4f 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.h +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.h @@ -48,6 +48,7 @@ #include "nsISVGValueObserver.h" #include "nsISVGOuterSVGFrame.h" #include "nsSVGMarkerFrame.h" +#include "nsSVGGradient.h" class nsPresContext; class nsIDOMSVGMatrix; @@ -126,6 +127,8 @@ private: nsCOMPtr mGeometry; PRUint32 mUpdateFlags; PRBool mPropagateTransform; + nsCOMPtr mFillGradient; + nsCOMPtr mStrokeGradient; void GetMarkerFrames(nsSVGMarkerFrame **markerStart, nsSVGMarkerFrame **markerMid, diff --git a/layout/svg/base/src/nsSVGStopFrame.cpp b/layout/svg/base/src/nsSVGStopFrame.cpp new file mode 100644 index 00000000000..6a97ad0b616 --- /dev/null +++ b/layout/svg/base/src/nsSVGStopFrame.cpp @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SVG project. + * + * The Initial Developer of the Original Code is + * Scooter Morris. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scooter Morris + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsWeakReference.h" +#include "nsIDOMSVGStopElement.h" +#include "nsStyleContext.h" +#include "nsContainerFrame.h" + +// This is a very simple frame whose only purpose is to capture style change +// events and propogate them to the parent. Most of the heavy lifting is done +// within the nsSVGGradientFrame, which is the parent for this frame + +typedef nsContainerFrame nsSVGStopFrameBase; + +class nsSVGStopFrame : public nsSVGStopFrameBase +{ +protected: + friend nsresult NS_NewSVGStopFrame(nsIPresShell* aPresShell, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame** aNewFrame); + +private: + // nsIFrame interface: + NS_IMETHOD DidSetStyleContext(nsPresContext* aPresContext); +}; + +//---------------------------------------------------------------------- +// Implementation + +//---------------------------------------------------------------------- +// nsIFrame methods: + +NS_IMETHODIMP +nsSVGStopFrame::DidSetStyleContext(nsPresContext* aPresContext) +{ +#ifdef DEBUG_scooter + printf("nsSVGStopFrame::DidSetStyleContext\n"); +#endif + // Tell our parent + if (mParent) + mParent->DidSetStyleContext(aPresContext); + return NS_OK; +} + +// ------------------------------------------------------------------------- +// Public functions +// ------------------------------------------------------------------------- + +nsresult NS_NewSVGStopFrame(nsIPresShell* aPresShell, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame** aNewFrame) +{ + *aNewFrame = nsnull; + +#ifdef DEBUG_scooter + printf("NS_NewSVGStopFrame\n"); +#endif + + nsCOMPtr grad = do_QueryInterface(aContent); + NS_ASSERTION(grad, "NS_NewSVGStopFrame -- Content doesn't support nsIDOMSVGStopElement"); + if (!grad) + return NS_ERROR_FAILURE; + + nsSVGStopFrame* it = new (aPresShell) nsSVGStopFrame; + if (nsnull == it) + return NS_ERROR_OUT_OF_MEMORY; + + *aNewFrame = it; + + return NS_OK; +}