1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "SVGGradientFrame.h"
11 // Keep others in (case-insensitive) order:
12 #include "AutoReferenceChainGuard.h"
13 #include "gfxPattern.h"
15 #include "mozilla/PresShell.h"
16 #include "mozilla/SVGObserverUtils.h"
17 #include "mozilla/SVGUtils.h"
18 #include "mozilla/dom/SVGGradientElement.h"
19 #include "mozilla/dom/SVGGradientElementBinding.h"
20 #include "mozilla/dom/SVGStopElement.h"
21 #include "mozilla/dom/SVGUnitTypesBinding.h"
22 #include "nsContentUtils.h"
23 #include "SVGAnimatedTransformList.h"
25 // XXX Tight coupling with content classes ahead!
27 using namespace mozilla::dom
;
28 using namespace mozilla::dom::SVGGradientElement_Binding
;
29 using namespace mozilla::dom::SVGUnitTypes_Binding
;
30 using namespace mozilla::gfx
;
34 //----------------------------------------------------------------------
37 SVGGradientFrame::SVGGradientFrame(ComputedStyle
* aStyle
,
38 nsPresContext
* aPresContext
, ClassID aID
)
39 : SVGPaintServerFrame(aStyle
, aPresContext
, aID
),
44 NS_QUERYFRAME_HEAD(SVGGradientFrame
)
45 NS_QUERYFRAME_ENTRY(SVGGradientFrame
)
46 NS_QUERYFRAME_TAIL_INHERITING(SVGPaintServerFrame
)
48 //----------------------------------------------------------------------
51 nsresult
SVGGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
54 if (aNameSpaceID
== kNameSpaceID_None
&&
55 (aAttribute
== nsGkAtoms::gradientUnits
||
56 aAttribute
== nsGkAtoms::gradientTransform
||
57 aAttribute
== nsGkAtoms::spreadMethod
)) {
58 SVGObserverUtils::InvalidateRenderingObservers(this);
59 } else if ((aNameSpaceID
== kNameSpaceID_XLink
||
60 aNameSpaceID
== kNameSpaceID_None
) &&
61 aAttribute
== nsGkAtoms::href
) {
62 // Blow away our reference, if any
63 SVGObserverUtils::RemoveTemplateObserver(this);
65 // And update whoever references us
66 SVGObserverUtils::InvalidateRenderingObservers(this);
69 return SVGPaintServerFrame::AttributeChanged(aNameSpaceID
, aAttribute
,
73 //----------------------------------------------------------------------
75 uint16_t SVGGradientFrame::GetEnumValue(uint32_t aIndex
, nsIContent
* aDefault
) {
76 const SVGAnimatedEnumeration
& thisEnum
=
77 static_cast<dom::SVGGradientElement
*>(GetContent())
78 ->mEnumAttributes
[aIndex
];
80 if (thisEnum
.IsExplicitlySet()) {
81 return thisEnum
.GetAnimValue();
84 // Before we recurse, make sure we'll break reference loops and over long
86 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
87 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
88 &sRefChainLengthCounter
);
89 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
90 // Break reference chain
91 return static_cast<dom::SVGGradientElement
*>(aDefault
)
92 ->mEnumAttributes
[aIndex
]
96 SVGGradientFrame
* next
= GetReferencedGradient();
98 return next
? next
->GetEnumValue(aIndex
, aDefault
)
99 : static_cast<dom::SVGGradientElement
*>(aDefault
)
100 ->mEnumAttributes
[aIndex
]
104 uint16_t SVGGradientFrame::GetGradientUnits() {
105 // This getter is called every time the others are called - maybe cache it?
106 return GetEnumValue(dom::SVGGradientElement::GRADIENTUNITS
);
109 uint16_t SVGGradientFrame::GetSpreadMethod() {
110 return GetEnumValue(dom::SVGGradientElement::SPREADMETHOD
);
113 const SVGAnimatedTransformList
* SVGGradientFrame::GetGradientTransformList(
114 nsIContent
* aDefault
) {
115 SVGAnimatedTransformList
* thisTransformList
=
116 static_cast<dom::SVGGradientElement
*>(GetContent())
117 ->GetAnimatedTransformList();
119 if (thisTransformList
&& thisTransformList
->IsExplicitlySet())
120 return thisTransformList
;
122 // Before we recurse, make sure we'll break reference loops and over long
124 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
125 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
126 &sRefChainLengthCounter
);
127 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
128 // Break reference chain
129 return static_cast<const dom::SVGGradientElement
*>(aDefault
)
130 ->mGradientTransform
.get();
133 SVGGradientFrame
* next
= GetReferencedGradient();
135 return next
? next
->GetGradientTransformList(aDefault
)
136 : static_cast<const dom::SVGGradientElement
*>(aDefault
)
137 ->mGradientTransform
.get();
140 gfxMatrix
SVGGradientFrame::GetGradientTransform(
141 nsIFrame
* aSource
, const gfxRect
* aOverrideBounds
) {
142 gfxMatrix bboxMatrix
;
144 uint16_t gradientUnits
= GetGradientUnits();
145 if (gradientUnits
!= SVG_UNIT_TYPE_USERSPACEONUSE
) {
146 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
147 "Unknown gradientUnits type");
148 // objectBoundingBox is the default anyway
150 gfxRect bbox
= aOverrideBounds
153 aSource
, SVGUtils::eUseFrameBoundsForOuterSVG
|
154 SVGUtils::eBBoxIncludeFillGeometry
);
156 gfxMatrix(bbox
.Width(), 0, 0, bbox
.Height(), bbox
.X(), bbox
.Y());
159 const SVGAnimatedTransformList
* animTransformList
=
160 GetGradientTransformList(GetContent());
161 if (!animTransformList
) {
165 gfxMatrix gradientTransform
=
166 animTransformList
->GetAnimValue().GetConsolidationMatrix();
167 return bboxMatrix
.PreMultiply(gradientTransform
);
170 dom::SVGLinearGradientElement
* SVGGradientFrame::GetLinearGradientWithLength(
171 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
172 // If this was a linear gradient with the required length, we would have
173 // already found it in SVGLinearGradientFrame::GetLinearGradientWithLength.
174 // Since we didn't find the length, continue looking down the chain.
176 // Before we recurse, make sure we'll break reference loops and over long
178 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
179 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
180 &sRefChainLengthCounter
);
181 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
182 // Break reference chain
186 SVGGradientFrame
* next
= GetReferencedGradient();
187 return next
? next
->GetLinearGradientWithLength(aIndex
, aDefault
) : aDefault
;
190 dom::SVGRadialGradientElement
* SVGGradientFrame::GetRadialGradientWithLength(
191 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
192 // If this was a radial gradient with the required length, we would have
193 // already found it in SVGRadialGradientFrame::GetRadialGradientWithLength.
194 // Since we didn't find the length, continue looking down the chain.
196 // Before we recurse, make sure we'll break reference loops and over long
198 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
199 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
200 &sRefChainLengthCounter
);
201 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
202 // Break reference chain
206 SVGGradientFrame
* next
= GetReferencedGradient();
207 return next
? next
->GetRadialGradientWithLength(aIndex
, aDefault
) : aDefault
;
210 //----------------------------------------------------------------------
211 // SVGPaintServerFrame methods:
214 static void GetStopInformation(nsIFrame
* aStopFrame
, float* aOffset
,
215 nscolor
* aStopColor
, float* aStopOpacity
) {
216 nsIContent
* stopContent
= aStopFrame
->GetContent();
217 MOZ_ASSERT(stopContent
&& stopContent
->IsSVGElement(nsGkAtoms::stop
));
219 static_cast<SVGStopElement
*>(stopContent
)
220 ->GetAnimatedNumberValues(aOffset
, nullptr);
222 const nsStyleSVGReset
* styleSVGReset
= aStopFrame
->StyleSVGReset();
223 *aOffset
= mozilla::clamped(*aOffset
, 0.0f
, 1.0f
);
224 *aStopColor
= styleSVGReset
->mStopColor
.CalcColor(aStopFrame
);
225 *aStopOpacity
= styleSVGReset
->mStopOpacity
;
228 already_AddRefed
<gfxPattern
> SVGGradientFrame::GetPaintServerPattern(
229 nsIFrame
* aSource
, const DrawTarget
* aDrawTarget
,
230 const gfxMatrix
& aContextMatrix
, StyleSVGPaint
nsStyleSVG::*aFillOrStroke
,
231 float aGraphicOpacity
, imgDrawingParams
& aImgParams
,
232 const gfxRect
* aOverrideBounds
) {
233 uint16_t gradientUnits
= GetGradientUnits();
234 MOZ_ASSERT(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
||
235 gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
);
236 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
237 // Set mSource for this consumer.
238 // If this gradient is applied to text, our caller will be the glyph, which
239 // is not an element, so we need to get the parent
240 mSource
= aSource
->IsTextFrame() ? aSource
->GetParent() : aSource
;
243 AutoTArray
<nsIFrame
*, 8> stopFrames
;
244 GetStopFrames(&stopFrames
);
246 uint32_t nStops
= stopFrames
.Length();
248 // SVG specification says that no stops should be treated like
249 // the corresponding fill or stroke had "none" specified.
251 RefPtr
<gfxPattern
> pattern
= new gfxPattern(DeviceColor());
252 return do_AddRef(new gfxPattern(DeviceColor()));
255 if (nStops
== 1 || GradientVectorLengthIsZero()) {
256 auto* lastStopFrame
= stopFrames
[nStops
- 1];
257 const auto* svgReset
= lastStopFrame
->StyleSVGReset();
258 // The gradient paints a single colour, using the stop-color of the last
259 // gradient step if there are more than one.
260 float stopOpacity
= svgReset
->mStopOpacity
;
261 nscolor stopColor
= svgReset
->mStopColor
.CalcColor(lastStopFrame
);
263 sRGBColor stopColor2
= sRGBColor::FromABGR(stopColor
);
264 stopColor2
.a
*= stopOpacity
* aGraphicOpacity
;
265 return do_AddRef(new gfxPattern(ToDeviceColor(stopColor2
)));
268 // Get the transform list (if there is one). We do this after the returns
269 // above since this call can be expensive when "gradientUnits" is set to
270 // "objectBoundingBox" (since that requiring a GetBBox() call).
271 gfxMatrix patternMatrix
= GetGradientTransform(aSource
, aOverrideBounds
);
273 if (patternMatrix
.IsSingular()) {
277 // revert any vector effect transform so that the gradient appears unchanged
278 if (aFillOrStroke
== &nsStyleSVG::mStroke
) {
279 gfxMatrix userToOuterSVG
;
280 if (SVGUtils::GetNonScalingStrokeTransform(aSource
, &userToOuterSVG
)) {
281 patternMatrix
*= userToOuterSVG
;
285 if (!patternMatrix
.Invert()) {
289 RefPtr
<gfxPattern
> gradient
= CreateGradient();
294 uint16_t aSpread
= GetSpreadMethod();
295 if (aSpread
== SVG_SPREADMETHOD_PAD
)
296 gradient
->SetExtend(ExtendMode::CLAMP
);
297 else if (aSpread
== SVG_SPREADMETHOD_REFLECT
)
298 gradient
->SetExtend(ExtendMode::REFLECT
);
299 else if (aSpread
== SVG_SPREADMETHOD_REPEAT
)
300 gradient
->SetExtend(ExtendMode::REPEAT
);
302 gradient
->SetMatrix(patternMatrix
);
305 float lastOffset
= 0.0f
;
307 for (uint32_t i
= 0; i
< nStops
; i
++) {
308 float offset
, stopOpacity
;
311 GetStopInformation(stopFrames
[i
], &offset
, &stopColor
, &stopOpacity
);
313 if (offset
< lastOffset
)
318 sRGBColor stopColor2
= sRGBColor::FromABGR(stopColor
);
319 stopColor2
.a
*= stopOpacity
* aGraphicOpacity
;
320 gradient
->AddColorStop(offset
, ToDeviceColor(stopColor2
));
323 return gradient
.forget();
326 // Private (helper) methods
328 SVGGradientFrame
* SVGGradientFrame::GetReferencedGradient() {
333 auto GetHref
= [this](nsAString
& aHref
) {
334 dom::SVGGradientElement
* grad
=
335 static_cast<dom::SVGGradientElement
*>(this->GetContent());
336 if (grad
->mStringAttributes
[dom::SVGGradientElement::HREF
]
337 .IsExplicitlySet()) {
338 grad
->mStringAttributes
[dom::SVGGradientElement::HREF
].GetAnimValue(aHref
,
341 grad
->mStringAttributes
[dom::SVGGradientElement::XLINK_HREF
].GetAnimValue(
344 this->mNoHRefURI
= aHref
.IsEmpty();
347 // We don't call SVGObserverUtils::RemoveTemplateObserver and set
348 // `mNoHRefURI = false` on failure since we want to be invalidated if the ID
349 // specified by our href starts resolving to a different/valid element.
351 return do_QueryFrame(SVGObserverUtils::GetAndObserveTemplate(this, GetHref
));
354 void SVGGradientFrame::GetStopFrames(nsTArray
<nsIFrame
*>* aStopFrames
) {
355 nsIFrame
* stopFrame
= nullptr;
356 for (stopFrame
= mFrames
.FirstChild(); stopFrame
;
357 stopFrame
= stopFrame
->GetNextSibling()) {
358 if (stopFrame
->IsSVGStopFrame()) {
359 aStopFrames
->AppendElement(stopFrame
);
362 if (aStopFrames
->Length() > 0) {
366 // Our gradient element doesn't have stops - try to "inherit" them
368 // Before we recurse, make sure we'll break reference loops and over long
370 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
371 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
372 &sRefChainLengthCounter
);
373 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
374 // Break reference chain
378 SVGGradientFrame
* next
= GetReferencedGradient();
380 next
->GetStopFrames(aStopFrames
);
384 // -------------------------------------------------------------------------
386 // -------------------------------------------------------------------------
388 NS_QUERYFRAME_HEAD(SVGLinearGradientFrame
)
389 NS_QUERYFRAME_ENTRY(SVGLinearGradientFrame
)
390 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
393 void SVGLinearGradientFrame::Init(nsIContent
* aContent
,
394 nsContainerFrame
* aParent
,
395 nsIFrame
* aPrevInFlow
) {
396 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::linearGradient
),
397 "Content is not an SVG linearGradient");
399 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
403 nsresult
SVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
406 if (aNameSpaceID
== kNameSpaceID_None
&&
407 (aAttribute
== nsGkAtoms::x1
|| aAttribute
== nsGkAtoms::y1
||
408 aAttribute
== nsGkAtoms::x2
|| aAttribute
== nsGkAtoms::y2
)) {
409 SVGObserverUtils::InvalidateRenderingObservers(this);
412 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
415 //----------------------------------------------------------------------
417 float SVGLinearGradientFrame::GetLengthValue(uint32_t aIndex
) {
418 dom::SVGLinearGradientElement
* lengthElement
= GetLinearGradientWithLength(
419 aIndex
, static_cast<dom::SVGLinearGradientElement
*>(GetContent()));
420 // We passed in mContent as a fallback, so, assuming mContent is non-null, the
421 // return value should also be non-null.
422 MOZ_ASSERT(lengthElement
,
423 "Got unexpected null element from GetLinearGradientWithLength");
424 const SVGAnimatedLength
& length
= lengthElement
->mLengthAttributes
[aIndex
];
426 // Object bounding box units are handled by setting the appropriate
427 // transform in GetGradientTransform, but we need to handle user
428 // space units as part of the individual Get* routines. Fixes 323669.
430 uint16_t gradientUnits
= GetGradientUnits();
431 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
432 return SVGUtils::UserSpace(mSource
, &length
);
435 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
436 "Unknown gradientUnits type");
438 return length
.GetAnimValue(static_cast<SVGViewportElement
*>(nullptr));
441 dom::SVGLinearGradientElement
*
442 SVGLinearGradientFrame::GetLinearGradientWithLength(
443 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
444 dom::SVGLinearGradientElement
* thisElement
=
445 static_cast<dom::SVGLinearGradientElement
*>(GetContent());
446 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
448 if (length
.IsExplicitlySet()) {
452 return SVGGradientFrame::GetLinearGradientWithLength(aIndex
, aDefault
);
455 bool SVGLinearGradientFrame::GradientVectorLengthIsZero() {
456 return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
) ==
457 GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
) &&
458 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
) ==
459 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
462 already_AddRefed
<gfxPattern
> SVGLinearGradientFrame::CreateGradient() {
463 float x1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
);
464 float y1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
);
465 float x2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
);
466 float y2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
468 RefPtr
<gfxPattern
> pattern
= new gfxPattern(x1
, y1
, x2
, y2
);
469 return pattern
.forget();
472 // -------------------------------------------------------------------------
474 // -------------------------------------------------------------------------
476 NS_QUERYFRAME_HEAD(SVGRadialGradientFrame
)
477 NS_QUERYFRAME_ENTRY(SVGRadialGradientFrame
)
478 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
481 void SVGRadialGradientFrame::Init(nsIContent
* aContent
,
482 nsContainerFrame
* aParent
,
483 nsIFrame
* aPrevInFlow
) {
484 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::radialGradient
),
485 "Content is not an SVG radialGradient");
487 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
491 nsresult
SVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
494 if (aNameSpaceID
== kNameSpaceID_None
&&
495 (aAttribute
== nsGkAtoms::r
|| aAttribute
== nsGkAtoms::cx
||
496 aAttribute
== nsGkAtoms::cy
|| aAttribute
== nsGkAtoms::fx
||
497 aAttribute
== nsGkAtoms::fy
)) {
498 SVGObserverUtils::InvalidateRenderingObservers(this);
501 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
504 //----------------------------------------------------------------------
506 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
) {
507 dom::SVGRadialGradientElement
* lengthElement
= GetRadialGradientWithLength(
508 aIndex
, static_cast<dom::SVGRadialGradientElement
*>(GetContent()));
509 // We passed in mContent as a fallback, so, assuming mContent is non-null,
510 // the return value should also be non-null.
511 MOZ_ASSERT(lengthElement
,
512 "Got unexpected null element from GetRadialGradientWithLength");
513 return GetLengthValueFromElement(aIndex
, *lengthElement
);
516 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
,
517 float aDefaultValue
) {
518 dom::SVGRadialGradientElement
* lengthElement
=
519 GetRadialGradientWithLength(aIndex
, nullptr);
521 return lengthElement
? GetLengthValueFromElement(aIndex
, *lengthElement
)
525 float SVGRadialGradientFrame::GetLengthValueFromElement(
526 uint32_t aIndex
, dom::SVGRadialGradientElement
& aElement
) {
527 const SVGAnimatedLength
& length
= aElement
.mLengthAttributes
[aIndex
];
529 // Object bounding box units are handled by setting the appropriate
530 // transform in GetGradientTransform, but we need to handle user
531 // space units as part of the individual Get* routines. Fixes 323669.
533 uint16_t gradientUnits
= GetGradientUnits();
534 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
535 return SVGUtils::UserSpace(mSource
, &length
);
538 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
539 "Unknown gradientUnits type");
541 return length
.GetAnimValue(static_cast<SVGViewportElement
*>(nullptr));
544 dom::SVGRadialGradientElement
*
545 SVGRadialGradientFrame::GetRadialGradientWithLength(
546 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
547 dom::SVGRadialGradientElement
* thisElement
=
548 static_cast<dom::SVGRadialGradientElement
*>(GetContent());
549 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
551 if (length
.IsExplicitlySet()) {
555 return SVGGradientFrame::GetRadialGradientWithLength(aIndex
, aDefault
);
558 bool SVGRadialGradientFrame::GradientVectorLengthIsZero() {
559 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
560 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
561 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
562 // If fx or fy are not set, use cx/cy instead
563 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
564 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
565 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
566 return cx
== fx
&& cy
== fy
&& r
== fr
;
569 already_AddRefed
<gfxPattern
> SVGRadialGradientFrame::CreateGradient() {
570 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
571 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
572 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
573 // If fx or fy are not set, use cx/cy instead
574 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
575 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
576 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
578 RefPtr
<gfxPattern
> pattern
= new gfxPattern(fx
, fy
, fr
, cx
, cy
, r
);
579 return pattern
.forget();
582 } // namespace mozilla
584 // -------------------------------------------------------------------------
586 // -------------------------------------------------------------------------
588 nsIFrame
* NS_NewSVGLinearGradientFrame(mozilla::PresShell
* aPresShell
,
589 mozilla::ComputedStyle
* aStyle
) {
590 return new (aPresShell
)
591 mozilla::SVGLinearGradientFrame(aStyle
, aPresShell
->GetPresContext());
594 nsIFrame
* NS_NewSVGRadialGradientFrame(mozilla::PresShell
* aPresShell
,
595 mozilla::ComputedStyle
* aStyle
) {
596 return new (aPresShell
)
597 mozilla::SVGRadialGradientFrame(aStyle
, aPresShell
->GetPresContext());
602 NS_IMPL_FRAMEARENA_HELPERS(SVGLinearGradientFrame
)
603 NS_IMPL_FRAMEARENA_HELPERS(SVGRadialGradientFrame
)
605 } // namespace mozilla