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