Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 #include "core/rendering/svg/RenderSVGEllipse.h"
30
31 #include "core/svg/SVGCircleElement.h"
32 #include "core/svg/SVGEllipseElement.h"
33 #include "platform/graphics/GraphicsContext.h"
34
35 namespace blink {
36
37 RenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement* node)
38     : RenderSVGShape(node)
39     , m_usePathFallback(false)
40 {
41 }
42
43 RenderSVGEllipse::~RenderSVGEllipse()
44 {
45 }
46
47 void RenderSVGEllipse::updateShapeFromElement()
48 {
49     // Before creating a new object we need to clear the cached bounding box
50     // to avoid using garbage.
51     m_fillBoundingBox = FloatRect();
52     m_strokeBoundingBox = FloatRect();
53     m_center = FloatPoint();
54     m_radii = FloatSize();
55     m_usePathFallback = false;
56
57     calculateRadiiAndCenter();
58
59     // Spec: "A negative value is an error. A value of zero disables rendering of the element."
60     if (m_radii.width() < 0 || m_radii.height() < 0)
61         return;
62
63     if (!m_radii.isEmpty()) {
64         // Fallback to RenderSVGShape if shape has a non-scaling stroke.
65         if (hasNonScalingStroke()) {
66             RenderSVGShape::updateShapeFromElement();
67             m_usePathFallback = true;
68             return;
69         }
70     }
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         SVGCircleElement& circle = toSVGCircleElement(*element());
83
84         SVGLengthContext lengthContext(&circle);
85         float radius = circle.r()->currentValue()->value(lengthContext);
86         m_radii = FloatSize(radius, radius);
87         m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext));
88         return;
89     }
90
91     SVGEllipseElement& ellipse = toSVGEllipseElement(*element());
92
93     SVGLengthContext lengthContext(&ellipse);
94     m_radii = FloatSize(ellipse.rx()->currentValue()->value(lengthContext), ellipse.ry()->currentValue()->value(lengthContext));
95     m_center = FloatPoint(ellipse.cx()->currentValue()->value(lengthContext), ellipse.cy()->currentValue()->value(lengthContext));
96 }
97
98 void RenderSVGEllipse::fillShape(GraphicsContext* context) const
99 {
100     if (m_usePathFallback) {
101         RenderSVGShape::fillShape(context);
102         return;
103     }
104     context->fillEllipse(m_fillBoundingBox);
105 }
106
107 void RenderSVGEllipse::strokeShape(GraphicsContext* context) const
108 {
109     if (!style()->svgStyle().hasVisibleStroke())
110         return;
111     if (m_usePathFallback) {
112         RenderSVGShape::strokeShape(context);
113         return;
114     }
115     context->strokeEllipse(m_fillBoundingBox);
116 }
117
118 bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
119 {
120     // The optimized contains code below does not support non-smooth strokes so we need
121     // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
122     if (m_usePathFallback || !hasSmoothStroke()) {
123         if (!hasPath())
124             RenderSVGShape::updateShapeFromElement();
125         return RenderSVGShape::shapeDependentStrokeContains(point);
126     }
127
128     float halfStrokeWidth = strokeWidth() / 2;
129     FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
130
131     // This works by checking if the point satisfies the ellipse equation,
132     // (x/rX)^2 + (y/rY)^2 <= 1, for the outer but not the inner stroke.
133     float xrXOuter = center.x() / (m_radii.width() + halfStrokeWidth);
134     float yrYOuter = center.y() / (m_radii.height() + halfStrokeWidth);
135     if (xrXOuter * xrXOuter + yrYOuter * yrYOuter > 1.0)
136         return false;
137
138     float xrXInner = center.x() / (m_radii.width() - halfStrokeWidth);
139     float yrYInner = center.y() / (m_radii.height() - halfStrokeWidth);
140     return xrXInner * xrXInner + yrYInner * yrYInner >= 1.0;
141 }
142
143 bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
144 {
145     if (m_usePathFallback)
146         return RenderSVGShape::shapeDependentFillContains(point, fillRule);
147
148     FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
149
150     // This works by checking if the point satisfies the ellipse equation.
151     // (x/rX)^2 + (y/rY)^2 <= 1
152     float xrX = center.x() / m_radii.width();
153     float yrY = center.y() / m_radii.height();
154     return xrX * xrX + yrY * yrY <= 1.0;
155 }
156
157 }