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
) {
160 return bboxMatrix
.PreMultiply(
161 SVGUtils::GetTransformMatrixInUserSpace(this));
164 gfxMatrix gradientTransform
=
165 animTransformList
->GetAnimValue().GetConsolidationMatrix();
166 return bboxMatrix
.PreMultiply(gradientTransform
);
169 dom::SVGLinearGradientElement
* SVGGradientFrame::GetLinearGradientWithLength(
170 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
171 // If this was a linear gradient with the required length, we would have
172 // already found it in SVGLinearGradientFrame::GetLinearGradientWithLength.
173 // Since we didn't find the length, continue looking down the chain.
175 // Before we recurse, make sure we'll break reference loops and over long
177 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
178 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
179 &sRefChainLengthCounter
);
180 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
181 // Break reference chain
185 SVGGradientFrame
* next
= GetReferencedGradient();
186 return next
? next
->GetLinearGradientWithLength(aIndex
, aDefault
) : aDefault
;
189 dom::SVGRadialGradientElement
* SVGGradientFrame::GetRadialGradientWithLength(
190 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
191 // If this was a radial gradient with the required length, we would have
192 // already found it in SVGRadialGradientFrame::GetRadialGradientWithLength.
193 // Since we didn't find the length, continue looking down the chain.
195 // Before we recurse, make sure we'll break reference loops and over long
197 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
198 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
199 &sRefChainLengthCounter
);
200 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
201 // Break reference chain
205 SVGGradientFrame
* next
= GetReferencedGradient();
206 return next
? next
->GetRadialGradientWithLength(aIndex
, aDefault
) : aDefault
;
209 //----------------------------------------------------------------------
210 // SVGPaintServerFrame methods:
214 static ColorStop
GetStopInformation(const nsIFrame
* aStopFrame
,
215 float aGraphicOpacity
,
216 float& aLastPosition
) {
217 nsIContent
* stopContent
= aStopFrame
->GetContent();
218 MOZ_ASSERT(stopContent
&& stopContent
->IsSVGElement(nsGkAtoms::stop
));
221 static_cast<SVGStopElement
*>(stopContent
)
222 ->GetAnimatedNumberValues(&position
, nullptr);
224 position
= clamped(position
, 0.0f
, 1.0f
);
226 if (position
< aLastPosition
) {
227 position
= aLastPosition
;
229 aLastPosition
= position
;
232 const auto* svgReset
= aStopFrame
->StyleSVGReset();
234 sRGBColor stopColor
=
235 sRGBColor::FromABGR(svgReset
->mStopColor
.CalcColor(aStopFrame
));
236 stopColor
.a
*= svgReset
->mStopOpacity
* aGraphicOpacity
;
238 return ColorStop(position
, false,
239 StyleAbsoluteColor::FromColor(stopColor
.ToABGR()));
242 class MOZ_STACK_CLASS SVGColorStopInterpolator
243 : public ColorStopInterpolator
<SVGColorStopInterpolator
> {
245 SVGColorStopInterpolator(
246 gfxPattern
* aGradient
, const nsTArray
<ColorStop
>& aStops
,
247 const StyleColorInterpolationMethod
& aStyleColorInterpolationMethod
)
248 : ColorStopInterpolator(aStops
, aStyleColorInterpolationMethod
),
249 mGradient(aGradient
) {}
251 void CreateStop(float aPosition
, DeviceColor aColor
) {
252 mGradient
->AddColorStop(aPosition
, aColor
);
256 gfxPattern
* mGradient
;
259 already_AddRefed
<gfxPattern
> SVGGradientFrame::GetPaintServerPattern(
260 nsIFrame
* aSource
, const DrawTarget
* aDrawTarget
,
261 const gfxMatrix
& aContextMatrix
, StyleSVGPaint
nsStyleSVG::*aFillOrStroke
,
262 float aGraphicOpacity
, imgDrawingParams
& aImgParams
,
263 const gfxRect
* aOverrideBounds
) {
264 uint16_t gradientUnits
= GetGradientUnits();
265 MOZ_ASSERT(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
||
266 gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
);
267 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
268 // Set mSource for this consumer.
269 // If this gradient is applied to text, our caller will be the glyph, which
270 // is not an element, so we need to get the parent
271 mSource
= aSource
->IsTextFrame() ? aSource
->GetParent() : aSource
;
274 AutoTArray
<ColorStop
, 8> stops
;
275 GetStops(&stops
, aGraphicOpacity
);
277 uint32_t nStops
= stops
.Length();
279 // SVG specification says that no stops should be treated like
280 // the corresponding fill or stroke had "none" specified.
282 return do_AddRef(new gfxPattern(DeviceColor()));
285 if (nStops
== 1 || GradientVectorLengthIsZero()) {
286 // The gradient paints a single colour, using the stop-color of the last
287 // gradient step if there are more than one.
288 return do_AddRef(new gfxPattern(ToDeviceColor(stops
.LastElement().mColor
)));
291 // Get the transform list (if there is one). We do this after the returns
292 // above since this call can be expensive when "gradientUnits" is set to
293 // "objectBoundingBox" (since that requiring a GetBBox() call).
294 gfxMatrix patternMatrix
= GetGradientTransform(aSource
, aOverrideBounds
);
296 if (patternMatrix
.IsSingular()) {
300 // revert any vector effect transform so that the gradient appears unchanged
301 if (aFillOrStroke
== &nsStyleSVG::mStroke
) {
302 gfxMatrix userToOuterSVG
;
303 if (SVGUtils::GetNonScalingStrokeTransform(aSource
, &userToOuterSVG
)) {
304 patternMatrix
*= userToOuterSVG
;
308 if (!patternMatrix
.Invert()) {
312 RefPtr
<gfxPattern
> gradient
= CreateGradient();
317 uint16_t aSpread
= GetSpreadMethod();
318 if (aSpread
== SVG_SPREADMETHOD_PAD
)
319 gradient
->SetExtend(ExtendMode::CLAMP
);
320 else if (aSpread
== SVG_SPREADMETHOD_REFLECT
)
321 gradient
->SetExtend(ExtendMode::REFLECT
);
322 else if (aSpread
== SVG_SPREADMETHOD_REPEAT
)
323 gradient
->SetExtend(ExtendMode::REPEAT
);
325 gradient
->SetMatrix(patternMatrix
);
327 if (StyleSVG()->mColorInterpolation
== StyleColorInterpolation::Linearrgb
) {
328 static constexpr auto interpolationMethod
= StyleColorInterpolationMethod
{
329 StyleColorSpace::SrgbLinear
, StyleHueInterpolationMethod::Shorter
};
330 SVGColorStopInterpolator
interpolator(gradient
, stops
, interpolationMethod
);
331 interpolator
.CreateStops();
333 // setup standard sRGB stops
334 for (const auto& stop
: stops
) {
335 gradient
->AddColorStop(stop
.mPosition
, ToDeviceColor(stop
.mColor
));
339 return gradient
.forget();
342 // Private (helper) methods
344 SVGGradientFrame
* SVGGradientFrame::GetReferencedGradient() {
349 auto GetHref
= [this](nsAString
& aHref
) {
350 dom::SVGGradientElement
* grad
=
351 static_cast<dom::SVGGradientElement
*>(this->GetContent());
352 if (grad
->mStringAttributes
[dom::SVGGradientElement::HREF
]
353 .IsExplicitlySet()) {
354 grad
->mStringAttributes
[dom::SVGGradientElement::HREF
].GetAnimValue(aHref
,
357 grad
->mStringAttributes
[dom::SVGGradientElement::XLINK_HREF
].GetAnimValue(
360 this->mNoHRefURI
= aHref
.IsEmpty();
363 // We don't call SVGObserverUtils::RemoveTemplateObserver and set
364 // `mNoHRefURI = false` on failure since we want to be invalidated if the ID
365 // specified by our href starts resolving to a different/valid element.
367 return do_QueryFrame(SVGObserverUtils::GetAndObserveTemplate(this, GetHref
));
370 void SVGGradientFrame::GetStops(nsTArray
<ColorStop
>* aStops
,
371 float aGraphicOpacity
) {
372 float lastPosition
= 0.0f
;
373 for (const auto* stopFrame
: mFrames
) {
374 if (stopFrame
->IsSVGStopFrame()) {
375 aStops
->AppendElement(
376 GetStopInformation(stopFrame
, aGraphicOpacity
, lastPosition
));
379 if (!aStops
->IsEmpty()) {
383 // Our gradient element doesn't have stops - try to "inherit" them
385 // Before we recurse, make sure we'll break reference loops and over long
387 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
388 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
389 &sRefChainLengthCounter
);
390 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
391 // Break reference chain
395 SVGGradientFrame
* next
= GetReferencedGradient();
397 next
->GetStops(aStops
, aGraphicOpacity
);
401 // -------------------------------------------------------------------------
403 // -------------------------------------------------------------------------
405 NS_QUERYFRAME_HEAD(SVGLinearGradientFrame
)
406 NS_QUERYFRAME_ENTRY(SVGLinearGradientFrame
)
407 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
410 void SVGLinearGradientFrame::Init(nsIContent
* aContent
,
411 nsContainerFrame
* aParent
,
412 nsIFrame
* aPrevInFlow
) {
413 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::linearGradient
),
414 "Content is not an SVG linearGradient");
416 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
420 nsresult
SVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
423 if (aNameSpaceID
== kNameSpaceID_None
&&
424 (aAttribute
== nsGkAtoms::x1
|| aAttribute
== nsGkAtoms::y1
||
425 aAttribute
== nsGkAtoms::x2
|| aAttribute
== nsGkAtoms::y2
)) {
426 SVGObserverUtils::InvalidateRenderingObservers(this);
429 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
432 //----------------------------------------------------------------------
434 float SVGLinearGradientFrame::GetLengthValue(uint32_t aIndex
) {
435 dom::SVGLinearGradientElement
* lengthElement
= GetLinearGradientWithLength(
436 aIndex
, static_cast<dom::SVGLinearGradientElement
*>(GetContent()));
437 // We passed in mContent as a fallback, so, assuming mContent is non-null, the
438 // return value should also be non-null.
439 MOZ_ASSERT(lengthElement
,
440 "Got unexpected null element from GetLinearGradientWithLength");
441 const SVGAnimatedLength
& length
= lengthElement
->mLengthAttributes
[aIndex
];
443 // Object bounding box units are handled by setting the appropriate
444 // transform in GetGradientTransform, but we need to handle user
445 // space units as part of the individual Get* routines. Fixes 323669.
447 uint16_t gradientUnits
= GetGradientUnits();
448 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
449 return SVGUtils::UserSpace(mSource
, &length
);
452 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
453 "Unknown gradientUnits type");
455 return length
.GetAnimValue(static_cast<SVGViewportElement
*>(nullptr));
458 dom::SVGLinearGradientElement
*
459 SVGLinearGradientFrame::GetLinearGradientWithLength(
460 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
461 dom::SVGLinearGradientElement
* thisElement
=
462 static_cast<dom::SVGLinearGradientElement
*>(GetContent());
463 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
465 if (length
.IsExplicitlySet()) {
469 return SVGGradientFrame::GetLinearGradientWithLength(aIndex
, aDefault
);
472 bool SVGLinearGradientFrame::GradientVectorLengthIsZero() {
473 return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
) ==
474 GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
) &&
475 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
) ==
476 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
479 already_AddRefed
<gfxPattern
> SVGLinearGradientFrame::CreateGradient() {
480 float x1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
);
481 float y1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
);
482 float x2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
);
483 float y2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
485 return do_AddRef(new gfxPattern(x1
, y1
, x2
, y2
));
488 // -------------------------------------------------------------------------
490 // -------------------------------------------------------------------------
492 NS_QUERYFRAME_HEAD(SVGRadialGradientFrame
)
493 NS_QUERYFRAME_ENTRY(SVGRadialGradientFrame
)
494 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
497 void SVGRadialGradientFrame::Init(nsIContent
* aContent
,
498 nsContainerFrame
* aParent
,
499 nsIFrame
* aPrevInFlow
) {
500 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::radialGradient
),
501 "Content is not an SVG radialGradient");
503 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
507 nsresult
SVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
510 if (aNameSpaceID
== kNameSpaceID_None
&&
511 (aAttribute
== nsGkAtoms::r
|| aAttribute
== nsGkAtoms::cx
||
512 aAttribute
== nsGkAtoms::cy
|| aAttribute
== nsGkAtoms::fx
||
513 aAttribute
== nsGkAtoms::fy
)) {
514 SVGObserverUtils::InvalidateRenderingObservers(this);
517 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
520 //----------------------------------------------------------------------
522 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
) {
523 dom::SVGRadialGradientElement
* lengthElement
= GetRadialGradientWithLength(
524 aIndex
, static_cast<dom::SVGRadialGradientElement
*>(GetContent()));
525 // We passed in mContent as a fallback, so, assuming mContent is non-null,
526 // the return value should also be non-null.
527 MOZ_ASSERT(lengthElement
,
528 "Got unexpected null element from GetRadialGradientWithLength");
529 return GetLengthValueFromElement(aIndex
, *lengthElement
);
532 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
,
533 float aDefaultValue
) {
534 dom::SVGRadialGradientElement
* lengthElement
=
535 GetRadialGradientWithLength(aIndex
, nullptr);
537 return lengthElement
? GetLengthValueFromElement(aIndex
, *lengthElement
)
541 float SVGRadialGradientFrame::GetLengthValueFromElement(
542 uint32_t aIndex
, dom::SVGRadialGradientElement
& aElement
) {
543 const SVGAnimatedLength
& length
= aElement
.mLengthAttributes
[aIndex
];
545 // Object bounding box units are handled by setting the appropriate
546 // transform in GetGradientTransform, but we need to handle user
547 // space units as part of the individual Get* routines. Fixes 323669.
549 uint16_t gradientUnits
= GetGradientUnits();
550 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
551 return SVGUtils::UserSpace(mSource
, &length
);
554 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
555 "Unknown gradientUnits type");
557 return length
.GetAnimValue(static_cast<SVGViewportElement
*>(nullptr));
560 dom::SVGRadialGradientElement
*
561 SVGRadialGradientFrame::GetRadialGradientWithLength(
562 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
563 dom::SVGRadialGradientElement
* thisElement
=
564 static_cast<dom::SVGRadialGradientElement
*>(GetContent());
565 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
567 if (length
.IsExplicitlySet()) {
571 return SVGGradientFrame::GetRadialGradientWithLength(aIndex
, aDefault
);
574 bool SVGRadialGradientFrame::GradientVectorLengthIsZero() {
575 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
576 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
577 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
578 // If fx or fy are not set, use cx/cy instead
579 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
580 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
581 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
582 return cx
== fx
&& cy
== fy
&& r
== fr
;
585 already_AddRefed
<gfxPattern
> SVGRadialGradientFrame::CreateGradient() {
586 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
587 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
588 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
589 // If fx or fy are not set, use cx/cy instead
590 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
591 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
592 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
594 return do_AddRef(new gfxPattern(fx
, fy
, fr
, cx
, cy
, r
));
597 } // namespace mozilla
599 // -------------------------------------------------------------------------
601 // -------------------------------------------------------------------------
603 nsIFrame
* NS_NewSVGLinearGradientFrame(mozilla::PresShell
* aPresShell
,
604 mozilla::ComputedStyle
* aStyle
) {
605 return new (aPresShell
)
606 mozilla::SVGLinearGradientFrame(aStyle
, aPresShell
->GetPresContext());
609 nsIFrame
* NS_NewSVGRadialGradientFrame(mozilla::PresShell
* aPresShell
,
610 mozilla::ComputedStyle
* aStyle
) {
611 return new (aPresShell
)
612 mozilla::SVGRadialGradientFrame(aStyle
, aPresShell
->GetPresContext());
617 NS_IMPL_FRAMEARENA_HELPERS(SVGLinearGradientFrame
)
618 NS_IMPL_FRAMEARENA_HELPERS(SVGRadialGradientFrame
)
620 } // namespace mozilla