Generate more SVG type checks and conversions.
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGEllipse.cpp
1 /*
2  * Copyright (C) 2012 Google, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if ENABLE(SVG)
30 #include "RenderSVGEllipse.h"
31
32 #include "SVGCircleElement.h"
33 #include "SVGEllipseElement.h"
34 #include "SVGGraphicsElement.h"
35 #include "SVGNames.h"
36
37 namespace WebCore {
38
39 RenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement* node)
40     : RenderSVGShape(node)
41     , m_usePathFallback(false)
42 {
43 }
44
45 RenderSVGEllipse::~RenderSVGEllipse()
46 {
47 }
48
49 void RenderSVGEllipse::updateShapeFromElement()
50 {
51     // Before creating a new object we need to clear the cached bounding box
52     // to avoid using garbage.
53     m_fillBoundingBox = FloatRect();
54     m_strokeBoundingBox = FloatRect();
55     m_center = FloatPoint();
56     m_radii = FloatSize();
57
58     // Fallback to RenderSVGShape if shape has a non-scaling stroke.
59     if (hasNonScalingStroke()) {
60         RenderSVGShape::updateShapeFromElement();
61         m_usePathFallback = true;
62         return;
63     } else
64         m_usePathFallback = false;
65
66     calculateRadiiAndCenter();
67
68     // Spec: "A value of zero disables rendering of the element."
69     if (m_radii.width() <= 0 || m_radii.height() <= 0)
70         return;
71
72     m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height());
73     m_strokeBoundingBox = m_fillBoundingBox;
74     if (style()->svgStyle()->hasStroke())
75         m_strokeBoundingBox.inflate(strokeWidth() / 2);
76 }
77
78 void RenderSVGEllipse::calculateRadiiAndCenter()
79 {
80     ASSERT(element());
81     if (isSVGCircleElement(element())) {
82
83         SVGCircleElement* circle = toSVGCircleElement(element());
84
85         SVGLengthContext lengthContext(circle);
86         float radius = circle->r().value(lengthContext);
87         m_radii = FloatSize(radius, radius);
88         m_center = FloatPoint(circle->cx().value(lengthContext), circle->cy().value(lengthContext));
89         return;
90     }
91
92     ASSERT(isSVGEllipseElement(element()));
93     SVGEllipseElement* ellipse = toSVGEllipseElement(element());
94
95     SVGLengthContext lengthContext(ellipse);
96     m_radii = FloatSize(ellipse->rx().value(lengthContext), ellipse->ry().value(lengthContext));
97     m_center = FloatPoint(ellipse->cx().value(lengthContext), ellipse->cy().value(lengthContext));
98 }
99
100 void RenderSVGEllipse::fillShape(GraphicsContext* context) const
101 {
102     if (m_usePathFallback) {
103         RenderSVGShape::fillShape(context);
104         return;
105     }
106     context->fillEllipse(m_fillBoundingBox);
107 }
108
109 void RenderSVGEllipse::strokeShape(GraphicsContext* context) const
110 {
111     if (!style()->svgStyle()->hasVisibleStroke())
112         return;
113     if (m_usePathFallback) {
114         RenderSVGShape::strokeShape(context);
115         return;
116     }
117     context->strokeEllipse(m_fillBoundingBox);
118 }
119
120 bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
121 {
122     // The optimized contains code below does not support non-smooth strokes so we need
123     // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
124     if (m_usePathFallback || !hasSmoothStroke()) {
125         if (!hasPath())
126             RenderSVGShape::updateShapeFromElement();
127         return RenderSVGShape::shapeDependentStrokeContains(point);
128     }
129
130     float halfStrokeWidth = strokeWidth() / 2;
131     FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
132
133     // This works by checking if the point satisfies the ellipse equation,
134     // (x/rX)^2 + (y/rY)^2 <= 1, for the outer but not the inner stroke.
135     float xrXOuter = center.x() / (m_radii.width() + halfStrokeWidth);
136     float yrYOuter = center.y() / (m_radii.height() + halfStrokeWidth);
137     if (xrXOuter * xrXOuter + yrYOuter * yrYOuter > 1.0)
138         return false;
139
140     float xrXInner = center.x() / (m_radii.width() - halfStrokeWidth);
141     float yrYInner = center.y() / (m_radii.height() - halfStrokeWidth);
142     return xrXInner * xrXInner + yrYInner * yrYInner >= 1.0;
143 }
144
145 bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
146 {
147     if (m_usePathFallback)
148         return RenderSVGShape::shapeDependentFillContains(point, fillRule);
149
150     FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
151
152     // This works by checking if the point satisfies the ellipse equation.
153     // (x/rX)^2 + (y/rY)^2 <= 1
154     float xrX = center.x() / m_radii.width();
155     float yrY = center.y() / m_radii.height();
156     return xrX * xrX + yrY * yrY <= 1.0;
157 }
158
159 }
160
161 #endif // ENABLE(SVG)