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 using namespace mozilla::dom
;
26 using namespace mozilla::dom::SVGGradientElement_Binding
;
27 using namespace mozilla::dom::SVGUnitTypes_Binding
;
28 using namespace mozilla::gfx
;
32 //----------------------------------------------------------------------
35 SVGGradientFrame::SVGGradientFrame(ComputedStyle
* aStyle
,
36 nsPresContext
* aPresContext
, ClassID aID
)
37 : SVGPaintServerFrame(aStyle
, aPresContext
, aID
),
42 NS_QUERYFRAME_HEAD(SVGGradientFrame
)
43 NS_QUERYFRAME_ENTRY(SVGGradientFrame
)
44 NS_QUERYFRAME_TAIL_INHERITING(SVGPaintServerFrame
)
46 //----------------------------------------------------------------------
49 nsresult
SVGGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
52 if (aNameSpaceID
== kNameSpaceID_None
&&
53 (aAttribute
== nsGkAtoms::gradientUnits
||
54 aAttribute
== nsGkAtoms::gradientTransform
||
55 aAttribute
== nsGkAtoms::spreadMethod
)) {
56 SVGObserverUtils::InvalidateRenderingObservers(this);
57 } else if ((aNameSpaceID
== kNameSpaceID_XLink
||
58 aNameSpaceID
== kNameSpaceID_None
) &&
59 aAttribute
== nsGkAtoms::href
) {
60 // Blow away our reference, if any
61 SVGObserverUtils::RemoveTemplateObserver(this);
63 // And update whoever references us
64 SVGObserverUtils::InvalidateRenderingObservers(this);
67 return SVGPaintServerFrame::AttributeChanged(aNameSpaceID
, aAttribute
,
71 //----------------------------------------------------------------------
73 uint16_t SVGGradientFrame::GetEnumValue(uint32_t aIndex
, nsIContent
* aDefault
) {
74 const SVGAnimatedEnumeration
& thisEnum
=
75 static_cast<dom::SVGGradientElement
*>(GetContent())
76 ->mEnumAttributes
[aIndex
];
78 if (thisEnum
.IsExplicitlySet()) {
79 return thisEnum
.GetAnimValue();
82 // Before we recurse, make sure we'll break reference loops and over long
84 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
85 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
86 &sRefChainLengthCounter
);
87 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
88 // Break reference chain
89 return static_cast<dom::SVGGradientElement
*>(aDefault
)
90 ->mEnumAttributes
[aIndex
]
94 SVGGradientFrame
* next
= GetReferencedGradient();
96 return next
? next
->GetEnumValue(aIndex
, aDefault
)
97 : static_cast<dom::SVGGradientElement
*>(aDefault
)
98 ->mEnumAttributes
[aIndex
]
102 uint16_t SVGGradientFrame::GetGradientUnits() {
103 // This getter is called every time the others are called - maybe cache it?
104 return GetEnumValue(dom::SVGGradientElement::GRADIENTUNITS
);
107 uint16_t SVGGradientFrame::GetSpreadMethod() {
108 return GetEnumValue(dom::SVGGradientElement::SPREADMETHOD
);
111 const SVGAnimatedTransformList
* SVGGradientFrame::GetGradientTransformList(
112 nsIContent
* aDefault
) {
113 SVGAnimatedTransformList
* thisTransformList
=
114 static_cast<dom::SVGGradientElement
*>(GetContent())
115 ->GetAnimatedTransformList();
117 if (thisTransformList
&& thisTransformList
->IsExplicitlySet())
118 return thisTransformList
;
120 // Before we recurse, make sure we'll break reference loops and over long
122 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
123 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
124 &sRefChainLengthCounter
);
125 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
126 // Break reference chain
127 return static_cast<const dom::SVGGradientElement
*>(aDefault
)
128 ->mGradientTransform
.get();
131 SVGGradientFrame
* next
= GetReferencedGradient();
133 return next
? next
->GetGradientTransformList(aDefault
)
134 : static_cast<const dom::SVGGradientElement
*>(aDefault
)
135 ->mGradientTransform
.get();
138 gfxMatrix
SVGGradientFrame::GetGradientTransform(
139 nsIFrame
* aSource
, const gfxRect
* aOverrideBounds
) {
140 gfxMatrix bboxMatrix
;
142 uint16_t gradientUnits
= GetGradientUnits();
143 if (gradientUnits
!= SVG_UNIT_TYPE_USERSPACEONUSE
) {
144 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
145 "Unknown gradientUnits type");
146 // objectBoundingBox is the default anyway
148 gfxRect bbox
= aOverrideBounds
151 aSource
, SVGUtils::eUseFrameBoundsForOuterSVG
|
152 SVGUtils::eBBoxIncludeFillGeometry
);
154 gfxMatrix(bbox
.Width(), 0, 0, bbox
.Height(), bbox
.X(), bbox
.Y());
157 const SVGAnimatedTransformList
* animTransformList
=
158 GetGradientTransformList(GetContent());
159 if (!animTransformList
) {
163 gfxMatrix gradientTransform
=
164 animTransformList
->GetAnimValue().GetConsolidationMatrix();
165 return bboxMatrix
.PreMultiply(gradientTransform
);
168 dom::SVGLinearGradientElement
* SVGGradientFrame::GetLinearGradientWithLength(
169 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
170 // If this was a linear gradient with the required length, we would have
171 // already found it in SVGLinearGradientFrame::GetLinearGradientWithLength.
172 // Since we didn't find the length, continue looking down the chain.
174 // Before we recurse, make sure we'll break reference loops and over long
176 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
177 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
178 &sRefChainLengthCounter
);
179 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
180 // Break reference chain
184 SVGGradientFrame
* next
= GetReferencedGradient();
185 return next
? next
->GetLinearGradientWithLength(aIndex
, aDefault
) : aDefault
;
188 dom::SVGRadialGradientElement
* SVGGradientFrame::GetRadialGradientWithLength(
189 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
190 // If this was a radial gradient with the required length, we would have
191 // already found it in SVGRadialGradientFrame::GetRadialGradientWithLength.
192 // Since we didn't find the length, continue looking down the chain.
194 // Before we recurse, make sure we'll break reference loops and over long
196 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
197 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
198 &sRefChainLengthCounter
);
199 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
200 // Break reference chain
204 SVGGradientFrame
* next
= GetReferencedGradient();
205 return next
? next
->GetRadialGradientWithLength(aIndex
, aDefault
) : aDefault
;
208 //----------------------------------------------------------------------
209 // SVGPaintServerFrame methods:
213 static ColorStop
GetStopInformation(const nsIFrame
* aStopFrame
,
214 float aGraphicOpacity
,
215 float& aLastPosition
) {
216 nsIContent
* stopContent
= aStopFrame
->GetContent();
217 MOZ_ASSERT(stopContent
&& stopContent
->IsSVGElement(nsGkAtoms::stop
));
220 static_cast<SVGStopElement
*>(stopContent
)
221 ->GetAnimatedNumberValues(&position
, nullptr);
223 position
= clamped(position
, 0.0f
, 1.0f
);
225 if (position
< aLastPosition
) {
226 position
= aLastPosition
;
228 aLastPosition
= position
;
231 const auto* svgReset
= aStopFrame
->StyleSVGReset();
233 sRGBColor stopColor
=
234 sRGBColor::FromABGR(svgReset
->mStopColor
.CalcColor(aStopFrame
));
235 stopColor
.a
*= svgReset
->mStopOpacity
* aGraphicOpacity
;
237 return ColorStop(position
, false,
238 StyleAbsoluteColor::FromColor(stopColor
.ToABGR()));
241 class MOZ_STACK_CLASS SVGColorStopInterpolator
242 : public ColorStopInterpolator
<SVGColorStopInterpolator
> {
244 SVGColorStopInterpolator(
245 gfxPattern
* aGradient
, const nsTArray
<ColorStop
>& aStops
,
246 const StyleColorInterpolationMethod
& aStyleColorInterpolationMethod
)
247 : ColorStopInterpolator(aStops
, aStyleColorInterpolationMethod
),
248 mGradient(aGradient
) {}
250 void CreateStop(float aPosition
, DeviceColor aColor
) {
251 mGradient
->AddColorStop(aPosition
, aColor
);
255 gfxPattern
* mGradient
;
258 already_AddRefed
<gfxPattern
> SVGGradientFrame::GetPaintServerPattern(
259 nsIFrame
* aSource
, const DrawTarget
* aDrawTarget
,
260 const gfxMatrix
& aContextMatrix
, StyleSVGPaint
nsStyleSVG::*aFillOrStroke
,
261 float aGraphicOpacity
, imgDrawingParams
& aImgParams
,
262 const gfxRect
* aOverrideBounds
) {
263 uint16_t gradientUnits
= GetGradientUnits();
264 MOZ_ASSERT(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
||
265 gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
);
266 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
267 // Set mSource for this consumer.
268 // If this gradient is applied to text, our caller will be the glyph, which
269 // is not an element, so we need to get the parent
270 mSource
= aSource
->IsTextFrame() ? aSource
->GetParent() : aSource
;
273 AutoTArray
<ColorStop
, 8> stops
;
274 GetStops(&stops
, aGraphicOpacity
);
276 uint32_t nStops
= stops
.Length();
278 // SVG specification says that no stops should be treated like
279 // the corresponding fill or stroke had "none" specified.
281 return do_AddRef(new gfxPattern(DeviceColor()));
284 if (nStops
== 1 || GradientVectorLengthIsZero()) {
285 // The gradient paints a single colour, using the stop-color of the last
286 // gradient step if there are more than one.
287 return do_AddRef(new gfxPattern(ToDeviceColor(stops
.LastElement().mColor
)));
290 // Get the transform list (if there is one). We do this after the returns
291 // above since this call can be expensive when "gradientUnits" is set to
292 // "objectBoundingBox" (since that requiring a GetBBox() call).
293 gfxMatrix patternMatrix
= GetGradientTransform(aSource
, aOverrideBounds
);
295 if (patternMatrix
.IsSingular()) {
299 // revert any vector effect transform so that the gradient appears unchanged
300 if (aFillOrStroke
== &nsStyleSVG::mStroke
) {
301 gfxMatrix userToOuterSVG
;
302 if (SVGUtils::GetNonScalingStrokeTransform(aSource
, &userToOuterSVG
)) {
303 patternMatrix
*= userToOuterSVG
;
307 if (!patternMatrix
.Invert()) {
311 RefPtr
<gfxPattern
> gradient
= CreateGradient();
316 uint16_t aSpread
= GetSpreadMethod();
317 if (aSpread
== SVG_SPREADMETHOD_PAD
)
318 gradient
->SetExtend(ExtendMode::CLAMP
);
319 else if (aSpread
== SVG_SPREADMETHOD_REFLECT
)
320 gradient
->SetExtend(ExtendMode::REFLECT
);
321 else if (aSpread
== SVG_SPREADMETHOD_REPEAT
)
322 gradient
->SetExtend(ExtendMode::REPEAT
);
324 gradient
->SetMatrix(patternMatrix
);
326 if (StyleSVG()->mColorInterpolation
== StyleColorInterpolation::Linearrgb
) {
327 static constexpr auto interpolationMethod
= StyleColorInterpolationMethod
{
328 StyleColorSpace::SrgbLinear
, StyleHueInterpolationMethod::Shorter
};
329 SVGColorStopInterpolator
interpolator(gradient
, stops
, interpolationMethod
);
330 interpolator
.CreateStops();
332 // setup standard sRGB stops
333 for (const auto& stop
: stops
) {
334 gradient
->AddColorStop(stop
.mPosition
, ToDeviceColor(stop
.mColor
));
338 return gradient
.forget();
341 // Private (helper) methods
343 SVGGradientFrame
* SVGGradientFrame::GetReferencedGradient() {
348 auto GetHref
= [this](nsAString
& aHref
) {
349 dom::SVGGradientElement
* grad
=
350 static_cast<dom::SVGGradientElement
*>(this->GetContent());
351 if (grad
->mStringAttributes
[dom::SVGGradientElement::HREF
]
352 .IsExplicitlySet()) {
353 grad
->mStringAttributes
[dom::SVGGradientElement::HREF
].GetAnimValue(aHref
,
356 grad
->mStringAttributes
[dom::SVGGradientElement::XLINK_HREF
].GetAnimValue(
359 this->mNoHRefURI
= aHref
.IsEmpty();
362 // We don't call SVGObserverUtils::RemoveTemplateObserver and set
363 // `mNoHRefURI = false` on failure since we want to be invalidated if the ID
364 // specified by our href starts resolving to a different/valid element.
366 return do_QueryFrame(SVGObserverUtils::GetAndObserveTemplate(this, GetHref
));
369 void SVGGradientFrame::GetStops(nsTArray
<ColorStop
>* aStops
,
370 float aGraphicOpacity
) {
371 float lastPosition
= 0.0f
;
372 for (const auto* stopFrame
: mFrames
) {
373 if (stopFrame
->IsSVGStopFrame()) {
374 aStops
->AppendElement(
375 GetStopInformation(stopFrame
, aGraphicOpacity
, lastPosition
));
378 if (!aStops
->IsEmpty()) {
382 // Our gradient element doesn't have stops - try to "inherit" them
384 // Before we recurse, make sure we'll break reference loops and over long
386 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
387 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
388 &sRefChainLengthCounter
);
389 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
390 // Break reference chain
394 SVGGradientFrame
* next
= GetReferencedGradient();
396 next
->GetStops(aStops
, aGraphicOpacity
);
400 // -------------------------------------------------------------------------
402 // -------------------------------------------------------------------------
404 NS_QUERYFRAME_HEAD(SVGLinearGradientFrame
)
405 NS_QUERYFRAME_ENTRY(SVGLinearGradientFrame
)
406 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
409 void SVGLinearGradientFrame::Init(nsIContent
* aContent
,
410 nsContainerFrame
* aParent
,
411 nsIFrame
* aPrevInFlow
) {
412 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::linearGradient
),
413 "Content is not an SVG linearGradient");
415 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
419 nsresult
SVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
422 if (aNameSpaceID
== kNameSpaceID_None
&&
423 (aAttribute
== nsGkAtoms::x1
|| aAttribute
== nsGkAtoms::y1
||
424 aAttribute
== nsGkAtoms::x2
|| aAttribute
== nsGkAtoms::y2
)) {
425 SVGObserverUtils::InvalidateRenderingObservers(this);
428 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
431 //----------------------------------------------------------------------
433 float SVGLinearGradientFrame::GetLengthValue(uint32_t aIndex
) {
434 dom::SVGLinearGradientElement
* lengthElement
= GetLinearGradientWithLength(
435 aIndex
, static_cast<dom::SVGLinearGradientElement
*>(GetContent()));
436 // We passed in mContent as a fallback, so, assuming mContent is non-null, the
437 // return value should also be non-null.
438 MOZ_ASSERT(lengthElement
,
439 "Got unexpected null element from GetLinearGradientWithLength");
440 const SVGAnimatedLength
& length
= lengthElement
->mLengthAttributes
[aIndex
];
442 // Object bounding box units are handled by setting the appropriate
443 // transform in GetGradientTransform, but we need to handle user
444 // space units as part of the individual Get* routines. Fixes 323669.
446 uint16_t gradientUnits
= GetGradientUnits();
447 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
448 return SVGUtils::UserSpace(mSource
, &length
);
451 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
452 "Unknown gradientUnits type");
454 return length
.GetAnimValue(static_cast<SVGViewportElement
*>(nullptr));
457 dom::SVGLinearGradientElement
*
458 SVGLinearGradientFrame::GetLinearGradientWithLength(
459 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
460 dom::SVGLinearGradientElement
* thisElement
=
461 static_cast<dom::SVGLinearGradientElement
*>(GetContent());
462 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
464 if (length
.IsExplicitlySet()) {
468 return SVGGradientFrame::GetLinearGradientWithLength(aIndex
, aDefault
);
471 bool SVGLinearGradientFrame::GradientVectorLengthIsZero() {
472 return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
) ==
473 GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
) &&
474 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
) ==
475 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
478 already_AddRefed
<gfxPattern
> SVGLinearGradientFrame::CreateGradient() {
479 float x1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
);
480 float y1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
);
481 float x2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
);
482 float y2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
484 return do_AddRef(new gfxPattern(x1
, y1
, x2
, y2
));
487 // -------------------------------------------------------------------------
489 // -------------------------------------------------------------------------
491 NS_QUERYFRAME_HEAD(SVGRadialGradientFrame
)
492 NS_QUERYFRAME_ENTRY(SVGRadialGradientFrame
)
493 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
496 void SVGRadialGradientFrame::Init(nsIContent
* aContent
,
497 nsContainerFrame
* aParent
,
498 nsIFrame
* aPrevInFlow
) {
499 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::radialGradient
),
500 "Content is not an SVG radialGradient");
502 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
506 nsresult
SVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
509 if (aNameSpaceID
== kNameSpaceID_None
&&
510 (aAttribute
== nsGkAtoms::r
|| aAttribute
== nsGkAtoms::cx
||
511 aAttribute
== nsGkAtoms::cy
|| aAttribute
== nsGkAtoms::fx
||
512 aAttribute
== nsGkAtoms::fy
)) {
513 SVGObserverUtils::InvalidateRenderingObservers(this);
516 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
519 //----------------------------------------------------------------------
521 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
) {
522 dom::SVGRadialGradientElement
* lengthElement
= GetRadialGradientWithLength(
523 aIndex
, static_cast<dom::SVGRadialGradientElement
*>(GetContent()));
524 // We passed in mContent as a fallback, so, assuming mContent is non-null,
525 // the return value should also be non-null.
526 MOZ_ASSERT(lengthElement
,
527 "Got unexpected null element from GetRadialGradientWithLength");
528 return GetLengthValueFromElement(aIndex
, *lengthElement
);
531 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
,
532 float aDefaultValue
) {
533 dom::SVGRadialGradientElement
* lengthElement
=
534 GetRadialGradientWithLength(aIndex
, nullptr);
536 return lengthElement
? GetLengthValueFromElement(aIndex
, *lengthElement
)
540 float SVGRadialGradientFrame::GetLengthValueFromElement(
541 uint32_t aIndex
, dom::SVGRadialGradientElement
& aElement
) {
542 const SVGAnimatedLength
& length
= aElement
.mLengthAttributes
[aIndex
];
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 uint16_t gradientUnits
= GetGradientUnits();
549 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
550 return SVGUtils::UserSpace(mSource
, &length
);
553 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
554 "Unknown gradientUnits type");
556 return length
.GetAnimValue(static_cast<SVGViewportElement
*>(nullptr));
559 dom::SVGRadialGradientElement
*
560 SVGRadialGradientFrame::GetRadialGradientWithLength(
561 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
562 dom::SVGRadialGradientElement
* thisElement
=
563 static_cast<dom::SVGRadialGradientElement
*>(GetContent());
564 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
566 if (length
.IsExplicitlySet()) {
570 return SVGGradientFrame::GetRadialGradientWithLength(aIndex
, aDefault
);
573 bool SVGRadialGradientFrame::GradientVectorLengthIsZero() {
574 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
575 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
576 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
577 // If fx or fy are not set, use cx/cy instead
578 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
579 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
580 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
581 return cx
== fx
&& cy
== fy
&& r
== fr
;
584 already_AddRefed
<gfxPattern
> SVGRadialGradientFrame::CreateGradient() {
585 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
586 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
587 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
588 // If fx or fy are not set, use cx/cy instead
589 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
590 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
591 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
593 return do_AddRef(new gfxPattern(fx
, fy
, fr
, cx
, cy
, r
));
596 } // namespace mozilla
598 // -------------------------------------------------------------------------
600 // -------------------------------------------------------------------------
602 nsIFrame
* NS_NewSVGLinearGradientFrame(mozilla::PresShell
* aPresShell
,
603 mozilla::ComputedStyle
* aStyle
) {
604 return new (aPresShell
)
605 mozilla::SVGLinearGradientFrame(aStyle
, aPresShell
->GetPresContext());
608 nsIFrame
* NS_NewSVGRadialGradientFrame(mozilla::PresShell
* aPresShell
,
609 mozilla::ComputedStyle
* aStyle
) {
610 return new (aPresShell
)
611 mozilla::SVGRadialGradientFrame(aStyle
, aPresShell
->GetPresContext());
616 NS_IMPL_FRAMEARENA_HELPERS(SVGLinearGradientFrame
)
617 NS_IMPL_FRAMEARENA_HELPERS(SVGRadialGradientFrame
)
619 } // namespace mozilla