1/*
2 * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#include "config.h"
23#include "SVGAngleValue.h"
24
25#include "SVGParserUtilities.h"
26#include <wtf/MathExtras.h>
27#include <wtf/text/StringConcatenateNumbers.h>
28
29namespace WebCore {
30
31float SVGAngleValue::value() const
32{
33 switch (m_unitType) {
34 case SVG_ANGLETYPE_GRAD:
35 return grad2deg(m_valueInSpecifiedUnits);
36 case SVG_ANGLETYPE_RAD:
37 return rad2deg(m_valueInSpecifiedUnits);
38 case SVG_ANGLETYPE_UNSPECIFIED:
39 case SVG_ANGLETYPE_UNKNOWN:
40 case SVG_ANGLETYPE_DEG:
41 return m_valueInSpecifiedUnits;
42 }
43 ASSERT_NOT_REACHED();
44 return 0;
45}
46
47void SVGAngleValue::setValue(float value)
48{
49 switch (m_unitType) {
50 case SVG_ANGLETYPE_GRAD:
51 m_valueInSpecifiedUnits = deg2grad(value);
52 return;
53 case SVG_ANGLETYPE_RAD:
54 m_valueInSpecifiedUnits = deg2rad(value);
55 return;
56 case SVG_ANGLETYPE_UNSPECIFIED:
57 case SVG_ANGLETYPE_UNKNOWN:
58 case SVG_ANGLETYPE_DEG:
59 m_valueInSpecifiedUnits = value;
60 return;
61 }
62 ASSERT_NOT_REACHED();
63}
64
65String SVGAngleValue::valueAsString() const
66{
67 switch (m_unitType) {
68 case SVG_ANGLETYPE_DEG:
69 return makeString(FormattedNumber::fixedPrecision(m_valueInSpecifiedUnits), "deg");
70 case SVG_ANGLETYPE_RAD:
71 return makeString(FormattedNumber::fixedPrecision(m_valueInSpecifiedUnits), "rad");
72 case SVG_ANGLETYPE_GRAD:
73 return makeString(FormattedNumber::fixedPrecision(m_valueInSpecifiedUnits), "grad");
74 case SVG_ANGLETYPE_UNSPECIFIED:
75 case SVG_ANGLETYPE_UNKNOWN:
76 return String::numberToStringFixedPrecision(m_valueInSpecifiedUnits);
77 }
78
79 ASSERT_NOT_REACHED();
80 return String();
81}
82
83static inline SVGAngleValue::Type parseAngleType(const UChar* ptr, const UChar* end)
84{
85 switch (end - ptr) {
86 case 0:
87 return SVGAngleValue::SVG_ANGLETYPE_UNSPECIFIED;
88 case 3:
89 if (ptr[0] == 'd' && ptr[1] == 'e' && ptr[2] == 'g')
90 return SVGAngleValue::SVG_ANGLETYPE_DEG;
91 if (ptr[0] == 'r' && ptr[1] == 'a' && ptr[2] == 'd')
92 return SVGAngleValue::SVG_ANGLETYPE_RAD;
93 break;
94 case 4:
95 if (ptr[0] == 'g' && ptr[1] == 'r' && ptr[2] == 'a' && ptr[3] == 'd')
96 return SVGAngleValue::SVG_ANGLETYPE_GRAD;
97 break;
98 }
99 return SVGAngleValue::SVG_ANGLETYPE_UNKNOWN;
100}
101
102ExceptionOr<void> SVGAngleValue::setValueAsString(const String& value)
103{
104 if (value.isEmpty()) {
105 m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
106 return { };
107 }
108
109 auto upconvertedCharacters = StringView(value).upconvertedCharacters();
110 const UChar* ptr = upconvertedCharacters;
111 const UChar* end = ptr + value.length();
112
113 float valueInSpecifiedUnits = 0;
114 if (!parseNumber(ptr, end, valueInSpecifiedUnits, false))
115 return Exception { SyntaxError };
116
117 auto unitType = parseAngleType(ptr, end);
118 if (unitType == SVG_ANGLETYPE_UNKNOWN)
119 return Exception { SyntaxError };
120
121 m_unitType = unitType;
122 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
123 return { };
124}
125
126ExceptionOr<void> SVGAngleValue::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
127{
128 if (unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD)
129 return Exception { NotSupportedError };
130
131 m_unitType = static_cast<Type>(unitType);
132 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
133 return { };
134}
135
136ExceptionOr<void> SVGAngleValue::convertToSpecifiedUnits(unsigned short unitType)
137{
138 if (unitType == SVG_ANGLETYPE_UNKNOWN || m_unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD)
139 return Exception { NotSupportedError };
140
141 if (unitType == m_unitType)
142 return { };
143
144 switch (m_unitType) {
145 case SVG_ANGLETYPE_RAD:
146 switch (unitType) {
147 case SVG_ANGLETYPE_GRAD:
148 m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits);
149 break;
150 case SVG_ANGLETYPE_UNSPECIFIED:
151 case SVG_ANGLETYPE_DEG:
152 m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits);
153 break;
154 case SVG_ANGLETYPE_RAD:
155 case SVG_ANGLETYPE_UNKNOWN:
156 ASSERT_NOT_REACHED();
157 break;
158 }
159 break;
160 case SVG_ANGLETYPE_GRAD:
161 switch (unitType) {
162 case SVG_ANGLETYPE_RAD:
163 m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits);
164 break;
165 case SVG_ANGLETYPE_UNSPECIFIED:
166 case SVG_ANGLETYPE_DEG:
167 m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits);
168 break;
169 case SVG_ANGLETYPE_GRAD:
170 case SVG_ANGLETYPE_UNKNOWN:
171 ASSERT_NOT_REACHED();
172 break;
173 }
174 break;
175 case SVG_ANGLETYPE_UNSPECIFIED:
176 // Spec: For angles, a unitless value is treated the same as if degrees were specified.
177 case SVG_ANGLETYPE_DEG:
178 switch (unitType) {
179 case SVG_ANGLETYPE_RAD:
180 m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits);
181 break;
182 case SVG_ANGLETYPE_GRAD:
183 m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits);
184 break;
185 case SVG_ANGLETYPE_UNSPECIFIED:
186 case SVG_ANGLETYPE_DEG:
187 break;
188 case SVG_ANGLETYPE_UNKNOWN:
189 ASSERT_NOT_REACHED();
190 break;
191 }
192 break;
193 case SVG_ANGLETYPE_UNKNOWN:
194 ASSERT_NOT_REACHED();
195 break;
196 }
197
198 m_unitType = static_cast<Type>(unitType);
199
200 return { };
201}
202
203}
204