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
;
19 namespace mozilla::dom
{
21 JSObject
* SVGCircleElement::WrapNode(JSContext
* aCx
,
22 JS::Handle
<JSObject
*> aGivenProto
) {
23 return SVGCircleElement_Binding::Wrap(aCx
, this, aGivenProto
);
26 SVGElement::LengthInfo
SVGCircleElement::sLengthInfo
[3] = {
27 {nsGkAtoms::cx
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
29 {nsGkAtoms::cy
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
31 {nsGkAtoms::r
, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER
,
32 SVGContentUtils::XY
}};
34 //----------------------------------------------------------------------
37 SVGCircleElement::SVGCircleElement(
38 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
39 : SVGCircleElementBase(std::move(aNodeInfo
)) {}
41 bool SVGCircleElement::IsAttributeMapped(const nsAtom
* aAttribute
) const {
42 return IsInLengthInfo(aAttribute
, sLengthInfo
) ||
43 SVGCircleElementBase::IsAttributeMapped(aAttribute
);
46 namespace SVGT
= SVGGeometryProperty::Tags
;
48 //----------------------------------------------------------------------
51 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGCircleElement
)
53 //----------------------------------------------------------------------
55 already_AddRefed
<DOMSVGAnimatedLength
> SVGCircleElement::Cx() {
56 return mLengthAttributes
[ATTR_CX
].ToDOMAnimatedLength(this);
59 already_AddRefed
<DOMSVGAnimatedLength
> SVGCircleElement::Cy() {
60 return mLengthAttributes
[ATTR_CY
].ToDOMAnimatedLength(this);
63 already_AddRefed
<DOMSVGAnimatedLength
> SVGCircleElement::R() {
64 return mLengthAttributes
[ATTR_R
].ToDOMAnimatedLength(this);
67 //----------------------------------------------------------------------
71 bool SVGCircleElement::HasValidDimensions() const {
74 if (SVGGeometryProperty::ResolveAll
<SVGT::R
>(this, &r
)) {
77 // This function might be called for an element in display:none subtree
78 // (e.g. SMIL animateMotion), we fall back to use SVG attributes.
79 return mLengthAttributes
[ATTR_R
].IsExplicitlySet() &&
80 mLengthAttributes
[ATTR_R
].GetAnimValInSpecifiedUnits() > 0;
83 SVGElement::LengthAttributesInfo
SVGCircleElement::GetLengthInfo() {
84 return LengthAttributesInfo(mLengthAttributes
, sLengthInfo
,
85 std::size(sLengthInfo
));
88 //----------------------------------------------------------------------
89 // SVGGeometryElement methods
91 bool SVGCircleElement::GetGeometryBounds(
92 Rect
* aBounds
, const StrokeOptions
& aStrokeOptions
,
93 const Matrix
& aToBoundsSpace
, const Matrix
* aToNonScalingStrokeSpace
) {
97 SVGGeometryProperty::ResolveAll
<SVGT::Cx
, SVGT::Cy
, SVGT::R
>(this, &x
, &y
,
99 MOZ_ASSERT(ok
, "SVGGeometryProperty::ResolveAll failed");
102 // Rendering of the element is disabled
103 *aBounds
= Rect(aToBoundsSpace
.TransformPoint(Point(x
, y
)), Size());
107 if (aToBoundsSpace
.IsRectilinear()) {
108 // Optimize the case where we can treat the circle as a rectangle and
109 // still get tight bounds.
110 if (aStrokeOptions
.mLineWidth
> 0.f
) {
111 if (aToNonScalingStrokeSpace
) {
112 if (aToNonScalingStrokeSpace
->IsRectilinear()) {
113 MOZ_ASSERT(!aToNonScalingStrokeSpace
->IsSingular());
114 Rect
userBounds(x
- r
, y
- r
, 2 * r
, 2 * r
);
115 SVGContentUtils::RectilinearGetStrokeBounds(
116 userBounds
, aToBoundsSpace
, *aToNonScalingStrokeSpace
,
117 aStrokeOptions
.mLineWidth
, aBounds
);
122 r
+= aStrokeOptions
.mLineWidth
/ 2.f
;
124 Rect
rect(x
- r
, y
- r
, 2 * r
, 2 * r
);
125 *aBounds
= aToBoundsSpace
.TransformBounds(rect
);
132 already_AddRefed
<Path
> SVGCircleElement::BuildPath(PathBuilder
* aBuilder
) {
134 if (!SVGGeometryProperty::ResolveAll
<SVGT::Cx
, SVGT::Cy
, SVGT::R
>(this, &x
,
136 // This function might be called for element in display:none subtree
137 // (e.g. getTotalLength), we fall back to use SVG attributes.
138 GetAnimatedLengthValues(&x
, &y
, &r
, nullptr);
145 aBuilder
->Arc(Point(x
, y
), r
, 0, Float(2 * M_PI
));
147 return aBuilder
->Finish();
150 bool SVGCircleElement::IsLengthChangedViaCSS(const ComputedStyle
& aNewStyle
,
151 const ComputedStyle
& aOldStyle
) {
152 const auto& newSVGReset
= *aNewStyle
.StyleSVGReset();
153 const auto& oldSVGReset
= *aOldStyle
.StyleSVGReset();
155 return newSVGReset
.mCx
!= oldSVGReset
.mCx
||
156 newSVGReset
.mCy
!= oldSVGReset
.mCy
|| newSVGReset
.mR
!= oldSVGReset
.mR
;
159 nsCSSPropertyID
SVGCircleElement::GetCSSPropertyIdForAttrEnum(
163 return eCSSProperty_cx
;
165 return eCSSProperty_cy
;
167 return eCSSProperty_r
;
169 MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
170 return eCSSProperty_UNKNOWN
;
174 } // namespace mozilla::dom