no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / layout / svg / SVGGradientFrame.cpp
blob92558cefcd0d664a6609587baee323dac3ff0d3d
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.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
176 // reference chains:
177 static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
178 AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
179 &sRefChainLengthCounter);
180 if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
181 // Break reference chain
182 return aDefault;
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
196 // reference chains:
197 static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
198 AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
199 &sRefChainLengthCounter);
200 if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
201 // Break reference chain
202 return aDefault;
205 SVGGradientFrame* next = GetReferencedGradient();
206 return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
209 //----------------------------------------------------------------------
210 // SVGPaintServerFrame methods:
212 // helpers
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));
220 float position;
221 static_cast<SVGStopElement*>(stopContent)
222 ->GetAnimatedNumberValues(&position, nullptr);
224 position = clamped(position, 0.0f, 1.0f);
226 if (position < aLastPosition) {
227 position = aLastPosition;
228 } else {
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> {
244 public:
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);
255 private:
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.
281 if (nStops == 0) {
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()) {
297 return nullptr;
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()) {
309 return nullptr;
312 RefPtr<gfxPattern> gradient = CreateGradient();
313 if (!gradient) {
314 return nullptr;
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();
332 } else {
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() {
345 if (mNoHRefURI) {
346 return nullptr;
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,
355 grad);
356 } else {
357 grad->mStringAttributes[dom::SVGGradientElement::XLINK_HREF].GetAnimValue(
358 aHref, grad);
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()) {
380 return;
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
386 // reference chains:
387 static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
388 AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
389 &sRefChainLengthCounter);
390 if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
391 // Break reference chain
392 return;
395 SVGGradientFrame* next = GetReferencedGradient();
396 if (next) {
397 next->GetStops(aStops, aGraphicOpacity);
401 // -------------------------------------------------------------------------
402 // Linear Gradients
403 // -------------------------------------------------------------------------
405 NS_QUERYFRAME_HEAD(SVGLinearGradientFrame)
406 NS_QUERYFRAME_ENTRY(SVGLinearGradientFrame)
407 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame)
409 #ifdef DEBUG
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);
418 #endif /* DEBUG */
420 nsresult SVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID,
421 nsAtom* aAttribute,
422 int32_t aModType) {
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()) {
466 return thisElement;
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 // -------------------------------------------------------------------------
489 // Radial Gradients
490 // -------------------------------------------------------------------------
492 NS_QUERYFRAME_HEAD(SVGRadialGradientFrame)
493 NS_QUERYFRAME_ENTRY(SVGRadialGradientFrame)
494 NS_QUERYFRAME_TAIL_INHERITING(SVGGradientFrame)
496 #ifdef DEBUG
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);
505 #endif /* DEBUG */
507 nsresult SVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID,
508 nsAtom* aAttribute,
509 int32_t aModType) {
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)
538 : aDefaultValue;
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()) {
568 return thisElement;
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 // -------------------------------------------------------------------------
600 // Public functions
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());
615 namespace mozilla {
617 NS_IMPL_FRAMEARENA_HELPERS(SVGLinearGradientFrame)
618 NS_IMPL_FRAMEARENA_HELPERS(SVGRadialGradientFrame)
620 } // namespace mozilla