1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/dom/SVGRectElement.h"
8 #include "mozilla/dom/SVGRectElementBinding.h"
9 #include "mozilla/gfx/2D.h"
10 #include "mozilla/gfx/Matrix.h"
11 #include "mozilla/gfx/Rect.h"
12 #include "mozilla/gfx/PathHelpers.h"
15 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Rect
)
17 using namespace mozilla::gfx
;
22 class SVGAnimatedLength
;
25 SVGRectElement::WrapNode(JSContext
*aCx
)
27 return SVGRectElementBinding::Wrap(aCx
, this);
30 nsSVGElement::LengthInfo
SVGRectElement::sLengthInfo
[6] =
32 { &nsGkAtoms::x
, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER
, SVGContentUtils::X
},
33 { &nsGkAtoms::y
, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER
, SVGContentUtils::Y
},
34 { &nsGkAtoms::width
, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER
, SVGContentUtils::X
},
35 { &nsGkAtoms::height
, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER
, SVGContentUtils::Y
},
36 { &nsGkAtoms::rx
, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER
, SVGContentUtils::X
},
37 { &nsGkAtoms::ry
, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER
, SVGContentUtils::Y
}
40 //----------------------------------------------------------------------
43 SVGRectElement::SVGRectElement(already_AddRefed
<mozilla::dom::NodeInfo
>& aNodeInfo
)
44 : SVGRectElementBase(aNodeInfo
)
48 //----------------------------------------------------------------------
51 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGRectElement
)
53 //----------------------------------------------------------------------
55 already_AddRefed
<SVGAnimatedLength
>
58 return mLengthAttributes
[ATTR_X
].ToDOMAnimatedLength(this);
61 already_AddRefed
<SVGAnimatedLength
>
64 return mLengthAttributes
[ATTR_Y
].ToDOMAnimatedLength(this);
67 already_AddRefed
<SVGAnimatedLength
>
68 SVGRectElement::Width()
70 return mLengthAttributes
[ATTR_WIDTH
].ToDOMAnimatedLength(this);
73 already_AddRefed
<SVGAnimatedLength
>
74 SVGRectElement::Height()
76 return mLengthAttributes
[ATTR_HEIGHT
].ToDOMAnimatedLength(this);
79 already_AddRefed
<SVGAnimatedLength
>
82 return mLengthAttributes
[ATTR_RX
].ToDOMAnimatedLength(this);
85 already_AddRefed
<SVGAnimatedLength
>
88 return mLengthAttributes
[ATTR_RY
].ToDOMAnimatedLength(this);
91 //----------------------------------------------------------------------
92 // nsSVGElement methods
95 SVGRectElement::HasValidDimensions() const
97 return mLengthAttributes
[ATTR_WIDTH
].IsExplicitlySet() &&
98 mLengthAttributes
[ATTR_WIDTH
].GetAnimValInSpecifiedUnits() > 0 &&
99 mLengthAttributes
[ATTR_HEIGHT
].IsExplicitlySet() &&
100 mLengthAttributes
[ATTR_HEIGHT
].GetAnimValInSpecifiedUnits() > 0;
103 nsSVGElement::LengthAttributesInfo
104 SVGRectElement::GetLengthInfo()
106 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
107 ArrayLength(sLengthInfo
));
110 //----------------------------------------------------------------------
111 // nsSVGPathGeometryElement methods
114 SVGRectElement::GetGeometryBounds(Rect
* aBounds
, Float aStrokeWidth
,
115 const Matrix
& aTransform
)
119 GetAnimatedLengthValues(&rect
.x
, &rect
.y
, &rect
.width
,
120 &rect
.height
, &rx
, &ry
, nullptr);
122 if (rect
.IsEmpty()) {
123 // Rendering of the element disabled
124 rect
.SetEmpty(); // Make sure width/height are zero and not negative
125 *aBounds
= rect
; // We still want the x/y position from 'rect'
129 if (!aTransform
.IsRectilinear()) {
130 // We can't ignore the radii in this case if we want tight bounds
131 rx
= std::max(rx
, 0.0f
);
132 ry
= std::max(ry
, 0.0f
);
134 if (rx
!= 0 || ry
!= 0) {
139 if (aStrokeWidth
> 0.f
) {
140 rect
.Inflate(aStrokeWidth
/ 2.f
);
143 *aBounds
= aTransform
.TransformBounds(rect
);
148 SVGRectElement::GetAsSimplePath(SimplePath
* aSimplePath
)
150 float x
, y
, width
, height
, rx
, ry
;
151 GetAnimatedLengthValues(&x
, &y
, &width
, &height
, &rx
, &ry
, nullptr);
153 if (width
<= 0 || height
<= 0) {
154 aSimplePath
->Reset();
158 rx
= std::max(rx
, 0.0f
);
159 ry
= std::max(ry
, 0.0f
);
161 if (rx
!= 0 || ry
!= 0) {
162 aSimplePath
->Reset();
166 aSimplePath
->SetRect(x
, y
, width
, height
);
170 SVGRectElement::BuildPath(PathBuilder
* aBuilder
)
172 float x
, y
, width
, height
, rx
, ry
;
173 GetAnimatedLengthValues(&x
, &y
, &width
, &height
, &rx
, &ry
, nullptr);
175 if (width
<= 0 || height
<= 0) {
179 rx
= std::max(rx
, 0.0f
);
180 ry
= std::max(ry
, 0.0f
);
182 if (rx
== 0 && ry
== 0) {
183 // Optimization for the no rounded corners case.
184 Rect
r(x
, y
, width
, height
);
185 aBuilder
->MoveTo(r
.TopLeft());
186 aBuilder
->LineTo(r
.TopRight());
187 aBuilder
->LineTo(r
.BottomRight());
188 aBuilder
->LineTo(r
.BottomLeft());
191 // If either the 'rx' or the 'ry' attribute isn't set, then we have to
192 // set it to the value of the other:
193 bool hasRx
= mLengthAttributes
[ATTR_RX
].IsExplicitlySet();
194 bool hasRy
= mLengthAttributes
[ATTR_RY
].IsExplicitlySet();
195 MOZ_ASSERT(hasRx
|| hasRy
);
197 if (hasRx
&& !hasRy
) {
199 } else if (hasRy
&& !hasRx
) {
203 // Clamp rx and ry to half the rect's width and height respectively:
204 rx
= std::min(rx
, width
/ 2);
205 ry
= std::min(ry
, height
/ 2);
207 RectCornerRadii
radii(rx
, ry
);
208 AppendRoundedRectToPath(aBuilder
, Rect(x
, y
, width
, height
), radii
);
211 return aBuilder
->Finish();
215 } // namespace mozilla