Move locale information into FontDescription
[WebKit-https.git] / Source / WebCore / platform / graphics / Path.cpp
1 /*
2  * Copyright (C) 2003, 2006 Apple Inc.  All rights reserved.
3  *                     2006 Rob Buis <buis@kde.org>
4  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28
29 #include "config.h"
30 #include "Path.h"
31
32 #include "FloatPoint.h"
33 #include "FloatRect.h"
34 #include "FloatRoundedRect.h"
35 #include "PathTraversalState.h"
36 #include "RoundedRect.h"
37 #include <math.h>
38 #include <wtf/MathExtras.h>
39
40 namespace WebCore {
41
42 float Path::length() const
43 {
44     PathTraversalState traversalState(PathTraversalState::Action::TotalLength);
45
46     apply([&traversalState](const PathElement& element) {
47         traversalState.processPathElement(element);
48     });
49
50     return traversalState.totalLength();
51 }
52
53 PathTraversalState Path::traversalStateAtLength(float length, bool& success) const
54 {
55     PathTraversalState traversalState(PathTraversalState::Action::VectorAtLength, length);
56
57     apply([&traversalState](const PathElement& element) {
58         traversalState.processPathElement(element);
59     });
60
61     success = traversalState.success();
62     return traversalState;
63 }
64
65 FloatPoint Path::pointAtLength(float length, bool& success) const
66 {
67     return traversalStateAtLength(length, success).current();
68 }
69
70 float Path::normalAngleAtLength(float length, bool& success) const
71 {
72     return traversalStateAtLength(length, success).normalAngle();
73 }
74
75 void Path::addRoundedRect(const FloatRect& rect, const FloatSize& roundingRadii, RoundedRectStrategy strategy)
76 {
77     if (rect.isEmpty())
78         return;
79
80     FloatSize radius(roundingRadii);
81     FloatSize halfSize(rect.width() / 2, rect.height() / 2);
82
83     // Apply the SVG corner radius constraints, per the rect section of the SVG shapes spec: if
84     // one of rx,ry is negative, then the other corner radius value is used. If both values are
85     // negative then rx = ry = 0. If rx is greater than half of the width of the rectangle
86     // then set rx to half of the width; ry is handled similarly.
87
88     if (radius.width() < 0)
89         radius.setWidth((radius.height() < 0) ? 0 : radius.height());
90
91     if (radius.height() < 0)
92         radius.setHeight(radius.width());
93
94     if (radius.width() > halfSize.width())
95         radius.setWidth(halfSize.width());
96
97     if (radius.height() > halfSize.height())
98         radius.setHeight(halfSize.height());
99
100     addRoundedRect(FloatRoundedRect(rect, radius, radius, radius, radius), strategy);
101 }
102
103 void Path::addRoundedRect(const FloatRoundedRect& r, RoundedRectStrategy strategy)
104 {
105     if (r.isEmpty())
106         return;
107
108     const FloatRoundedRect::Radii& radii = r.radii();
109     const FloatRect& rect = r.rect();
110
111     if (!r.isRenderable()) {
112         // If all the radii cannot be accommodated, return a rect.
113         addRect(rect);
114         return;
115     }
116
117     if (strategy == PreferNativeRoundedRect) {
118 #if USE(CG)
119         platformAddPathForRoundedRect(rect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight());
120         return;
121 #endif
122     }
123
124     addBeziersForRoundedRect(rect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight());
125 }
126
127 void Path::addRoundedRect(const RoundedRect& r)
128 {
129     addRoundedRect(FloatRoundedRect(r));
130 }
131
132 // Approximation of control point positions on a bezier to simulate a quarter of a circle.
133 // This is 1-kappa, where kappa = 4 * (sqrt(2) - 1) / 3
134 static const float gCircleControlPoint = 0.447715f;
135
136 void Path::addBeziersForRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
137 {
138     moveTo(FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));
139
140     addLineTo(FloatPoint(rect.maxX() - topRightRadius.width(), rect.y()));
141     if (topRightRadius.width() > 0 || topRightRadius.height() > 0)
142         addBezierCurveTo(FloatPoint(rect.maxX() - topRightRadius.width() * gCircleControlPoint, rect.y()),
143             FloatPoint(rect.maxX(), rect.y() + topRightRadius.height() * gCircleControlPoint),
144             FloatPoint(rect.maxX(), rect.y() + topRightRadius.height()));
145     addLineTo(FloatPoint(rect.maxX(), rect.maxY() - bottomRightRadius.height()));
146     if (bottomRightRadius.width() > 0 || bottomRightRadius.height() > 0)
147         addBezierCurveTo(FloatPoint(rect.maxX(), rect.maxY() - bottomRightRadius.height() * gCircleControlPoint),
148             FloatPoint(rect.maxX() - bottomRightRadius.width() * gCircleControlPoint, rect.maxY()),
149             FloatPoint(rect.maxX() - bottomRightRadius.width(), rect.maxY()));
150     addLineTo(FloatPoint(rect.x() + bottomLeftRadius.width(), rect.maxY()));
151     if (bottomLeftRadius.width() > 0 || bottomLeftRadius.height() > 0)
152         addBezierCurveTo(FloatPoint(rect.x() + bottomLeftRadius.width() * gCircleControlPoint, rect.maxY()),
153             FloatPoint(rect.x(), rect.maxY() - bottomLeftRadius.height() * gCircleControlPoint),
154             FloatPoint(rect.x(), rect.maxY() - bottomLeftRadius.height()));
155     addLineTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height()));
156     if (topLeftRadius.width() > 0 || topLeftRadius.height() > 0)
157         addBezierCurveTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height() * gCircleControlPoint),
158             FloatPoint(rect.x() + topLeftRadius.width() * gCircleControlPoint, rect.y()),
159             FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));
160
161     closeSubpath();
162 }
163
164 #if !USE(CG)
165 FloatRect Path::fastBoundingRect() const
166 {
167     return boundingRect();
168 }
169 #endif
170
171 }