Back to index

lightning-sunbird  0.9+nobinonly
nsSVGGradientFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Mozilla SVG project.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Scooter Morris.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Scooter Morris <scootermorris@comcast.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsSVGGenericContainerFrame.h"
00040 #include "nsSVGGradient.h"
00041 #include "nsIDOMDocument.h"
00042 #include "nsIDocument.h"
00043 #include "nsIDOMSVGStopElement.h"
00044 #include "nsSVGAtoms.h"
00045 #include "nsIDOMSVGLength.h"
00046 #include "nsIDOMSVGAnimatedEnum.h"
00047 #include "nsIDOMSVGAnimatedLength.h"
00048 #include "nsIDOMSVGAnimatedNumber.h"
00049 #include "nsIDOMSVGAnimatedString.h"
00050 #include "nsIDOMSVGAnimTransformList.h"
00051 #include "nsIDOMSVGTransformList.h"
00052 #include "nsIDOMSVGNumber.h"
00053 #include "nsIDOMSVGGradientElement.h"
00054 #include "nsIDOMSVGURIReference.h"
00055 #include "nsISVGValue.h"
00056 #include "nsISVGValueUtils.h"
00057 #include "nsStyleContext.h"
00058 #include "nsSVGValue.h"
00059 #include "nsNetUtil.h"
00060 #include "nsINameSpaceManager.h"
00061 #include "nsISVGChildFrame.h"
00062 #include "nsIDOMSVGRect.h"
00063 #include "nsSVGMatrix.h"
00064 #include "nsISVGGeometrySource.h"
00065 #include "nsISVGGradient.h"
00066 #include "nsIURI.h"
00067 #include "nsIContent.h"
00068 #include "nsSVGNumber.h"
00069 #include "nsIDOMSVGStopElement.h"
00070 #include "nsSVGUtils.h"
00071 #include "nsWeakReference.h"
00072 #include "nsISVGValueObserver.h"
00073   
00074 typedef nsSVGGenericContainerFrame  nsSVGGradientFrameBase;
00075 
00076 class nsSVGGradientFrame : public nsSVGGradientFrameBase,
00077                            public nsSVGValue,
00078                            public nsISVGValueObserver,
00079                            public nsSupportsWeakReference,
00080                            public nsISVGGradient
00081 {
00082 protected:
00083   friend nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, 
00084                                                nsIContent*   aContent, 
00085                                                nsIFrame**    aNewFrame);
00086 
00087   friend nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, 
00088                                                nsIContent*   aContent, 
00089                                                nsIFrame**    aNewFrame);
00090 
00091   friend nsresult NS_NewSVGStopFrame(nsIPresShell* aPresShell, 
00092                                      nsIContent*   aContent, 
00093                                      nsIFrame*     aParentFrame, 
00094                                      nsIFrame**    aNewFrame);
00095 
00096   friend nsresult NS_GetSVGGradientFrame(nsIFrame**      result, 
00097                                          nsIURI*         aURI, 
00098                                          nsIContent*     aContent,
00099                                          nsIPresShell*   aPresShell);
00100 
00101 
00102 public:
00103   // nsISupports interface:
00104   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00105   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00106   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
00107 
00108   // nsISVGGradient interface:
00109   NS_DECL_NSISVGGRADIENT
00110 
00111   // nsISVGValue interface:
00112   NS_IMETHOD SetValueString(const nsAString &aValue) { return NS_OK; }
00113   NS_IMETHOD GetValueString(nsAString& aValue) { return NS_ERROR_NOT_IMPLEMENTED; }
00114 
00115   // nsISVGValueObserver interface:
00116   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable, 
00117                                      nsISVGValue::modificationType aModType);
00118   NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable, 
00119                                     nsISVGValue::modificationType aModType);
00120 
00121   // nsIFrame interface:
00122   NS_IMETHOD DidSetStyleContext(nsPresContext* aPresContext);
00123   NS_IMETHOD RemoveFrame(nsIAtom*        aListName,
00124                          nsIFrame*       aOldFrame);
00125 
00131   virtual nsIAtom* GetType() const;
00132 
00133   // nsISVGChildFrame interface:
00134   // Override PaintSVG (our frames don't directly render)
00135   NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas,
00136                       const nsRect& dirtyRectTwips,
00137                       PRBool ignoreFilter) {return NS_OK;}
00138   
00139 #ifdef DEBUG
00140   NS_IMETHOD GetFrameName(nsAString& aResult) const
00141   {
00142     return MakeFrameName(NS_LITERAL_STRING("SVGGradient"), aResult);
00143   }
00144 #endif // DEBUG
00145 
00146 protected:
00147   virtual ~nsSVGGradientFrame();
00148 
00149   // Internal methods for handling referenced gradients
00150   PRBool checkURITarget(nsIAtom *);
00151   PRBool checkURITarget();
00152   //
00153   NS_IMETHOD PrivateGetGradientUnits(nsIDOMSVGAnimatedEnumeration * *aEnum);
00154   NS_IMETHOD PrivateGetSpreadMethod(nsIDOMSVGAnimatedEnumeration * *aValue);
00155   //
00156 
00157   nsSVGGradientFrame                     *mNextGrad;
00158   PRBool                                  mLoopFlag;
00159   nsCOMPtr<nsIContent>                    mSourceContent;
00160 
00161 private:
00162   // Cached values
00163   nsCOMPtr<nsIDOMSVGAnimatedEnumeration>  mGradientUnits;
00164   nsCOMPtr<nsIDOMSVGAnimatedEnumeration>  mSpreadMethod;
00165 
00166   nsAutoString                            mNextGradStr;
00167 
00168   PRInt32 GetStopElement(PRInt32 aIndex, 
00169                          nsIDOMSVGStopElement * *aStopElement,
00170                          nsIFrame * *aStopFrame);
00171 };
00172 
00173 // -------------------------------------------------------------------------
00174 // Linear Gradients
00175 // -------------------------------------------------------------------------
00176 
00177 typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase;
00178 
00179 class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase,
00180                                  public nsISVGLinearGradient
00181 {
00182 public:
00183   // nsISupports interface:
00184   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00185   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00186   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
00187 
00188   // nsISVGLinearGradient interface:
00189   NS_DECL_NSISVGLINEARGRADIENT
00190 
00191   // nsISVGGradient interface gets inherited from nsSVGGradientFrame
00192 
00198   virtual nsIAtom* GetType() const;
00199 
00200 #ifdef DEBUG
00201   NS_IMETHOD GetFrameName(nsAString& aResult) const
00202   {
00203     return MakeFrameName(NS_LITERAL_STRING("SVGLinearGradient"), aResult);
00204   }
00205 #endif // DEBUG
00206 
00207 
00208 protected:
00209   virtual ~nsSVGLinearGradientFrame();
00210 
00211   NS_IMETHOD PrivateGetX1(nsIDOMSVGLength * *aX1);
00212   NS_IMETHOD PrivateGetX2(nsIDOMSVGLength * *aX2);
00213   NS_IMETHOD PrivateGetY1(nsIDOMSVGLength * *aY1);
00214   NS_IMETHOD PrivateGetY2(nsIDOMSVGLength * *aY2);
00215 
00216 private:
00217   nsCOMPtr<nsIDOMSVGLength>       mX1;
00218   nsCOMPtr<nsIDOMSVGLength>       mX2;
00219   nsCOMPtr<nsIDOMSVGLength>       mY1;
00220   nsCOMPtr<nsIDOMSVGLength>       mY2;
00221 };
00222 
00223 // -------------------------------------------------------------------------
00224 // Radial Gradients
00225 // -------------------------------------------------------------------------
00226 
00227 typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase;
00228 
00229 class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase,
00230                                  public nsISVGRadialGradient
00231 {
00232 public:
00233    // nsISupports interface:
00234   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00235   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00236   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
00237 
00238   // nsISVGRadialGradient interface:
00239   NS_DECL_NSISVGRADIALGRADIENT
00240 
00241   // nsISVGGradient interface gets inherited from nsSVGGradientFrame
00242 
00248   virtual nsIAtom* GetType() const;
00249 
00250 #ifdef DEBUG
00251   NS_IMETHOD GetFrameName(nsAString& aResult) const
00252   {
00253     return MakeFrameName(NS_LITERAL_STRING("SVGRadialGradient"), aResult);
00254   }
00255 #endif // DEBUG
00256 
00257 protected:
00258   virtual ~nsSVGRadialGradientFrame();
00259 
00260   NS_IMETHOD PrivateGetCx(nsIDOMSVGLength * *aCx);
00261   NS_IMETHOD PrivateGetCy(nsIDOMSVGLength * *aCy);
00262   NS_IMETHOD PrivateGetFx(nsIDOMSVGLength * *aFx);
00263   NS_IMETHOD PrivateGetFy(nsIDOMSVGLength * *aFy);
00264   NS_IMETHOD PrivateGetR(nsIDOMSVGLength * *aR);
00265 
00266 private:
00267   nsCOMPtr<nsIDOMSVGLength>       mCx;
00268   nsCOMPtr<nsIDOMSVGLength>       mCy;
00269   nsCOMPtr<nsIDOMSVGLength>       mFx;
00270   nsCOMPtr<nsIDOMSVGLength>       mFy;
00271   nsCOMPtr<nsIDOMSVGLength>       mR;
00272 
00273 };
00274 
00275 //----------------------------------------------------------------------
00276 // Implementation
00277 
00278 nsSVGGradientFrame::~nsSVGGradientFrame()
00279 {
00280   WillModify();
00281   // Notify the world that we're dying
00282   DidModify(mod_die);
00283 
00284   // Remove observers on gradient attributes
00285   if (mGradientUnits) NS_REMOVE_SVGVALUE_OBSERVER(mGradientUnits);
00286   if (mSpreadMethod) NS_REMOVE_SVGVALUE_OBSERVER(mSpreadMethod);
00287   if (mNextGrad) mNextGrad->RemoveObserver(this);
00288 }
00289 
00290 //----------------------------------------------------------------------
00291 // nsISupports methods:
00292 
00293 NS_INTERFACE_MAP_BEGIN(nsSVGGradientFrame)
00294   NS_INTERFACE_MAP_ENTRY(nsISVGValue)
00295   NS_INTERFACE_MAP_ENTRY(nsISVGGradient)
00296   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00297   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00298   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
00299 NS_INTERFACE_MAP_END_INHERITING(nsSVGGradientFrameBase)
00300 
00301 //----------------------------------------------------------------------
00302 // nsISVGValueObserver methods:
00303 NS_IMETHODIMP
00304 nsSVGGradientFrame::WillModifySVGObservable(nsISVGValue* observable,
00305                                             modificationType aModType)
00306 {
00307   WillModify(aModType);
00308   return NS_OK;
00309 }
00310                                                                                 
00311 NS_IMETHODIMP
00312 nsSVGGradientFrame::DidModifySVGObservable(nsISVGValue* observable, 
00313                                            nsISVGValue::modificationType aModType)
00314 {
00315   nsCOMPtr<nsISVGGradient> gradient = do_QueryInterface(observable);
00316   // Is this a gradient we are observing that is going away?
00317   if (mNextGrad && aModType == nsISVGValue::mod_die && gradient) {
00318     // Yes, we need to handle this differently
00319     nsISVGGradient *grad;
00320     CallQueryInterface(mNextGrad, &grad);
00321     if (grad == gradient) {
00322       mNextGrad = nsnull;
00323     }
00324   }
00325   // Something we depend on was modified -- pass it on!
00326   DidModify(aModType);
00327   return NS_OK;
00328 }
00329 
00330 //----------------------------------------------------------------------
00331 // nsIFrame methods:
00332 
00333 NS_IMETHODIMP
00334 nsSVGGradientFrame::DidSetStyleContext(nsPresContext* aPresContext)
00335 {
00336   WillModify(mod_other);
00337   DidModify(mod_other);
00338   return NS_OK;
00339 }
00340 
00341 NS_IMETHODIMP
00342 nsSVGGradientFrame::RemoveFrame(nsIAtom*        aListName,
00343                                 nsIFrame*       aOldFrame)
00344 {
00345   WillModify(mod_other);
00346   PRBool result = mFrames.DestroyFrame(GetPresContext(), aOldFrame);
00347   DidModify(mod_other);
00348   return result ? NS_OK : NS_ERROR_FAILURE;
00349 }
00350 
00351 nsIAtom*
00352 nsSVGGradientFrame::GetType() const
00353 {
00354   return nsLayoutAtoms::svgGradientFrame;
00355 }
00356 
00357 //----------------------------------------------------------------------
00358 //  nsISVGGradient implementation
00359 //----------------------------------------------------------------------
00360 
00361 NS_IMETHODIMP
00362 nsSVGGradientFrame::GetStopCount(PRUint32 *aStopCount)
00363 {
00364   nsresult rv = NS_OK;
00365   nsIDOMSVGStopElement *stopElement = nsnull;
00366   *aStopCount = GetStopElement(-1, &stopElement, nsnull);
00367   if (*aStopCount == 0) {
00368     // No stops?  check for URI target
00369     if (checkURITarget())
00370       rv = mNextGrad->GetStopCount(aStopCount);
00371     else
00372       rv = NS_ERROR_FAILURE;
00373   }
00374   mLoopFlag = PR_FALSE;
00375   return rv;
00376 }
00377 
00378 NS_IMETHODIMP
00379 nsSVGGradientFrame::GetStopOffset(PRInt32 aIndex, float *aOffset)
00380 {
00381   nsIDOMSVGStopElement *stopElement = nsnull;
00382   nsresult rv = NS_OK;
00383   PRInt32 stopCount = GetStopElement(aIndex, &stopElement, nsnull);
00384 
00385   if (stopElement) {
00386     nsCOMPtr<nsIDOMSVGAnimatedNumber> aNum;
00387     stopElement->GetOffset(getter_AddRefs(aNum));
00388     aNum->GetAnimVal(aOffset);
00389     if (*aOffset < 0.0f)
00390       *aOffset = 0.0f;
00391     if (*aOffset > 1.0f)
00392       *aOffset = 1.0f;
00393 
00394     return NS_OK;
00395   }
00396 
00397   // if our gradient doesn't have its own stops we must check if it references
00398   // another gradient in which case we must attempt to "inherit" its stops
00399   if (stopCount == 0 && checkURITarget()) {
00400     rv = mNextGrad->GetStopOffset(aIndex, aOffset);
00401   }
00402   else {
00403     *aOffset = 0.0f;
00404     rv = NS_ERROR_FAILURE;
00405   }
00406   mLoopFlag = PR_FALSE;
00407   return rv;
00408 }
00409 
00410 NS_IMETHODIMP
00411 nsSVGGradientFrame::GetStopColor(PRInt32 aIndex, nscolor *aStopColor) 
00412 {
00413   nsIDOMSVGStopElement *stopElement = nsnull;
00414   nsIFrame *stopFrame = nsnull;
00415   nsresult rv = NS_OK;
00416   PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame);
00417 
00418   if (stopElement) {
00419     if (!stopFrame) {
00420       NS_ERROR("No stop frame found!");
00421       *aStopColor = 0;
00422       return NS_ERROR_FAILURE;
00423     }
00424     *aStopColor = stopFrame->GetStyleSVGReset()->mStopColor.mPaint.mColor;
00425 
00426     return NS_OK;
00427   }
00428 
00429   // if our gradient doesn't have its own stops we must check if it references
00430   // another gradient in which case we must attempt to "inherit" its stops
00431   if (stopCount == 0 && checkURITarget()) {
00432     rv = mNextGrad->GetStopColor(aIndex, aStopColor);
00433   }
00434   else {
00435     *aStopColor = 0;
00436     rv = NS_ERROR_FAILURE;
00437   }
00438   mLoopFlag = PR_FALSE;
00439   return rv;
00440 }
00441 
00442 NS_IMETHODIMP
00443 nsSVGGradientFrame::GetStopOpacity(PRInt32 aIndex, float *aStopOpacity) 
00444 {
00445   nsIDOMSVGStopElement *stopElement = nsnull;
00446   nsIFrame *stopFrame = nsnull;
00447   nsresult rv = NS_OK;
00448   PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame);
00449 
00450   if (stopElement) {
00451     if (!stopFrame) {
00452       NS_ERROR("No stop frame found!");
00453       *aStopOpacity = 1.0f;
00454       return NS_ERROR_FAILURE;
00455     }
00456     *aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity;
00457 
00458     return NS_OK;
00459   }
00460 
00461   // if our gradient doesn't have its own stops we must check if it references
00462   // another gradient in which case we must attempt to "inherit" its stops
00463   if (stopCount == 0 && checkURITarget()) {
00464     rv = mNextGrad->GetStopOpacity(aIndex, aStopOpacity);
00465   }
00466   else {
00467     *aStopOpacity = 0;
00468     rv = NS_ERROR_FAILURE;
00469   }
00470   mLoopFlag = PR_FALSE;
00471   return rv;
00472 }
00473 
00474 NS_IMETHODIMP
00475 nsSVGGradientFrame::GetGradientType(PRUint32 *aType)
00476 {
00477   nsCOMPtr<nsIDOMSVGLinearGradientElement> aLe = do_QueryInterface(mContent);
00478   if (aLe) {
00479     *aType = nsISVGGradient::SVG_LINEAR_GRADIENT;
00480     return NS_OK;
00481   }
00482 
00483   nsCOMPtr<nsIDOMSVGRadialGradientElement> aRe = do_QueryInterface(mContent);
00484   if (aRe) {
00485     *aType = nsISVGGradient::SVG_RADIAL_GRADIENT;
00486     return NS_OK;
00487   }
00488   *aType = nsISVGGradient::SVG_UNKNOWN_GRADIENT;
00489   return NS_OK;
00490 }
00491 
00492 NS_IMETHODIMP
00493 nsSVGGradientFrame::GetGradientUnits(PRUint16 *aUnits)
00494 {
00495   if (!mGradientUnits) {
00496     PrivateGetGradientUnits(getter_AddRefs(mGradientUnits));
00497     if (!mGradientUnits)
00498       return NS_ERROR_FAILURE;
00499     NS_ADD_SVGVALUE_OBSERVER(mGradientUnits);
00500   }
00501   mGradientUnits->GetAnimVal(aUnits);
00502   return NS_OK;
00503 }
00504 
00505 NS_IMETHODIMP
00506 nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform,
00507                                          nsISVGGeometrySource *aSource)
00508 {
00509   *aGradientTransform = nsnull;
00510   nsCOMPtr<nsIDOMSVGAnimatedTransformList> aTrans;
00511   nsCOMPtr<nsIDOMSVGGradientElement> aGrad = do_QueryInterface(mContent);
00512   NS_ASSERTION(aGrad, "Wrong content element (not gradient)");
00513   if (aGrad == nsnull) {
00514     return NS_ERROR_FAILURE;
00515   }
00516 
00517   nsCOMPtr<nsIDOMSVGMatrix> bboxTransform;
00518   PRUint16 bbox;
00519   GetGradientUnits(&bbox);
00520   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
00521     nsISVGChildFrame *frame = nsnull;
00522     if (aSource)
00523       CallQueryInterface(aSource, &frame);
00524     nsCOMPtr<nsIDOMSVGRect> rect;
00525     if (frame) {
00526       frame->SetMatrixPropagation(PR_FALSE);
00527       frame->NotifyCanvasTMChanged();
00528       frame->GetBBox(getter_AddRefs(rect));
00529       frame->SetMatrixPropagation(PR_TRUE);
00530       frame->NotifyCanvasTMChanged();
00531     }
00532     if (rect) {
00533       float x, y, width, height;
00534       rect->GetX(&x);
00535       rect->GetY(&y);
00536       rect->GetWidth(&width);
00537       rect->GetHeight(&height);
00538       NS_NewSVGMatrix(getter_AddRefs(bboxTransform),
00539                       width, 0, 0, height, x, y);
00540     }
00541   } else if (aSource) {
00542     nsIFrame *frame = nsnull;
00543     CallQueryInterface(aSource, &frame);
00544 
00545     nsIAtom *callerType = frame->GetType();
00546     if (callerType == nsLayoutAtoms::svgGlyphFrame)
00547       mSourceContent = frame->GetContent()->GetParent();
00548     else
00549       mSourceContent = frame->GetContent();
00550   }
00551 
00552   if (!bboxTransform)
00553     NS_NewSVGMatrix(getter_AddRefs(bboxTransform));
00554 
00555   nsCOMPtr<nsIDOMSVGMatrix> gradientTransform;
00556   // See if we need to get the value from another gradient
00557   if (!checkURITarget(nsSVGAtoms::gradientTransform)) {
00558     // No, return the values
00559     aGrad->GetGradientTransform(getter_AddRefs(aTrans));
00560     nsCOMPtr<nsIDOMSVGTransformList> lTrans;
00561     aTrans->GetAnimVal(getter_AddRefs(lTrans));
00562     lTrans->GetConsolidationMatrix(getter_AddRefs(gradientTransform));
00563   } else {
00564     // Yes, get it from the target
00565     mNextGrad->GetGradientTransform(getter_AddRefs(gradientTransform), nsnull);
00566   }
00567 
00568   bboxTransform->Multiply(gradientTransform, aGradientTransform);
00569   mLoopFlag = PR_FALSE;
00570   return NS_OK;
00571 }
00572 
00573 NS_IMETHODIMP
00574 nsSVGGradientFrame::GetSpreadMethod(PRUint16 *aSpreadMethod)
00575 {
00576   if (!mSpreadMethod) {
00577     PrivateGetSpreadMethod(getter_AddRefs(mSpreadMethod));
00578     if (!mSpreadMethod)
00579       return NS_ERROR_FAILURE;
00580     NS_ADD_SVGVALUE_OBSERVER(mSpreadMethod);
00581   }
00582   mSpreadMethod->GetAnimVal(aSpreadMethod);
00583   return NS_OK;
00584 }
00585 
00586 // -------------------------------------------------------------
00587 // Protected versions of the various "Get" routines.  These need
00588 // to be used to allow for the ability to delegate to referenced
00589 // gradients
00590 // -------------------------------------------------------------
00591 NS_IMETHODIMP
00592 nsSVGGradientFrame::PrivateGetGradientUnits(nsIDOMSVGAnimatedEnumeration * *aEnum)
00593 {
00594   nsCOMPtr<nsIDOMSVGGradientElement> aGrad = do_QueryInterface(mContent);
00595   NS_ASSERTION(aGrad, "Wrong content element (not gradient)");
00596   if (aGrad == nsnull) {
00597     return NS_ERROR_FAILURE;
00598   }
00599   // See if we need to get the value from another gradient
00600   if (!checkURITarget(nsSVGAtoms::gradientUnits)) {
00601     // No, return the values
00602     aGrad->GetGradientUnits(aEnum);
00603   } else {
00604     // Yes, get it from the target
00605     mNextGrad->PrivateGetGradientUnits(aEnum);
00606     mLoopFlag = PR_FALSE;
00607   }
00608   return NS_OK;
00609 }
00610 
00611 NS_IMETHODIMP
00612 nsSVGGradientFrame::PrivateGetSpreadMethod(nsIDOMSVGAnimatedEnumeration * *aEnum)
00613 {
00614   nsCOMPtr<nsIDOMSVGGradientElement> aGrad = do_QueryInterface(mContent);
00615   NS_ASSERTION(aGrad, "Wrong content element (not gradient)");
00616   if (aGrad == nsnull) {
00617     return NS_ERROR_FAILURE;
00618   }
00619   // See if we need to get the value from another gradient
00620   if (!checkURITarget(nsSVGAtoms::spreadMethod)) {
00621     // No, return the values
00622     aGrad->GetSpreadMethod(aEnum);
00623   } else {
00624     // Yes, get it from the target
00625     mNextGrad->PrivateGetSpreadMethod(aEnum);
00626   }
00627   mLoopFlag = PR_FALSE;
00628   return NS_OK;
00629 }
00630 
00631 NS_IMETHODIMP
00632 nsSVGGradientFrame::GetNextGradient(nsISVGGradient * *aNextGrad, PRUint32 aType) {
00633   PRUint32 nextType;
00634   if (!mNextGrad) {
00635     *aNextGrad = nsnull;
00636     return NS_ERROR_FAILURE;
00637   }
00638   mNextGrad->GetGradientType(&nextType);
00639   if (nextType == aType) {
00640     *aNextGrad = mNextGrad;
00641     return NS_OK;
00642   } else {
00643     return mNextGrad->GetNextGradient(aNextGrad, aType);
00644   }
00645 }
00646 
00647 // Private (helper) methods
00648 PRBool 
00649 nsSVGGradientFrame::checkURITarget(nsIAtom *attr) {
00650   // Was the attribute explicitly set?
00651   if (mContent->HasAttr(kNameSpaceID_None, attr)) {
00652     // Yes, just return
00653     return PR_FALSE;
00654   }
00655   return checkURITarget();
00656 }
00657 
00658 PRBool
00659 nsSVGGradientFrame::checkURITarget(void) {
00660   nsIFrame *aNextGrad;
00661   mLoopFlag = PR_TRUE; // Set our loop detection flag
00662   // Have we already figured out the next Gradient?
00663   if (mNextGrad != nsnull) {
00664     return PR_TRUE;
00665   }
00666 
00667   // Do we have URI?
00668   if (mNextGradStr.Length() == 0) {
00669     return PR_FALSE; // No, return the default
00670   }
00671 
00672   // Get the Gradient
00673   nsCAutoString aGradStr;
00674   CopyUTF16toUTF8(mNextGradStr, aGradStr);
00675   // Note that we are using *our* frame tree for this call, otherwise we're going to have
00676   // to get the PresShell in each call
00677   if (nsSVGUtils::GetReferencedFrame(&aNextGrad, aGradStr, mContent, GetPresContext()->PresShell()) == NS_OK) {
00678     nsIAtom* frameType = aNextGrad->GetType();
00679     if ((frameType != nsLayoutAtoms::svgLinearGradientFrame) && 
00680         (frameType != nsLayoutAtoms::svgRadialGradientFrame))
00681       return PR_FALSE;
00682 
00683     mNextGrad = (nsSVGGradientFrame *)aNextGrad;
00684     if (mNextGrad->mLoopFlag) {
00685       // Yes, remove the reference and return an error
00686       NS_WARNING("Gradient loop detected!");
00687       CopyUTF8toUTF16("", mNextGradStr);
00688       mNextGrad = nsnull;
00689       return PR_FALSE;
00690     }
00691     // Add ourselves to the observer list
00692     if (mNextGrad) {
00693       // Can't use the NS_ADD macro here because of nsISupports ambiguity
00694       mNextGrad->AddObserver(this);
00695     }
00696     return PR_TRUE;
00697   }
00698   return PR_FALSE;
00699 }
00700 
00701 // -------------------------------------------------------------------------
00702 // Private helper method to simplify getting stop elements
00703 // returns non-addrefed stop element
00704 // -------------------------------------------------------------------------
00705 PRInt32 
00706 nsSVGGradientFrame::GetStopElement(PRInt32 aIndex, nsIDOMSVGStopElement * *aStopElement,
00707                                    nsIFrame * *aStopFrame)
00708 {
00709   PRInt32 stopCount = 0;
00710   nsIFrame *stopFrame;
00711   for (stopFrame = mFrames.FirstChild(); stopFrame;
00712        stopFrame = stopFrame->GetNextSibling()) {
00713     nsCOMPtr<nsIDOMSVGStopElement>stopElement = do_QueryInterface(stopFrame->GetContent());
00714     if (stopElement) {
00715       // Is this the one we're looking for?
00716       if (stopCount++ == aIndex) {
00717         *aStopElement = stopElement;
00718         break; // Yes, break out of the loop
00719       }
00720     }
00721   }
00722   if (aStopFrame)
00723     *aStopFrame = stopFrame;
00724   return stopCount;
00725 }
00726 
00727 // -------------------------------------------------------------------------
00728 // Linear Gradients
00729 // -------------------------------------------------------------------------
00730 
00731 nsIAtom*
00732 nsSVGLinearGradientFrame::GetType() const
00733 {
00734   return nsLayoutAtoms::svgLinearGradientFrame;
00735 }
00736 
00737 //----------------------------------------------------------------------
00738 // nsISupports methods
00739 
00740 NS_INTERFACE_MAP_BEGIN(nsSVGLinearGradientFrame)
00741   NS_INTERFACE_MAP_ENTRY(nsISVGLinearGradient)
00742 NS_INTERFACE_MAP_END_INHERITING(nsSVGLinearGradientFrameBase)
00743 
00744 // Implementation
00745 nsSVGLinearGradientFrame::~nsSVGLinearGradientFrame()
00746 {
00747   if (mX1) NS_REMOVE_SVGVALUE_OBSERVER(mX1);
00748   if (mY1) NS_REMOVE_SVGVALUE_OBSERVER(mY1);
00749   if (mX2) NS_REMOVE_SVGVALUE_OBSERVER(mX2);
00750   if (mY2) NS_REMOVE_SVGVALUE_OBSERVER(mY2);
00751 }
00752 
00753 nsresult
00754 nsSVGLinearGradientFrame::PrivateGetX1(nsIDOMSVGLength * *aX1)
00755 {
00756   nsCOMPtr<nsIDOMSVGLinearGradientElement> aLgrad = do_QueryInterface(mContent);
00757   NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)");
00758   if (aLgrad == nsnull) {
00759     return NS_ERROR_FAILURE;
00760   }
00761   // See if we need to get the value from another gradient
00762   if (checkURITarget(nsSVGAtoms::x1)) {
00763     // Yes, get it from the target
00764     nsISVGGradient *aNextGrad;
00765     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) {
00766       nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad;
00767       aLNgrad->PrivateGetX1(aX1);
00768       mLoopFlag = PR_FALSE;
00769       return NS_OK;
00770     }
00771     // There are no gradients in the list with our type -- fall through
00772     // and return our default value
00773   }
00774   // No, return the values
00775   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
00776   aLgrad->GetX1(getter_AddRefs(aLen));
00777   aLen->GetAnimVal(aX1);
00778   mLoopFlag = PR_FALSE;
00779   return NS_OK;
00780 }
00781 
00782 nsresult
00783 nsSVGLinearGradientFrame::PrivateGetY1(nsIDOMSVGLength * *aY1)
00784 {
00785   nsCOMPtr<nsIDOMSVGLinearGradientElement> aLgrad = do_QueryInterface(mContent);
00786   NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)");
00787   if (aLgrad == nsnull) {
00788     return NS_ERROR_FAILURE;
00789   }
00790   // See if we need to get the value from another gradient
00791   if (checkURITarget(nsSVGAtoms::y1)) {
00792     // Yes, get it from the target
00793     nsISVGGradient *aNextGrad;
00794     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) {
00795       nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad;
00796       aLNgrad->PrivateGetY1(aY1);
00797       mLoopFlag = PR_FALSE;
00798       return NS_OK;
00799     }
00800     // There are no gradients in the list with our type -- fall through
00801     // and return our default value
00802   }
00803   // No, return the values
00804   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
00805   aLgrad->GetY1(getter_AddRefs(aLen));
00806   aLen->GetAnimVal(aY1);
00807   mLoopFlag = PR_FALSE;
00808   return NS_OK;
00809 }
00810 
00811 nsresult
00812 nsSVGLinearGradientFrame::PrivateGetX2(nsIDOMSVGLength * *aX2)
00813 {
00814   nsCOMPtr<nsIDOMSVGLinearGradientElement> aLgrad = do_QueryInterface(mContent);
00815   NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)");
00816   if (aLgrad == nsnull) {
00817     return NS_ERROR_FAILURE;
00818   }
00819   // See if we need to get the value from another gradient
00820   if (checkURITarget(nsSVGAtoms::x2)) {
00821     // Yes, get it from the target
00822     nsISVGGradient *aNextGrad;
00823     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) {
00824       nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad;
00825       aLNgrad->PrivateGetX2(aX2);
00826       mLoopFlag = PR_FALSE;
00827       return NS_OK;
00828     }
00829     // There are no gradients in the list with our type -- fall through
00830     // and return our default value
00831   }
00832   // No, return the values
00833   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
00834   aLgrad->GetX2(getter_AddRefs(aLen));
00835   aLen->GetAnimVal(aX2);
00836   mLoopFlag = PR_FALSE;
00837   return NS_OK;
00838 }
00839 
00840 nsresult
00841 nsSVGLinearGradientFrame::PrivateGetY2(nsIDOMSVGLength * *aY2)
00842 {
00843   nsCOMPtr<nsIDOMSVGLinearGradientElement> aLgrad = do_QueryInterface(mContent);
00844   NS_ASSERTION(aLgrad, "Wrong content element (not linear gradient)");
00845   if (aLgrad == nsnull) {
00846     return NS_ERROR_FAILURE;
00847   }
00848   // See if we need to get the value from another gradient
00849   if (checkURITarget(nsSVGAtoms::y2)) {
00850     // Yes, get it from the target
00851     nsISVGGradient *aNextGrad;
00852     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) {
00853       nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad;
00854       aLNgrad->PrivateGetY2(aY2);
00855       mLoopFlag = PR_FALSE;
00856       return NS_OK;
00857     }
00858     // There are no gradients in the list with our type -- fall through
00859     // and return our default value
00860   }
00861   // No, return the values
00862   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
00863   aLgrad->GetY2(getter_AddRefs(aLen));
00864   aLen->GetAnimVal(aY2);
00865   mLoopFlag = PR_FALSE;
00866   return NS_OK;
00867 }
00868 
00869 // nsISVGLinearGradient
00870 NS_IMETHODIMP
00871 nsSVGLinearGradientFrame::GetX1(float *aX1)
00872 {
00873   if (!mX1) {
00874     PrivateGetX1(getter_AddRefs(mX1));
00875     if (!mX1)
00876       return NS_ERROR_FAILURE;
00877     NS_ADD_SVGVALUE_OBSERVER(mX1);
00878   }
00879   PRUint16 bbox;
00880   GetGradientUnits(&bbox);
00881   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
00882     mX1->GetValue(aX1);
00883   } else {
00884     *aX1 = nsSVGUtils::UserSpace(mSourceContent, mX1, nsSVGUtils::X);
00885   }
00886   return NS_OK;
00887 }
00888 
00889 NS_IMETHODIMP
00890 nsSVGLinearGradientFrame::GetY1(float *aY1)
00891 {
00892   if (!mY1) {
00893     PrivateGetY1(getter_AddRefs(mY1));
00894     if (!mY1)
00895       return NS_ERROR_FAILURE;
00896     NS_ADD_SVGVALUE_OBSERVER(mY1);
00897   }
00898   PRUint16 bbox;
00899   GetGradientUnits(&bbox);
00900   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
00901     mY1->GetValue(aY1);
00902   } else {
00903     *aY1 = nsSVGUtils::UserSpace(mSourceContent, mY1, nsSVGUtils::Y);
00904   }
00905   return NS_OK;
00906 }
00907 
00908 NS_IMETHODIMP
00909 nsSVGLinearGradientFrame::GetX2(float *aX2)
00910 {
00911   if (!mX2) {
00912     PrivateGetX2(getter_AddRefs(mX2));
00913     if (!mX2)
00914       return NS_ERROR_FAILURE;
00915     NS_ADD_SVGVALUE_OBSERVER(mX2);
00916   }
00917   PRUint16 bbox;
00918   GetGradientUnits(&bbox);
00919   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
00920     mX2->GetValue(aX2);
00921   } else {
00922     *aX2 = nsSVGUtils::UserSpace(mSourceContent, mX2, nsSVGUtils::X);
00923   }
00924   return NS_OK;
00925 }
00926 
00927 NS_IMETHODIMP
00928 nsSVGLinearGradientFrame::GetY2(float *aY2)
00929 {
00930   if (!mY2) {
00931     PrivateGetY2(getter_AddRefs(mY2));
00932     if (!mY2)
00933       return NS_ERROR_FAILURE;
00934     NS_ADD_SVGVALUE_OBSERVER(mY2);
00935   }
00936   PRUint16 bbox;
00937   GetGradientUnits(&bbox);
00938   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
00939     mY2->GetValue(aY2);
00940   } else {
00941     *aY2 = nsSVGUtils::UserSpace(mSourceContent, mY2, nsSVGUtils::Y);
00942   }
00943   return NS_OK;
00944 }
00945 
00946 // -------------------------------------------------------------------------
00947 // Radial Gradients
00948 // -------------------------------------------------------------------------
00949 
00950 //----------------------------------------------------------------------
00951 // nsISupports methods
00952 
00953 NS_INTERFACE_MAP_BEGIN(nsSVGRadialGradientFrame)
00954   NS_INTERFACE_MAP_ENTRY(nsISVGRadialGradient)
00955 NS_INTERFACE_MAP_END_INHERITING(nsSVGRadialGradientFrameBase)
00956 
00957 nsIAtom*
00958 nsSVGRadialGradientFrame::GetType() const
00959 {
00960   return nsLayoutAtoms::svgRadialGradientFrame;
00961 }
00962 
00963 // Implementation
00964 nsSVGRadialGradientFrame::~nsSVGRadialGradientFrame()
00965 {
00966   if (mCx) NS_REMOVE_SVGVALUE_OBSERVER(mCx);
00967   if (mCy) NS_REMOVE_SVGVALUE_OBSERVER(mCy);
00968   if (mFx) NS_REMOVE_SVGVALUE_OBSERVER(mFx);
00969   if (mFy) NS_REMOVE_SVGVALUE_OBSERVER(mFy);
00970   if (mR) NS_REMOVE_SVGVALUE_OBSERVER(mR);
00971 }
00972 
00973 
00974 nsresult
00975 nsSVGRadialGradientFrame::PrivateGetCx(nsIDOMSVGLength * *aCx)
00976 {
00977   nsCOMPtr<nsIDOMSVGRadialGradientElement> aRgrad = do_QueryInterface(mContent);
00978   NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)");
00979   if (aRgrad == nsnull) {
00980     return NS_ERROR_FAILURE;
00981   }
00982   // See if we need to get the value from another gradient
00983   if (checkURITarget(nsSVGAtoms::cx)) {
00984     // Yes, get it from the target
00985     nsISVGGradient *aNextGrad;
00986     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) {
00987       nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad;
00988       aRNgrad->PrivateGetCx(aCx);
00989       mLoopFlag = PR_FALSE;
00990       return NS_OK;
00991     }
00992     // There are no gradients in the list with our type -- fall through
00993     // and return our default value
00994   }
00995   // No, return the values
00996   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
00997   aRgrad->GetCx(getter_AddRefs(aLen));
00998   aLen->GetAnimVal(aCx);
00999   mLoopFlag = PR_FALSE;
01000   return NS_OK;
01001 }
01002 
01003 nsresult
01004 nsSVGRadialGradientFrame::PrivateGetCy(nsIDOMSVGLength * *aCy)
01005 {
01006   nsCOMPtr<nsIDOMSVGRadialGradientElement> aRgrad = do_QueryInterface(mContent);
01007   NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)");
01008   if (aRgrad == nsnull) {
01009     return NS_ERROR_FAILURE;
01010   }
01011   // See if we need to get the value from another gradient
01012   if (checkURITarget(nsSVGAtoms::cy)) {
01013     // Yes, get it from the target
01014     nsISVGGradient *aNextGrad;
01015     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) {
01016       nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad;
01017       aRNgrad->PrivateGetCy(aCy);
01018       mLoopFlag = PR_FALSE;
01019       return NS_OK;
01020     }
01021     // There are no gradients in the list with our type -- fall through
01022     // and return our default value
01023   }
01024   // No, return the values
01025   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
01026   aRgrad->GetCy(getter_AddRefs(aLen));
01027   aLen->GetAnimVal(aCy);
01028   mLoopFlag = PR_FALSE;
01029   return NS_OK;
01030 }
01031 
01032 nsresult
01033 nsSVGRadialGradientFrame::PrivateGetR(nsIDOMSVGLength * *aR)
01034 {
01035   nsCOMPtr<nsIDOMSVGRadialGradientElement> aRgrad = do_QueryInterface(mContent);
01036   NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)");
01037   if (aRgrad == nsnull) {
01038     return NS_ERROR_FAILURE;
01039   }
01040   // See if we need to get the value from another gradient
01041   if (checkURITarget(nsSVGAtoms::r)) {
01042     // Yes, get it from the target
01043     nsISVGGradient *aNextGrad;
01044     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) {
01045       nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad;
01046       aRNgrad->PrivateGetR(aR);
01047       mLoopFlag = PR_FALSE;
01048       return NS_OK;
01049     }
01050     // There are no gradients in the list with our type -- fall through
01051     // and return our default value
01052   }
01053   // No, return the values
01054   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
01055   aRgrad->GetR(getter_AddRefs(aLen));
01056   aLen->GetAnimVal(aR);
01057   mLoopFlag = PR_FALSE;
01058   return NS_OK;
01059 }
01060 
01061 nsresult
01062 nsSVGRadialGradientFrame::PrivateGetFx(nsIDOMSVGLength * *aFx)
01063 {
01064   nsCOMPtr<nsIDOMSVGRadialGradientElement> aRgrad = do_QueryInterface(mContent);
01065   NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)");
01066   if (aRgrad == nsnull) {
01067     return NS_ERROR_FAILURE;
01068   }
01069   // See if we need to get the value from another gradient
01070   if (checkURITarget(nsSVGAtoms::fx)) {
01071     // Yes, get it from the target
01072     nsISVGGradient *aNextGrad;
01073     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) {
01074       nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad;
01075       aRNgrad->PrivateGetFx(aFx);
01076       mLoopFlag = PR_FALSE;
01077       return NS_OK;
01078     }
01079     // There are no gradients in the list with our type -- fall through
01080     // and return our default value
01081   }
01082   // See if the value was explicitly set --  the spec
01083   // states that if there is no explicit fx value, we return the cx value
01084   // see http://www.w3.org/TR/SVG11/pservers.html#RadialGradients
01085   if (!mContent->HasAttr(kNameSpaceID_None, nsSVGAtoms::fx))
01086     return PrivateGetCx(aFx);
01087   // No, return the values
01088   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
01089   aRgrad->GetFx(getter_AddRefs(aLen));
01090   aLen->GetAnimVal(aFx);
01091   mLoopFlag = PR_FALSE;
01092   return NS_OK;
01093 }
01094 
01095 nsresult
01096 nsSVGRadialGradientFrame::PrivateGetFy(nsIDOMSVGLength * *aFy)
01097 {
01098   nsCOMPtr<nsIDOMSVGRadialGradientElement> aRgrad = do_QueryInterface(mContent);
01099   NS_ASSERTION(aRgrad, "Wrong content element (not radial gradient)");
01100   if (aRgrad == nsnull) {
01101     return NS_ERROR_FAILURE;
01102   }
01103   // See if we need to get the value from another gradient
01104   if (checkURITarget(nsSVGAtoms::fy)) {
01105     // Yes, get it from the target
01106     nsISVGGradient *aNextGrad;
01107     if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) {
01108       nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad;
01109       aRNgrad->PrivateGetFy(aFy);
01110       mLoopFlag = PR_FALSE;
01111       return NS_OK;
01112     }
01113     // There are no gradients in the list with our type -- fall through
01114     // and return our default value
01115   }
01116   // See if the value was explicitly set --  the spec
01117   // states that if there is no explicit fy value, we return the cy value
01118   // see http://www.w3.org/TR/SVG11/pservers.html#RadialGradients
01119   mLoopFlag = PR_FALSE;
01120   if (!mContent->HasAttr(kNameSpaceID_None, nsSVGAtoms::fy))
01121     return PrivateGetCy(aFy);
01122   // No, return the values
01123   nsCOMPtr<nsIDOMSVGAnimatedLength> aLen;
01124   aRgrad->GetFy(getter_AddRefs(aLen));
01125   aLen->GetAnimVal(aFy);
01126   return NS_OK;
01127 }
01128 
01129 // nsISVGRadialGradient
01130 NS_IMETHODIMP
01131 nsSVGRadialGradientFrame::GetFx(float *aFx)
01132 {
01133   if (!mFx) {
01134     PrivateGetFx(getter_AddRefs(mFx));
01135     if (!mFx)
01136       return NS_ERROR_FAILURE;
01137     NS_ADD_SVGVALUE_OBSERVER(mFx);
01138   }
01139   PRUint16 bbox;
01140   GetGradientUnits(&bbox);
01141   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
01142     mFx->GetValue(aFx);
01143   } else {
01144     *aFx = nsSVGUtils::UserSpace(mSourceContent, mFx, nsSVGUtils::X);
01145   }
01146   return NS_OK;
01147 }
01148 
01149 NS_IMETHODIMP
01150 nsSVGRadialGradientFrame::GetFy(float *aFy)
01151 {
01152   if (!mFy) {
01153     PrivateGetFy(getter_AddRefs(mFy));
01154     if (!mFy)
01155       return NS_ERROR_FAILURE;
01156     NS_ADD_SVGVALUE_OBSERVER(mFy);
01157   }
01158   PRUint16 bbox;
01159   GetGradientUnits(&bbox);
01160   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
01161     mFy->GetValue(aFy);
01162   } else {
01163     *aFy = nsSVGUtils::UserSpace(mSourceContent, mFy, nsSVGUtils::Y);
01164   }
01165   return NS_OK;
01166 }
01167 
01168 NS_IMETHODIMP
01169 nsSVGRadialGradientFrame::GetCx(float *aCx)
01170 {
01171   if (!mCx) {
01172     PrivateGetCx(getter_AddRefs(mCx));
01173     if (!mCx)
01174       return NS_ERROR_FAILURE;
01175     NS_ADD_SVGVALUE_OBSERVER(mCx);
01176   }
01177   PRUint16 bbox;
01178   GetGradientUnits(&bbox);
01179   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
01180     mCx->GetValue(aCx);
01181   } else {
01182     *aCx = nsSVGUtils::UserSpace(mSourceContent, mCx, nsSVGUtils::X);
01183   }
01184   return NS_OK;
01185 }
01186 
01187 NS_IMETHODIMP
01188 nsSVGRadialGradientFrame::GetCy(float *aCy)
01189 {
01190   if (!mCy) {
01191     PrivateGetCy(getter_AddRefs(mCy));
01192     if (!mCy)
01193       return NS_ERROR_FAILURE;
01194     NS_ADD_SVGVALUE_OBSERVER(mCy);
01195   }
01196   PRUint16 bbox;
01197   GetGradientUnits(&bbox);
01198   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
01199     mCy->GetValue(aCy);
01200   } else {
01201     *aCy = nsSVGUtils::UserSpace(mSourceContent, mCy, nsSVGUtils::Y);
01202   }
01203   return NS_OK;
01204 }
01205 
01206 NS_IMETHODIMP
01207 nsSVGRadialGradientFrame::GetR(float *aR)
01208 {
01209   if (!mR) {
01210     PrivateGetR(getter_AddRefs(mR));
01211     if (!mR)
01212       return NS_ERROR_FAILURE;
01213     NS_ADD_SVGVALUE_OBSERVER(mR);
01214   }
01215   PRUint16 bbox;
01216   GetGradientUnits(&bbox);
01217   if (bbox == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX) {
01218     mR->GetValue(aR);
01219   } else {
01220     *aR = nsSVGUtils::UserSpace(mSourceContent, mR, nsSVGUtils::XY);
01221   }
01222   return NS_OK;
01223 }
01224 
01225 // -------------------------------------------------------------------------
01226 // Public functions
01227 // -------------------------------------------------------------------------
01228 
01229 nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, 
01230                                       nsIContent*   aContent, 
01231                                       nsIFrame**    aNewFrame)
01232 {
01233   *aNewFrame = nsnull;
01234   
01235   nsCOMPtr<nsIDOMSVGLinearGradientElement> grad = do_QueryInterface(aContent);
01236   NS_ASSERTION(grad, "NS_NewSVGLinearGradientFrame -- Content doesn't support nsIDOMSVGLinearGradient");
01237   if (!grad)
01238     return NS_ERROR_FAILURE;
01239   
01240   nsSVGLinearGradientFrame* it = new (aPresShell) nsSVGLinearGradientFrame;
01241   if (nsnull == it)
01242     return NS_ERROR_OUT_OF_MEMORY;
01243 
01244   nsCOMPtr<nsIDOMSVGURIReference> aRef = do_QueryInterface(aContent);
01245   NS_ASSERTION(aRef, "NS_NewSVGLinearGradientFrame -- Content doesn't support nsIDOMSVGURIReference");
01246   if (!aRef) {
01247     it->mNextGrad = nsnull;
01248   } else {
01249     // Get the hRef
01250     nsCOMPtr<nsIDOMSVGAnimatedString> aHref;
01251     aRef->GetHref(getter_AddRefs(aHref));
01252 
01253     nsAutoString aStr;
01254     aHref->GetAnimVal(aStr);
01255     it->mNextGradStr = aStr;
01256     it->mNextGrad = nsnull;
01257   }
01258 
01259   it->mLoopFlag = PR_FALSE;
01260   *aNewFrame = it;
01261 
01262   return NS_OK;
01263 }
01264 
01265 nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, 
01266                                       nsIContent*   aContent, 
01267                                       nsIFrame**    aNewFrame)
01268 {
01269   *aNewFrame = nsnull;
01270   
01271   nsCOMPtr<nsIDOMSVGRadialGradientElement> grad = do_QueryInterface(aContent);
01272   NS_ASSERTION(grad, "NS_NewSVGRadialGradientFrame -- Content doesn't support nsIDOMSVGRadialGradient");
01273   if (!grad)
01274     return NS_ERROR_FAILURE;
01275   
01276   nsSVGRadialGradientFrame* it = new (aPresShell) nsSVGRadialGradientFrame;
01277   if (nsnull == it)
01278     return NS_ERROR_OUT_OF_MEMORY;
01279 
01280   nsCOMPtr<nsIDOMSVGURIReference> aRef = do_QueryInterface(aContent);
01281   NS_ASSERTION(aRef, "NS_NewSVGRadialGradientFrame -- Content doesn't support nsIDOMSVGURIReference");
01282   if (!aRef) {
01283     it->mNextGrad = nsnull;
01284   } else {
01285     // Get the hRef
01286     nsCOMPtr<nsIDOMSVGAnimatedString> aHref;
01287     aRef->GetHref(getter_AddRefs(aHref));
01288 
01289     nsAutoString aStr;
01290     aHref->GetAnimVal(aStr);
01291     it->mNextGradStr = aStr;
01292     it->mNextGrad = nsnull;
01293   }
01294 
01295   it->mLoopFlag = PR_FALSE;
01296   *aNewFrame = it;
01297 
01298   return NS_OK;
01299 }
01300 
01301 // Public function to locate the SVGGradientFrame structure pointed to by a URI
01302 // and return a nsISVGGradient
01303 nsresult NS_GetSVGGradient(nsISVGGradient **aGrad, nsIURI *aURI, nsIContent *aContent, 
01304                            nsIPresShell *aPresShell)
01305 {
01306   *aGrad = nsnull;
01307 
01308   // Get the spec from the URI
01309   nsCAutoString uriSpec;
01310   aURI->GetSpec(uriSpec);
01311 #ifdef DEBUG_scooter
01312   printf("NS_GetSVGGradient: uri = %s\n",uriSpec.get());
01313 #endif
01314   nsIFrame *result;
01315   if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&result, 
01316                                                    uriSpec, aContent, aPresShell))) {
01317     return NS_ERROR_FAILURE;
01318   }
01319   return result->QueryInterface(NS_GET_IID(nsISVGGradient), (void **)aGrad);
01320 }