Bug 1805294 [wpt PR 37463] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / dom / svg / SVGCircleElement.cpp
blobc3f4beb40d33e31c540598201447cbba2f7e75a4
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,
28 SVGContentUtils::X},
29 {nsGkAtoms::cy, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
30 SVGContentUtils::Y},
31 {nsGkAtoms::r, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
32 SVGContentUtils::XY}};
34 //----------------------------------------------------------------------
35 // Implementation
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 //----------------------------------------------------------------------
49 // nsINode methods
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 //----------------------------------------------------------------------
68 // SVGElement methods
70 /* virtual */
71 bool SVGCircleElement::HasValidDimensions() const {
72 float r;
74 if (SVGGeometryProperty::ResolveAll<SVGT::R>(this, &r)) {
75 return r > 0;
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 ArrayLength(sLengthInfo));
88 //----------------------------------------------------------------------
89 // SVGGeometryElement methods
91 bool SVGCircleElement::GetGeometryBounds(
92 Rect* aBounds, const StrokeOptions& aStrokeOptions,
93 const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) {
94 float x, y, r;
96 DebugOnly<bool> ok =
97 SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::R>(this, &x, &y,
98 &r);
99 MOZ_ASSERT(ok, "SVGGeometryProperty::ResolveAll failed");
101 if (r <= 0.f) {
102 // Rendering of the element is disabled
103 *aBounds = Rect(aToBoundsSpace.TransformPoint(Point(x, y)), Size());
104 return true;
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);
118 return true;
120 return false;
122 r += aStrokeOptions.mLineWidth / 2.f;
124 Rect rect(x - r, y - r, 2 * r, 2 * r);
125 *aBounds = aToBoundsSpace.TransformBounds(rect);
126 return true;
129 return false;
132 already_AddRefed<Path> SVGCircleElement::BuildPath(PathBuilder* aBuilder) {
133 float x, y, r;
134 if (!SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::R>(this, &x,
135 &y, &r)) {
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);
141 if (r <= 0.0f) {
142 return 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(
160 uint8_t aAttrEnum) {
161 switch (aAttrEnum) {
162 case ATTR_CX:
163 return eCSSProperty_cx;
164 case ATTR_CY:
165 return eCSSProperty_cy;
166 case ATTR_R:
167 return eCSSProperty_r;
168 default:
169 MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
170 return eCSSProperty_UNKNOWN;
174 } // namespace mozilla::dom