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/. */
6
7 #include "mozilla/dom/SVGEllipseElement.h"
8 #include "mozilla/dom/SVGEllipseElementBinding.h"
9 #include "mozilla/dom/SVGLengthBinding.h"
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/gfx/PathHelpers.h"
12 #include "mozilla/RefPtr.h"
13
14 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse)
15
16 using namespace mozilla::gfx;
17
18 namespace mozilla {
19 namespace dom {
20
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)21 JSObject* SVGEllipseElement::WrapNode(JSContext* aCx,
22 JS::Handle<JSObject*> aGivenProto) {
23 return SVGEllipseElementBinding::Wrap(aCx, this, aGivenProto);
24 }
25
26 nsSVGElement::LengthInfo SVGEllipseElement::sLengthInfo[4] = {
27 {&nsGkAtoms::cx, 0, SVGLengthBinding::SVG_LENGTHTYPE_NUMBER,
28 SVGContentUtils::X},
29 {&nsGkAtoms::cy, 0, SVGLengthBinding::SVG_LENGTHTYPE_NUMBER,
30 SVGContentUtils::Y},
31 {&nsGkAtoms::rx, 0, SVGLengthBinding::SVG_LENGTHTYPE_NUMBER,
32 SVGContentUtils::X},
33 {&nsGkAtoms::ry, 0, SVGLengthBinding::SVG_LENGTHTYPE_NUMBER,
34 SVGContentUtils::Y},
35 };
36
37 //----------------------------------------------------------------------
38 // Implementation
39
SVGEllipseElement(already_AddRefed<mozilla::dom::NodeInfo> & aNodeInfo)40 SVGEllipseElement::SVGEllipseElement(
41 already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
42 : SVGEllipseElementBase(aNodeInfo) {}
43
44 //----------------------------------------------------------------------
45 // nsIDOMNode methods
46
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGEllipseElement)47 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGEllipseElement)
48
49 //----------------------------------------------------------------------
50 // nsIDOMSVGEllipseElement methods
51
52 already_AddRefed<SVGAnimatedLength> SVGEllipseElement::Cx() {
53 return mLengthAttributes[CX].ToDOMAnimatedLength(this);
54 }
55
Cy()56 already_AddRefed<SVGAnimatedLength> SVGEllipseElement::Cy() {
57 return mLengthAttributes[CY].ToDOMAnimatedLength(this);
58 }
59
Rx()60 already_AddRefed<SVGAnimatedLength> SVGEllipseElement::Rx() {
61 return mLengthAttributes[RX].ToDOMAnimatedLength(this);
62 }
63
Ry()64 already_AddRefed<SVGAnimatedLength> SVGEllipseElement::Ry() {
65 return mLengthAttributes[RY].ToDOMAnimatedLength(this);
66 }
67
68 //----------------------------------------------------------------------
69 // nsSVGElement methods
70
HasValidDimensions() const71 /* virtual */ bool SVGEllipseElement::HasValidDimensions() const {
72 return mLengthAttributes[RX].IsExplicitlySet() &&
73 mLengthAttributes[RX].GetAnimValInSpecifiedUnits() > 0 &&
74 mLengthAttributes[RY].IsExplicitlySet() &&
75 mLengthAttributes[RY].GetAnimValInSpecifiedUnits() > 0;
76 }
77
GetLengthInfo()78 nsSVGElement::LengthAttributesInfo SVGEllipseElement::GetLengthInfo() {
79 return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
80 ArrayLength(sLengthInfo));
81 }
82
83 //----------------------------------------------------------------------
84 // SVGGeometryElement methods
85
GetGeometryBounds(Rect * aBounds,const StrokeOptions & aStrokeOptions,const Matrix & aToBoundsSpace,const Matrix * aToNonScalingStrokeSpace)86 bool SVGEllipseElement::GetGeometryBounds(
87 Rect* aBounds, const StrokeOptions& aStrokeOptions,
88 const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) {
89 float x, y, rx, ry;
90 GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
91
92 if (rx <= 0.f || ry <= 0.f) {
93 // Rendering of the element is disabled
94 *aBounds = Rect(aToBoundsSpace.TransformPoint(Point(x, y)), Size());
95 return true;
96 }
97
98 if (aToBoundsSpace.IsRectilinear()) {
99 // Optimize the case where we can treat the ellipse as a rectangle and
100 // still get tight bounds.
101 if (aStrokeOptions.mLineWidth > 0.f) {
102 if (aToNonScalingStrokeSpace) {
103 if (aToNonScalingStrokeSpace->IsRectilinear()) {
104 MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
105 Rect userBounds(x - rx, y - ry, 2 * rx, 2 * ry);
106 SVGContentUtils::RectilinearGetStrokeBounds(
107 userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
108 aStrokeOptions.mLineWidth, aBounds);
109 return true;
110 }
111 return false;
112 }
113 rx += aStrokeOptions.mLineWidth / 2.f;
114 ry += aStrokeOptions.mLineWidth / 2.f;
115 }
116 Rect rect(x - rx, y - ry, 2 * rx, 2 * ry);
117 *aBounds = aToBoundsSpace.TransformBounds(rect);
118 return true;
119 }
120
121 return false;
122 }
123
BuildPath(PathBuilder * aBuilder)124 already_AddRefed<Path> SVGEllipseElement::BuildPath(PathBuilder* aBuilder) {
125 float x, y, rx, ry;
126 GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
127
128 if (rx <= 0.0f || ry <= 0.0f) {
129 return nullptr;
130 }
131
132 EllipseToBezier(aBuilder, Point(x, y), Size(rx, ry));
133
134 return aBuilder->Finish();
135 }
136
137 } // namespace dom
138 } // namespace mozilla
139