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 #include "ComputedStyle.h"
8 #include "mozilla/dom/SVGCircleElement.h"
9 #include "mozilla/gfx/2D.h"
10 #include "nsGkAtoms.h"
11 #include "mozilla/dom/SVGCircleElementBinding.h"
12 #include "mozilla/dom/SVGLengthBinding.h"
13 #include "SVGGeometryProperty.h"
15 NS_IMPL_NS_NEW_SVG_ELEMENT(Circle
)
17 using namespace mozilla::gfx
;
22 JSObject
* SVGCircleElement::WrapNode(JSContext
* aCx
,
23 JS::Handle
<JSObject
*> aGivenProto
) {
24 return SVGCircleElement_Binding::Wrap(aCx
, this, aGivenProto
);
27 SVGElement::LengthInfo
SVGCircleElement::sLengthInfo
[3] = {
28 {nsGkAtoms::cx
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
30 {nsGkAtoms::cy
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
32 {nsGkAtoms::r
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
33 SVGContentUtils::XY
}};
35 //----------------------------------------------------------------------
38 SVGCircleElement::SVGCircleElement(
39 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
40 : SVGCircleElementBase(std::move(aNodeInfo
)) {}
42 bool SVGCircleElement::IsAttributeMapped(const nsAtom
* aAttribute
) const {
43 return IsInLengthInfo(aAttribute
, sLengthInfo
) ||
44 SVGCircleElementBase::IsAttributeMapped(aAttribute
);
47 namespace SVGT
= SVGGeometryProperty::Tags
;
49 //----------------------------------------------------------------------
52 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGCircleElement
)
54 //----------------------------------------------------------------------
56 already_AddRefed
<DOMSVGAnimatedLength
> SVGCircleElement::Cx() {
57 return mLengthAttributes
[ATTR_CX
].ToDOMAnimatedLength(this);
60 already_AddRefed
<DOMSVGAnimatedLength
> SVGCircleElement::Cy() {
61 return mLengthAttributes
[ATTR_CY
].ToDOMAnimatedLength(this);
64 already_AddRefed
<DOMSVGAnimatedLength
> SVGCircleElement::R() {
65 return mLengthAttributes
[ATTR_R
].ToDOMAnimatedLength(this);
68 //----------------------------------------------------------------------
72 bool SVGCircleElement::HasValidDimensions() const {
75 if (SVGGeometryProperty::ResolveAll
<SVGT::R
>(this, &r
)) {
78 // This function might be called for an element in display:none subtree
79 // (e.g. SMIL animateMotion), we fall back to use SVG attributes.
80 return mLengthAttributes
[ATTR_R
].IsExplicitlySet() &&
81 mLengthAttributes
[ATTR_R
].GetAnimValInSpecifiedUnits() > 0;
84 SVGElement::LengthAttributesInfo
SVGCircleElement::GetLengthInfo() {
85 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
86 ArrayLength(sLengthInfo
));
89 //----------------------------------------------------------------------
90 // SVGGeometryElement methods
92 bool SVGCircleElement::GetGeometryBounds(
93 Rect
* aBounds
, const StrokeOptions
& aStrokeOptions
,
94 const Matrix
& aToBoundsSpace
, const Matrix
* aToNonScalingStrokeSpace
) {
98 SVGGeometryProperty::ResolveAll
<SVGT::Cx
, SVGT::Cy
, SVGT::R
>(this, &x
, &y
,
100 MOZ_ASSERT(ok
, "SVGGeometryProperty::ResolveAll failed");
103 // Rendering of the element is disabled
104 *aBounds
= Rect(aToBoundsSpace
.TransformPoint(Point(x
, y
)), Size());
108 if (aToBoundsSpace
.IsRectilinear()) {
109 // Optimize the case where we can treat the circle as a rectangle and
110 // still get tight bounds.
111 if (aStrokeOptions
.mLineWidth
> 0.f
) {
112 if (aToNonScalingStrokeSpace
) {
113 if (aToNonScalingStrokeSpace
->IsRectilinear()) {
114 MOZ_ASSERT(!aToNonScalingStrokeSpace
->IsSingular());
115 Rect
userBounds(x
- r
, y
- r
, 2 * r
, 2 * r
);
116 SVGContentUtils::RectilinearGetStrokeBounds(
117 userBounds
, aToBoundsSpace
, *aToNonScalingStrokeSpace
,
118 aStrokeOptions
.mLineWidth
, aBounds
);
123 r
+= aStrokeOptions
.mLineWidth
/ 2.f
;
125 Rect
rect(x
- r
, y
- r
, 2 * r
, 2 * r
);
126 *aBounds
= aToBoundsSpace
.TransformBounds(rect
);
133 already_AddRefed
<Path
> SVGCircleElement::BuildPath(PathBuilder
* aBuilder
) {
135 if (!SVGGeometryProperty::ResolveAll
<SVGT::Cx
, SVGT::Cy
, SVGT::R
>(this, &x
,
137 // This function might be called for element in display:none subtree
138 // (e.g. getTotalLength), we fall back to use SVG attributes.
139 GetAnimatedLengthValues(&x
, &y
, &r
, nullptr);
146 aBuilder
->Arc(Point(x
, y
), r
, 0, Float(2 * M_PI
));
148 return aBuilder
->Finish();
151 bool SVGCircleElement::IsLengthChangedViaCSS(const ComputedStyle
& aNewStyle
,
152 const ComputedStyle
& aOldStyle
) {
153 const auto& newSVGReset
= *aNewStyle
.StyleSVGReset();
154 const auto& oldSVGReset
= *aOldStyle
.StyleSVGReset();
156 return newSVGReset
.mCx
!= oldSVGReset
.mCx
||
157 newSVGReset
.mCy
!= oldSVGReset
.mCy
|| newSVGReset
.mR
!= oldSVGReset
.mR
;
160 nsCSSPropertyID
SVGCircleElement::GetCSSPropertyIdForAttrEnum(
164 return eCSSProperty_cx
;
166 return eCSSProperty_cy
;
168 return eCSSProperty_r
;
170 MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
171 return eCSSProperty_UNKNOWN
;
176 } // namespace mozilla