Bug 1874644 [wpt PR 43993] - Rewrite prerender-while-prerender.html with a different...
[gecko.git] / layout / svg / SVGGradientFrame.cpp
blobf316c0180d04d5e2faee624399878cdf6df6bae4
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/. */
7 // Main header first:
8 #include "SVGGradientFrame.h"
9 #include <algorithm>
11 // Keep others in (case-insensitive) order:
12 #include "AutoReferenceChainGuard.h"
13 #include "gfxPattern.h"
14 #include "gfxUtils.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;
30 namespace mozilla {
32 //----------------------------------------------------------------------
33 // Implementation
35 SVGGradientFrame::SVGGradientFrame(ComputedStyle* aStyle,
36 nsPresContext* aPresContext, ClassID aID)
37 : SVGPaintServerFrame(aStyle, aPresContext, aID),
38 mSource(nullptr),
39 mLoopFlag(false),
40 mNoHRefURI(false) {}
42 NS_QUERYFRAME_HEAD(SVGGradientFrame)
43 NS_QUERYFRAME_ENTRY(SVGGradientFrame)
44 NS_QUERYFRAME_TAIL_INHERITING(SVGPaintServerFrame)
46 //----------------------------------------------------------------------
47 // nsIFrame methods:
49 nsresult SVGGradientFrame::AttributeChanged(int32_t aNameSpaceID,
50 nsAtom* aAttribute,
51 int32_t aModType) {
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);
62 mNoHRefURI = false;
63 // And update whoever references us
64 SVGObserverUtils::InvalidateRenderingObservers(this);
67 return SVGPaintServerFrame::AttributeChanged(aNameSpaceID, aAttribute,
68 aModType);
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
83 // reference chains:
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]
91 .GetAnimValue();
94 SVGGradientFrame* next = GetReferencedGradient();
96 return next ? next->GetEnumValue(aIndex, aDefault)
97 : static_cast<dom::SVGGradientElement*>(aDefault)
98 ->mEnumAttributes[aIndex]
99 .GetAnimValue();
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
121 // reference chains:
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
149 ? *aOverrideBounds
150 : SVGUtils::GetBBox(
151 aSource, SVGUtils::eUseFrameBoundsForOuterSVG |
152 SVGUtils::eBBoxIncludeFillGeometry);
153 bboxMatrix =
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;
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
175 // reference chains:
176 static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
177 AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
178 &sRefChainLengthCounter);
179 if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
180 // Break reference chain
181 return aDefault;
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
195 // reference chains:
196 static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
197 AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
198 &sRefChainLengthCounter);
199 if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
200 // Break reference chain
201 return aDefault;
204 SVGGradientFrame* next = GetReferencedGradient();
205 return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
208 //----------------------------------------------------------------------
209 // SVGPaintServerFrame methods:
211 // helpers
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));
219 float position;
220 static_cast<SVGStopElement*>(stopContent)
221 ->GetAnimatedNumberValues(&position, nullptr);
223 position = clamped(position, 0.0f, 1.0f);
225 if (position < aLastPosition) {
226 position = aLastPosition;
227 } else {
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> {
243 public:
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);
254 private:
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.
280 if (nStops == 0) {
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()) {
296 return nullptr;
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()) {
308 return nullptr;
311 RefPtr<gfxPattern> gradient = CreateGradient();
312 if (!gradient) {
313 return nullptr;
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();
331 } else {
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() {
344 if (mNoHRefURI) {
345 return nullptr;
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,
354 grad);
355 } else {
356 grad->mStringAttributes[dom::SVGGradientElement::XLINK_HREF].GetAnimValue(
357 aHref, grad);
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()) {
379 return;
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
385 // reference chains:
386 static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
387 AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
388 &sRefChainLengthCounter);
389 if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
390 // Break reference chain
391 return;
394 SVGGradientFrame* next = GetReferencedGradient();
395 if (next) {
396 next->GetStops(aStops, aGraphicOpacity);
400 // -------------------------------------------------------------------------
401 // Linear Gradients
402 // -------------------------------------------------------------------------
404 NS_QUERYFRAME_HEAD(SVGLinearGradientFrame)
405 NS_QUERYFRAME_ENTRY(SVGLinearGradientFrame)
406 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame)
408 #ifdef DEBUG
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);
417 #endif /* DEBUG */
419 nsresult SVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID,
420 nsAtom* aAttribute,
421 int32_t aModType) {
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()) {
465 return thisElement;
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 // -------------------------------------------------------------------------
488 // Radial Gradients
489 // -------------------------------------------------------------------------
491 NS_QUERYFRAME_HEAD(SVGRadialGradientFrame)
492 NS_QUERYFRAME_ENTRY(SVGRadialGradientFrame)
493 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame)
495 #ifdef DEBUG
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);
504 #endif /* DEBUG */
506 nsresult SVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID,
507 nsAtom* aAttribute,
508 int32_t aModType) {
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)
537 : aDefaultValue;
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()) {
567 return thisElement;
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 // -------------------------------------------------------------------------
599 // Public functions
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());
614 namespace mozilla {
616 NS_IMPL_FRAMEARENA_HELPERS(SVGLinearGradientFrame)
617 NS_IMPL_FRAMEARENA_HELPERS(SVGRadialGradientFrame)
619 } // namespace mozilla