1836734
[gecko.git] / 
blob18367346fd918260a741bcec46fa3ca2e55af857
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is the Mozilla SVG project.
16  *
17  * The Initial Developer of the Original Code is
18  * Scooter Morris.
19  * Portions created by the Initial Developer are Copyright (C) 2004
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Scooter Morris <scootermorris@comcast.net>
24  *   Jonathan Watt <jwatt@jwatt.org>
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either the GNU General Public License Version 2 or later (the "GPL"), or
28  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
40 #include "nsIDOMSVGAnimatedNumber.h"
41 #include "nsIDOMSVGAnimTransformList.h"
42 #include "nsSVGTransformList.h"
43 #include "nsSVGMatrix.h"
44 #include "nsSVGEffects.h"
45 #include "nsIDOMSVGStopElement.h"
46 #include "nsSVGGradientElement.h"
47 #include "nsSVGGeometryFrame.h"
48 #include "nsSVGGradientFrame.h"
49 #include "gfxContext.h"
50 #include "gfxPattern.h"
52 //----------------------------------------------------------------------
53 // Implementation
55 nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext) :
56   nsSVGGradientFrameBase(aContext),
57   mLoopFlag(PR_FALSE),
58   mNoHRefURI(PR_FALSE)
62 NS_IMPL_FRAMEARENA_HELPERS(nsSVGGradientFrame)
64 //----------------------------------------------------------------------
65 // nsIFrame methods:
67 /* virtual */ void
68 nsSVGGradientFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
70   nsSVGEffects::InvalidateRenderingObservers(this);
71   nsSVGGradientFrameBase::DidSetStyleContext(aOldStyleContext);
74 NS_IMETHODIMP
75 nsSVGGradientFrame::AttributeChanged(PRInt32         aNameSpaceID,
76                                      nsIAtom*        aAttribute,
77                                      PRInt32         aModType)
79   if (aNameSpaceID == kNameSpaceID_None &&
80       (aAttribute == nsGkAtoms::gradientUnits ||
81        aAttribute == nsGkAtoms::gradientTransform ||
82        aAttribute == nsGkAtoms::spreadMethod)) {
83     nsSVGEffects::InvalidateRenderingObservers(this);
84   } else if (aNameSpaceID == kNameSpaceID_XLink &&
85              aAttribute == nsGkAtoms::href) {
86     // Blow away our reference, if any
87     Properties().Delete(nsSVGEffects::HrefProperty());
88     mNoHRefURI = PR_FALSE;
89     // And update whoever references us
90     nsSVGEffects::InvalidateRenderingObservers(this);
91   }
93   return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
94                                                   aAttribute, aModType);
97 //----------------------------------------------------------------------
99 PRUint32
100 nsSVGGradientFrame::GetStopCount()
102   return GetStopFrame(-1, nsnull);
105 void
106 nsSVGGradientFrame::GetStopInformation(PRInt32 aIndex,
107                                        float *aOffset,
108                                        nscolor *aStopColor,
109                                        float *aStopOpacity)
111   *aOffset = 0.0f;
112   *aStopColor = NS_RGBA(0, 0, 0, 0);
113   *aStopOpacity = 1.0f;
115   nsIFrame *stopFrame = nsnull;
116   GetStopFrame(aIndex, &stopFrame);
117   nsCOMPtr<nsIDOMSVGStopElement> stopElement =
118     do_QueryInterface(stopFrame->GetContent());
120   if (stopElement) {
121     nsCOMPtr<nsIDOMSVGAnimatedNumber> aNum;
122     stopElement->GetOffset(getter_AddRefs(aNum));
124     aNum->GetAnimVal(aOffset);
125     if (*aOffset < 0.0f)
126       *aOffset = 0.0f;
127     else if (*aOffset > 1.0f)
128       *aOffset = 1.0f;
129   }
131   if (stopFrame) {
132     *aStopColor   = stopFrame->GetStyleSVGReset()->mStopColor;
133     *aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity;
134   }
135 #ifdef DEBUG
136   // One way or another we have an implementation problem if we get here
137   else if (stopElement) {
138     NS_WARNING("We *do* have a stop but can't use it because it doesn't have "
139                "a frame - we need frame free gradients and stops!");
140   }
141   else {
142     NS_ERROR("Don't call me with an invalid stop index!");
143   }
144 #endif
147 gfxMatrix
148 nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
149                                          const gfxRect *aOverrideBounds)
151   gfxMatrix bboxMatrix;
153   PRUint16 gradientUnits = GetGradientUnits();
154   if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
155     // If this gradient is applied to text, our caller
156     // will be the glyph, which is not a container, so we
157     // need to get the parent
158     if (aSource->GetContent()->IsNodeOfType(nsINode::eTEXT))
159       mSource = aSource->GetParent();
160     else
161       mSource = aSource;
162   } else {
163     NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
164                  "Unknown gradientUnits type");
165     // objectBoundingBox is the default anyway
167     nsIFrame *frame = aSource->GetContent()->IsNodeOfType(nsINode::eTEXT) ?
168                         aSource->GetParent() : aSource;
169     gfxRect bbox = aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(frame);
170     bboxMatrix = gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
171   }
173   nsSVGGradientElement *element =
174     GetGradientWithAttr(nsGkAtoms::gradientTransform, mContent);
176   if (!element->mGradientTransform)
177     return bboxMatrix;
179   nsCOMPtr<nsIDOMSVGTransformList> trans;
180   element->mGradientTransform->GetAnimVal(getter_AddRefs(trans));
181   nsCOMPtr<nsIDOMSVGMatrix> gradientTransform =
182     nsSVGTransformList::GetConsolidationMatrix(trans);
184   if (!gradientTransform)
185     return bboxMatrix;
187   return bboxMatrix.PreMultiply(nsSVGUtils::ConvertSVGMatrixToThebes(gradientTransform));
190 PRUint16
191 nsSVGGradientFrame::GetSpreadMethod()
193   nsSVGGradientElement *element =
194     GetGradientWithAttr(nsGkAtoms::spreadMethod, mContent);
196   return element->mEnumAttributes[nsSVGGradientElement::SPREADMETHOD].GetAnimValue();
199 //----------------------------------------------------------------------
200 // nsSVGPaintServerFrame methods:
202 already_AddRefed<gfxPattern>
203 nsSVGGradientFrame::GetPaintServerPattern(nsIFrame *aSource,
204                                            float aGraphicOpacity,
205                                            const gfxRect *aOverrideBounds)
207   // Get the transform list (if there is one)
208   gfxMatrix patternMatrix = GetGradientTransform(aSource, aOverrideBounds);
210   if (patternMatrix.IsSingular())
211     return nsnull;
213   PRUint32 nStops = GetStopCount();
215   // SVG specification says that no stops should be treated like
216   // the corresponding fill or stroke had "none" specified.
217   if (nStops == 0) {
218     nsRefPtr<gfxPattern> pattern = new gfxPattern(gfxRGBA(0, 0, 0, 0));
219     return pattern.forget();
220   }
222   patternMatrix.Invert();
224   nsRefPtr<gfxPattern> gradient = CreateGradient();
225   if (!gradient || gradient->CairoStatus())
226     return nsnull;
228   PRUint16 aSpread = GetSpreadMethod();
229   if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_PAD)
230     gradient->SetExtend(gfxPattern::EXTEND_PAD);
231   else if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_REFLECT)
232     gradient->SetExtend(gfxPattern::EXTEND_REFLECT);
233   else if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_REPEAT)
234     gradient->SetExtend(gfxPattern::EXTEND_REPEAT);
236   gradient->SetMatrix(patternMatrix);
238   // setup stops
239   float lastOffset = 0.0f;
241   for (PRUint32 i = 0; i < nStops; i++) {
242     float offset, stopOpacity;
243     nscolor stopColor;
245     GetStopInformation(i, &offset, &stopColor, &stopOpacity);
247     if (offset < lastOffset)
248       offset = lastOffset;
249     else
250       lastOffset = offset;
252     gradient->AddColorStop(offset,
253                            gfxRGBA(NS_GET_R(stopColor)/255.0,
254                                    NS_GET_G(stopColor)/255.0,
255                                    NS_GET_B(stopColor)/255.0,
256                                    NS_GET_A(stopColor)/255.0 *
257                                      stopOpacity * aGraphicOpacity));
258   }
260   return gradient.forget();
263 // Private (helper) methods
265 nsSVGGradientFrame *
266 nsSVGGradientFrame::GetReferencedGradient()
268   if (mNoHRefURI)
269     return nsnull;
271   nsSVGPaintingProperty *property = static_cast<nsSVGPaintingProperty*>
272     (Properties().Get(nsSVGEffects::HrefProperty()));
274   if (!property) {
275     // Fetch our gradient element's xlink:href attribute
276     nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(mContent);
277     nsAutoString href;
278     grad->mStringAttributes[nsSVGGradientElement::HREF].GetAnimValue(href, grad);
279     if (href.IsEmpty()) {
280       mNoHRefURI = PR_TRUE;
281       return nsnull; // no URL
282     }
284     // Convert href to an nsIURI
285     nsCOMPtr<nsIURI> targetURI;
286     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
287     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
288                                               mContent->GetCurrentDoc(), base);
290     property =
291       nsSVGEffects::GetPaintingProperty(targetURI, this, nsSVGEffects::HrefProperty());
292     if (!property)
293       return nsnull;
294   }
296   nsIFrame *result = property->GetReferencedFrame();
297   if (!result)
298     return nsnull;
300   nsIAtom* frameType = result->GetType();
301   if (frameType != nsGkAtoms::svgLinearGradientFrame &&
302       frameType != nsGkAtoms::svgRadialGradientFrame)
303     return nsnull;
305   return static_cast<nsSVGGradientFrame*>(result);
308 nsSVGGradientElement *
309 nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
311   if (mContent->HasAttr(kNameSpaceID_None, aAttrName))
312     return static_cast<nsSVGGradientElement *>(mContent);
314   nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
316   nsSVGGradientFrame *next = GetReferencedGradient();
317   if (!next)
318     return grad;
320   // Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
321   mLoopFlag = PR_TRUE;
322   // XXXjwatt: we should really send an error to the JavaScript Console here:
323   NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
324                                      "while inheriting attribute!");
325   if (!next->mLoopFlag)
326     grad = next->GetGradientWithAttr(aAttrName, aDefault);
327   mLoopFlag = PR_FALSE;
329   return grad;
332 nsSVGGradientElement *
333 nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType,
334                                         nsIContent *aDefault)
336   if (GetType() == aGradType && mContent->HasAttr(kNameSpaceID_None, aAttrName))
337     return static_cast<nsSVGGradientElement *>(mContent);
339   nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
341   nsSVGGradientFrame *next = GetReferencedGradient();
342   if (!next)
343     return grad;
345   // Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
346   mLoopFlag = PR_TRUE;
347   // XXXjwatt: we should really send an error to the JavaScript Console here:
348   NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
349                                      "while inheriting attribute!");
350   if (!next->mLoopFlag)
351     grad = next->GetGradientWithAttr(aAttrName, aGradType, aDefault);
352   mLoopFlag = PR_FALSE;
354   return grad;
357 PRInt32
358 nsSVGGradientFrame::GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame)
360   PRInt32 stopCount = 0;
361   nsIFrame *stopFrame = nsnull;
362   for (stopFrame = mFrames.FirstChild(); stopFrame;
363        stopFrame = stopFrame->GetNextSibling()) {
364     if (stopFrame->GetType() == nsGkAtoms::svgStopFrame) {
365       // Is this the one we're looking for?
366       if (stopCount++ == aIndex)
367         break; // Yes, break out of the loop
368     }
369   }
370   if (stopCount > 0) {
371     if (aStopFrame)
372       *aStopFrame = stopFrame;
373     return stopCount;
374   }
376   // Our gradient element doesn't have stops - try to "inherit" them
378   nsSVGGradientFrame *next = GetReferencedGradient();
379   if (!next) {
380     if (aStopFrame)
381       *aStopFrame = nsnull;
382     return 0;
383   }
385   // Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
386   mLoopFlag = PR_TRUE;
387   // XXXjwatt: we should really send an error to the JavaScript Console here:
388   NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
389                                      "while inheriting stop!");
390   if (!next->mLoopFlag)
391     stopCount = next->GetStopFrame(aIndex, aStopFrame);
392   mLoopFlag = PR_FALSE;
394   return stopCount;
397 PRUint16
398 nsSVGGradientFrame::GetGradientUnits()
400   // This getter is called every time the others are called - maybe cache it?
402   nsSVGGradientElement *element =
403     GetGradientWithAttr(nsGkAtoms::gradientUnits, mContent);
404   return element->mEnumAttributes[nsSVGGradientElement::GRADIENTUNITS].GetAnimValue();
407 // -------------------------------------------------------------------------
408 // Linear Gradients
409 // -------------------------------------------------------------------------
411 #ifdef DEBUG
412 NS_IMETHODIMP
413 nsSVGLinearGradientFrame::Init(nsIContent* aContent,
414                                nsIFrame* aParent,
415                                nsIFrame* aPrevInFlow)
417   nsCOMPtr<nsIDOMSVGLinearGradientElement> grad = do_QueryInterface(aContent);
418   NS_ASSERTION(grad, "Content is not an SVG linearGradient");
420   return nsSVGLinearGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
422 #endif /* DEBUG */
424 nsIAtom*
425 nsSVGLinearGradientFrame::GetType() const
427   return nsGkAtoms::svgLinearGradientFrame;
430 NS_IMETHODIMP
431 nsSVGLinearGradientFrame::AttributeChanged(PRInt32         aNameSpaceID,
432                                            nsIAtom*        aAttribute,
433                                            PRInt32         aModType)
435   if (aNameSpaceID == kNameSpaceID_None &&
436       (aAttribute == nsGkAtoms::x1 ||
437        aAttribute == nsGkAtoms::y1 ||
438        aAttribute == nsGkAtoms::x2 ||
439        aAttribute == nsGkAtoms::y2)) {
440     nsSVGEffects::InvalidateRenderingObservers(this);
441   }
443   return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
444                                               aAttribute, aModType);
447 //----------------------------------------------------------------------
449 float
450 nsSVGLinearGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
451                                                   PRUint16 aEnumName)
453   nsSVGLinearGradientElement *element =
454     GetLinearGradientWithAttr(aAtomName, mContent);
456   // Object bounding box units are handled by setting the appropriate
457   // transform in GetGradientTransform, but we need to handle user
458   // space units as part of the individual Get* routines.  Fixes 323669.
460   PRUint16 gradientUnits = GetGradientUnits();
461   if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
462     return nsSVGUtils::UserSpace(mSource,
463                                  &element->mLengthAttributes[aEnumName]);
464   }
466   NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
467                "Unknown gradientUnits type");
469   return element->mLengthAttributes[aEnumName].
470     GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
473 already_AddRefed<gfxPattern>
474 nsSVGLinearGradientFrame::CreateGradient()
476   float x1, y1, x2, y2;
478   x1 = GradientLookupAttribute(nsGkAtoms::x1, nsSVGLinearGradientElement::X1);
479   y1 = GradientLookupAttribute(nsGkAtoms::y1, nsSVGLinearGradientElement::Y1);
480   x2 = GradientLookupAttribute(nsGkAtoms::x2, nsSVGLinearGradientElement::X2);
481   y2 = GradientLookupAttribute(nsGkAtoms::y2, nsSVGLinearGradientElement::Y2);
483   gfxPattern *pattern = new gfxPattern(x1, y1, x2, y2);
484   NS_IF_ADDREF(pattern);
485   return pattern;
488 // -------------------------------------------------------------------------
489 // Radial Gradients
490 // -------------------------------------------------------------------------
492 #ifdef DEBUG
493 NS_IMETHODIMP
494 nsSVGRadialGradientFrame::Init(nsIContent* aContent,
495                                nsIFrame* aParent,
496                                nsIFrame* aPrevInFlow)
498   nsCOMPtr<nsIDOMSVGRadialGradientElement> grad = do_QueryInterface(aContent);
499   NS_ASSERTION(grad, "Content is not an SVG radialGradient");
501   return nsSVGRadialGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
503 #endif /* DEBUG */
505 nsIAtom*
506 nsSVGRadialGradientFrame::GetType() const
508   return nsGkAtoms::svgRadialGradientFrame;
511 NS_IMETHODIMP
512 nsSVGRadialGradientFrame::AttributeChanged(PRInt32         aNameSpaceID,
513                                            nsIAtom*        aAttribute,
514                                            PRInt32         aModType)
516   if (aNameSpaceID == kNameSpaceID_None &&
517       (aAttribute == nsGkAtoms::r ||
518        aAttribute == nsGkAtoms::cx ||
519        aAttribute == nsGkAtoms::cy ||
520        aAttribute == nsGkAtoms::fx ||
521        aAttribute == nsGkAtoms::fy)) {
522     nsSVGEffects::InvalidateRenderingObservers(this);
523   }
525   return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
526                                               aAttribute, aModType);
529 //----------------------------------------------------------------------
531 float
532 nsSVGRadialGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
533                                                   PRUint16 aEnumName,
534                                                   nsSVGRadialGradientElement *aElement)
536   nsSVGRadialGradientElement *element;
538   if (aElement) {
539     element = aElement;
540   } else {
541     element = GetRadialGradientWithAttr(aAtomName, mContent);
542   }
544   // Object bounding box units are handled by setting the appropriate
545   // transform in GetGradientTransform, but we need to handle user
546   // space units as part of the individual Get* routines.  Fixes 323669.
548   PRUint16 gradientUnits = GetGradientUnits();
549   if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
550     return nsSVGUtils::UserSpace(mSource,
551                                  &element->mLengthAttributes[aEnumName]);
552   }
554   NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
555                "Unknown gradientUnits type");
557   return element->mLengthAttributes[aEnumName].
558     GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
561 already_AddRefed<gfxPattern>
562 nsSVGRadialGradientFrame::CreateGradient()
564   float cx, cy, r, fx, fy;
566   cx = GradientLookupAttribute(nsGkAtoms::cx, nsSVGRadialGradientElement::CX);
567   cy = GradientLookupAttribute(nsGkAtoms::cy, nsSVGRadialGradientElement::CY);
568   r  = GradientLookupAttribute(nsGkAtoms::r,  nsSVGRadialGradientElement::R);
570   nsSVGRadialGradientElement *gradient;
572   if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fx, nsnull)))
573     fx = cx;  // if fx isn't set, we must use cx
574   else
575     fx = GradientLookupAttribute(nsGkAtoms::fx, nsSVGRadialGradientElement::FX, gradient);
577   if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fy, nsnull)))
578     fy = cy;  // if fy isn't set, we must use cy
579   else
580     fy = GradientLookupAttribute(nsGkAtoms::fy, nsSVGRadialGradientElement::FY, gradient);
582   if (fx != cx || fy != cy) {
583     // The focal point (fFx and fFy) must be clamped to be *inside* - not on -
584     // the circumference of the gradient or we'll get rendering anomalies. We
585     // calculate the distance from the focal point to the gradient center and
586     // make sure it is *less* than the gradient radius.
587     // 1/128 is the limit of the fractional part of cairo's 24.8 fixed point
588     // representation divided by 2 to ensure that we get different cairo
589     // fractions
590     double dMax = NS_MAX(0.0, r - 1.0/128);
591     float dx = fx - cx;
592     float dy = fy - cy;
593     double d = sqrt((dx * dx) + (dy * dy));
594     if (d > dMax) {
595       double angle = atan2(dy, dx);
596       fx = (float)(dMax * cos(angle)) + cx;
597       fy = (float)(dMax * sin(angle)) + cy;
598     }
599   }
601   gfxPattern *pattern = new gfxPattern(fx, fy, 0, cx, cy, r);
602   NS_IF_ADDREF(pattern);
603   return pattern;
606 // -------------------------------------------------------------------------
607 // Public functions
608 // -------------------------------------------------------------------------
610 nsIFrame*
611 NS_NewSVGLinearGradientFrame(nsIPresShell*   aPresShell,
612                              nsStyleContext* aContext)
614   return new (aPresShell) nsSVGLinearGradientFrame(aContext);
617 NS_IMPL_FRAMEARENA_HELPERS(nsSVGLinearGradientFrame)
619 nsIFrame*
620 NS_NewSVGRadialGradientFrame(nsIPresShell*   aPresShell,
621                              nsStyleContext* aContext)
623   return new (aPresShell) nsSVGRadialGradientFrame(aContext);
626 NS_IMPL_FRAMEARENA_HELPERS(nsSVGRadialGradientFrame)