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 SVGGradientFrame
* SVGGradientFrame::GetGradientTransformFrame(
112 SVGGradientFrame
* aDefault
) {
113 if (!StyleDisplay()->mTransform
.IsNone()) {
116 // Before we recurse, make sure we'll break reference loops and over long
118 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
119 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
120 &sRefChainLengthCounter
);
121 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
122 // Break reference chain
126 if (SVGGradientFrame
* next
= GetReferencedGradient()) {
127 return next
->GetGradientTransformFrame(aDefault
);
132 gfxMatrix
SVGGradientFrame::GetGradientTransform(
133 nsIFrame
* aSource
, const gfxRect
* aOverrideBounds
) {
134 gfxMatrix bboxMatrix
;
135 uint16_t gradientUnits
= GetGradientUnits();
136 if (gradientUnits
!= SVG_UNIT_TYPE_USERSPACEONUSE
) {
137 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
138 "Unknown gradientUnits type");
139 // objectBoundingBox is the default anyway
141 gfxRect bbox
= aOverrideBounds
144 aSource
, SVGUtils::eUseFrameBoundsForOuterSVG
|
145 SVGUtils::eBBoxIncludeFillGeometry
);
147 gfxMatrix(bbox
.Width(), 0, 0, bbox
.Height(), bbox
.X(), bbox
.Y());
150 return bboxMatrix
.PreMultiply(
151 SVGUtils::GetTransformMatrixInUserSpace(GetGradientTransformFrame(this)));
154 dom::SVGLinearGradientElement
* SVGGradientFrame::GetLinearGradientWithLength(
155 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
156 // If this was a linear gradient with the required length, we would have
157 // already found it in SVGLinearGradientFrame::GetLinearGradientWithLength.
158 // Since we didn't find the length, continue looking down the chain.
160 // Before we recurse, make sure we'll break reference loops and over long
162 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
163 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
164 &sRefChainLengthCounter
);
165 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
166 // Break reference chain
170 SVGGradientFrame
* next
= GetReferencedGradient();
171 return next
? next
->GetLinearGradientWithLength(aIndex
, aDefault
) : aDefault
;
174 dom::SVGRadialGradientElement
* SVGGradientFrame::GetRadialGradientWithLength(
175 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
176 // If this was a radial gradient with the required length, we would have
177 // already found it in SVGRadialGradientFrame::GetRadialGradientWithLength.
178 // Since we didn't find the length, continue looking down the chain.
180 // Before we recurse, make sure we'll break reference loops and over long
182 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
183 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
184 &sRefChainLengthCounter
);
185 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
186 // Break reference chain
190 SVGGradientFrame
* next
= GetReferencedGradient();
191 return next
? next
->GetRadialGradientWithLength(aIndex
, aDefault
) : aDefault
;
194 //----------------------------------------------------------------------
195 // SVGPaintServerFrame methods:
199 static ColorStop
GetStopInformation(const nsIFrame
* aStopFrame
,
200 float aGraphicOpacity
,
201 float& aLastPosition
) {
202 nsIContent
* stopContent
= aStopFrame
->GetContent();
203 MOZ_ASSERT(stopContent
&& stopContent
->IsSVGElement(nsGkAtoms::stop
));
206 static_cast<SVGStopElement
*>(stopContent
)
207 ->GetAnimatedNumberValues(&position
, nullptr);
209 position
= std::clamp(position
, 0.0f
, 1.0f
);
211 if (position
< aLastPosition
) {
212 position
= aLastPosition
;
214 aLastPosition
= position
;
217 const auto* svgReset
= aStopFrame
->StyleSVGReset();
219 sRGBColor stopColor
=
220 sRGBColor::FromABGR(svgReset
->mStopColor
.CalcColor(aStopFrame
));
221 stopColor
.a
*= svgReset
->mStopOpacity
* aGraphicOpacity
;
223 return ColorStop(position
, false,
224 StyleAbsoluteColor::FromColor(stopColor
.ToABGR()));
227 class MOZ_STACK_CLASS SVGColorStopInterpolator
228 : public ColorStopInterpolator
<SVGColorStopInterpolator
> {
230 SVGColorStopInterpolator(
231 gfxPattern
* aGradient
, const nsTArray
<ColorStop
>& aStops
,
232 const StyleColorInterpolationMethod
& aStyleColorInterpolationMethod
,
234 : ColorStopInterpolator(aStops
, aStyleColorInterpolationMethod
, aExtend
),
235 mGradient(aGradient
) {}
237 void CreateStop(float aPosition
, DeviceColor aColor
) {
238 mGradient
->AddColorStop(aPosition
, aColor
);
242 gfxPattern
* mGradient
;
245 already_AddRefed
<gfxPattern
> SVGGradientFrame::GetPaintServerPattern(
246 nsIFrame
* aSource
, const DrawTarget
* aDrawTarget
,
247 const gfxMatrix
& aContextMatrix
, StyleSVGPaint
nsStyleSVG::* aFillOrStroke
,
248 float aGraphicOpacity
, imgDrawingParams
& aImgParams
,
249 const gfxRect
* aOverrideBounds
) {
250 uint16_t gradientUnits
= GetGradientUnits();
251 MOZ_ASSERT(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
||
252 gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
);
253 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
254 // Set mSource for this consumer.
255 // If this gradient is applied to text, our caller will be the glyph, which
256 // is not an element, so we need to get the parent
257 mSource
= aSource
->IsTextFrame() ? aSource
->GetParent() : aSource
;
260 AutoTArray
<ColorStop
, 8> stops
;
261 GetStops(&stops
, aGraphicOpacity
);
263 uint32_t nStops
= stops
.Length();
265 // SVG specification says that no stops should be treated like
266 // the corresponding fill or stroke had "none" specified.
268 return do_AddRef(new gfxPattern(DeviceColor()));
271 if (nStops
== 1 || GradientVectorLengthIsZero()) {
272 // The gradient paints a single colour, using the stop-color of the last
273 // gradient step if there are more than one.
274 return do_AddRef(new gfxPattern(ToDeviceColor(stops
.LastElement().mColor
)));
277 // Get the transform list (if there is one). We do this after the returns
278 // above since this call can be expensive when "gradientUnits" is set to
279 // "objectBoundingBox" (since that requiring a GetBBox() call).
280 gfxMatrix patternMatrix
= GetGradientTransform(aSource
, aOverrideBounds
);
281 if (patternMatrix
.IsSingular()) {
285 // revert any vector effect transform so that the gradient appears unchanged
286 if (aFillOrStroke
== &nsStyleSVG::mStroke
) {
287 gfxMatrix userToOuterSVG
;
288 if (SVGUtils::GetNonScalingStrokeTransform(aSource
, &userToOuterSVG
)) {
289 patternMatrix
*= userToOuterSVG
;
293 if (!patternMatrix
.Invert()) {
297 RefPtr
<gfxPattern
> gradient
= CreateGradient();
302 uint16_t aSpread
= GetSpreadMethod();
303 if (aSpread
== SVG_SPREADMETHOD_PAD
) {
304 gradient
->SetExtend(ExtendMode::CLAMP
);
305 } else if (aSpread
== SVG_SPREADMETHOD_REFLECT
) {
306 gradient
->SetExtend(ExtendMode::REFLECT
);
307 } else if (aSpread
== SVG_SPREADMETHOD_REPEAT
) {
308 gradient
->SetExtend(ExtendMode::REPEAT
);
311 gradient
->SetMatrix(patternMatrix
);
313 if (StyleSVG()->mColorInterpolation
== StyleColorInterpolation::Linearrgb
) {
314 static constexpr auto interpolationMethod
= StyleColorInterpolationMethod
{
315 StyleColorSpace::SrgbLinear
, StyleHueInterpolationMethod::Shorter
};
316 SVGColorStopInterpolator
interpolator(gradient
, stops
, interpolationMethod
,
318 interpolator
.CreateStops();
320 // setup standard sRGB stops
321 for (const auto& stop
: stops
) {
322 gradient
->AddColorStop(stop
.mPosition
, ToDeviceColor(stop
.mColor
));
326 return gradient
.forget();
329 // Private (helper) methods
331 SVGGradientFrame
* SVGGradientFrame::GetReferencedGradient() {
336 auto GetHref
= [this](nsAString
& aHref
) {
337 dom::SVGGradientElement
* grad
=
338 static_cast<dom::SVGGradientElement
*>(this->GetContent());
339 if (grad
->mStringAttributes
[dom::SVGGradientElement::HREF
]
340 .IsExplicitlySet()) {
341 grad
->mStringAttributes
[dom::SVGGradientElement::HREF
].GetAnimValue(aHref
,
344 grad
->mStringAttributes
[dom::SVGGradientElement::XLINK_HREF
].GetAnimValue(
347 this->mNoHRefURI
= aHref
.IsEmpty();
350 // We don't call SVGObserverUtils::RemoveTemplateObserver and set
351 // `mNoHRefURI = false` on failure since we want to be invalidated if the ID
352 // specified by our href starts resolving to a different/valid element.
354 return do_QueryFrame(SVGObserverUtils::GetAndObserveTemplate(this, GetHref
));
357 void SVGGradientFrame::GetStops(nsTArray
<ColorStop
>* aStops
,
358 float aGraphicOpacity
) {
359 float lastPosition
= 0.0f
;
360 for (const auto* stopFrame
: mFrames
) {
361 if (stopFrame
->IsSVGStopFrame()) {
362 aStops
->AppendElement(
363 GetStopInformation(stopFrame
, aGraphicOpacity
, lastPosition
));
366 if (!aStops
->IsEmpty()) {
370 // Our gradient element doesn't have stops - try to "inherit" them
372 // Before we recurse, make sure we'll break reference loops and over long
374 static int16_t sRefChainLengthCounter
= AutoReferenceChainGuard::noChain
;
375 AutoReferenceChainGuard
refChainGuard(this, &mLoopFlag
,
376 &sRefChainLengthCounter
);
377 if (MOZ_UNLIKELY(!refChainGuard
.Reference())) {
378 // Break reference chain
382 SVGGradientFrame
* next
= GetReferencedGradient();
384 next
->GetStops(aStops
, aGraphicOpacity
);
388 // -------------------------------------------------------------------------
390 // -------------------------------------------------------------------------
392 NS_QUERYFRAME_HEAD(SVGLinearGradientFrame
)
393 NS_QUERYFRAME_ENTRY(SVGLinearGradientFrame
)
394 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
397 void SVGLinearGradientFrame::Init(nsIContent
* aContent
,
398 nsContainerFrame
* aParent
,
399 nsIFrame
* aPrevInFlow
) {
400 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::linearGradient
),
401 "Content is not an SVG linearGradient");
403 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
407 nsresult
SVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
410 if (aNameSpaceID
== kNameSpaceID_None
&&
411 (aAttribute
== nsGkAtoms::x1
|| aAttribute
== nsGkAtoms::y1
||
412 aAttribute
== nsGkAtoms::x2
|| aAttribute
== nsGkAtoms::y2
)) {
413 SVGObserverUtils::InvalidateRenderingObservers(this);
416 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
419 //----------------------------------------------------------------------
421 float SVGLinearGradientFrame::GetLengthValue(uint32_t aIndex
) {
422 dom::SVGLinearGradientElement
* lengthElement
= GetLinearGradientWithLength(
423 aIndex
, static_cast<dom::SVGLinearGradientElement
*>(GetContent()));
424 // We passed in mContent as a fallback, so, assuming mContent is non-null, the
425 // return value should also be non-null.
426 MOZ_ASSERT(lengthElement
,
427 "Got unexpected null element from GetLinearGradientWithLength");
428 const SVGAnimatedLength
& length
= lengthElement
->mLengthAttributes
[aIndex
];
430 // Object bounding box units are handled by setting the appropriate
431 // transform in GetGradientTransform, but we need to handle user
432 // space units as part of the individual Get* routines. Fixes 323669.
434 uint16_t gradientUnits
= GetGradientUnits();
435 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
436 return SVGUtils::UserSpace(mSource
, &length
);
439 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
440 "Unknown gradientUnits type");
442 return length
.GetAnimValueWithZoom(static_cast<SVGViewportElement
*>(nullptr));
445 dom::SVGLinearGradientElement
*
446 SVGLinearGradientFrame::GetLinearGradientWithLength(
447 uint32_t aIndex
, dom::SVGLinearGradientElement
* aDefault
) {
448 dom::SVGLinearGradientElement
* thisElement
=
449 static_cast<dom::SVGLinearGradientElement
*>(GetContent());
450 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
452 if (length
.IsExplicitlySet()) {
456 return SVGGradientFrame::GetLinearGradientWithLength(aIndex
, aDefault
);
459 bool SVGLinearGradientFrame::GradientVectorLengthIsZero() {
460 return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
) ==
461 GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
) &&
462 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
) ==
463 GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
466 already_AddRefed
<gfxPattern
> SVGLinearGradientFrame::CreateGradient() {
467 float x1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1
);
468 float y1
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1
);
469 float x2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2
);
470 float y2
= GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2
);
472 return do_AddRef(new gfxPattern(x1
, y1
, x2
, y2
));
475 // -------------------------------------------------------------------------
477 // -------------------------------------------------------------------------
479 NS_QUERYFRAME_HEAD(SVGRadialGradientFrame
)
480 NS_QUERYFRAME_ENTRY(SVGRadialGradientFrame
)
481 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame
)
484 void SVGRadialGradientFrame::Init(nsIContent
* aContent
,
485 nsContainerFrame
* aParent
,
486 nsIFrame
* aPrevInFlow
) {
487 NS_ASSERTION(aContent
->IsSVGElement(nsGkAtoms::radialGradient
),
488 "Content is not an SVG radialGradient");
490 SVGGradientFrame::Init(aContent
, aParent
, aPrevInFlow
);
494 nsresult
SVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID
,
497 if (aNameSpaceID
== kNameSpaceID_None
&&
498 (aAttribute
== nsGkAtoms::r
|| aAttribute
== nsGkAtoms::cx
||
499 aAttribute
== nsGkAtoms::cy
|| aAttribute
== nsGkAtoms::fx
||
500 aAttribute
== nsGkAtoms::fy
)) {
501 SVGObserverUtils::InvalidateRenderingObservers(this);
504 return SVGGradientFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
507 //----------------------------------------------------------------------
509 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
) {
510 dom::SVGRadialGradientElement
* lengthElement
= GetRadialGradientWithLength(
511 aIndex
, static_cast<dom::SVGRadialGradientElement
*>(GetContent()));
512 // We passed in mContent as a fallback, so, assuming mContent is non-null,
513 // the return value should also be non-null.
514 MOZ_ASSERT(lengthElement
,
515 "Got unexpected null element from GetRadialGradientWithLength");
516 return GetLengthValueFromElement(aIndex
, *lengthElement
);
519 float SVGRadialGradientFrame::GetLengthValue(uint32_t aIndex
,
520 float aDefaultValue
) {
521 dom::SVGRadialGradientElement
* lengthElement
=
522 GetRadialGradientWithLength(aIndex
, nullptr);
524 return lengthElement
? GetLengthValueFromElement(aIndex
, *lengthElement
)
528 float SVGRadialGradientFrame::GetLengthValueFromElement(
529 uint32_t aIndex
, dom::SVGRadialGradientElement
& aElement
) {
530 const SVGAnimatedLength
& length
= aElement
.mLengthAttributes
[aIndex
];
532 // Object bounding box units are handled by setting the appropriate
533 // transform in GetGradientTransform, but we need to handle user
534 // space units as part of the individual Get* routines. Fixes 323669.
536 uint16_t gradientUnits
= GetGradientUnits();
537 if (gradientUnits
== SVG_UNIT_TYPE_USERSPACEONUSE
) {
538 return SVGUtils::UserSpace(mSource
, &length
);
541 NS_ASSERTION(gradientUnits
== SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
,
542 "Unknown gradientUnits type");
544 return length
.GetAnimValueWithZoom(static_cast<SVGViewportElement
*>(nullptr));
547 dom::SVGRadialGradientElement
*
548 SVGRadialGradientFrame::GetRadialGradientWithLength(
549 uint32_t aIndex
, dom::SVGRadialGradientElement
* aDefault
) {
550 dom::SVGRadialGradientElement
* thisElement
=
551 static_cast<dom::SVGRadialGradientElement
*>(GetContent());
552 const SVGAnimatedLength
& length
= thisElement
->mLengthAttributes
[aIndex
];
554 if (length
.IsExplicitlySet()) {
558 return SVGGradientFrame::GetRadialGradientWithLength(aIndex
, aDefault
);
561 bool SVGRadialGradientFrame::GradientVectorLengthIsZero() {
562 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
563 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
564 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
565 // If fx or fy are not set, use cx/cy instead
566 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
567 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
568 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
569 return cx
== fx
&& cy
== fy
&& r
== fr
;
572 already_AddRefed
<gfxPattern
> SVGRadialGradientFrame::CreateGradient() {
573 float cx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX
);
574 float cy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY
);
575 float r
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_R
);
576 // If fx or fy are not set, use cx/cy instead
577 float fx
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX
, cx
);
578 float fy
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY
, cy
);
579 float fr
= GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR
);
581 return do_AddRef(new gfxPattern(fx
, fy
, fr
, cx
, cy
, r
));
584 } // namespace mozilla
586 // -------------------------------------------------------------------------
588 // -------------------------------------------------------------------------
590 nsIFrame
* NS_NewSVGLinearGradientFrame(mozilla::PresShell
* aPresShell
,
591 mozilla::ComputedStyle
* aStyle
) {
592 return new (aPresShell
)
593 mozilla::SVGLinearGradientFrame(aStyle
, aPresShell
->GetPresContext());
596 nsIFrame
* NS_NewSVGRadialGradientFrame(mozilla::PresShell
* aPresShell
,
597 mozilla::ComputedStyle
* aStyle
) {
598 return new (aPresShell
)
599 mozilla::SVGRadialGradientFrame(aStyle
, aPresShell
->GetPresContext());
604 NS_IMPL_FRAMEARENA_HELPERS(SVGLinearGradientFrame
)
605 NS_IMPL_FRAMEARENA_HELPERS(SVGRadialGradientFrame
)
607 } // namespace mozilla