blob: a90953ba2d2c07b5fca97d6650f5d9a9b1721f28 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010024#include "core/svg/SVGAngle.h"
25
26#include "core/dom/ExceptionCode.h"
27#include "core/svg/SVGParserUtilities.h"
28#include <wtf/MathExtras.h>
29#include <wtf/text/WTFString.h>
30
31namespace WebCore {
32
33SVGAngle::SVGAngle()
34 : m_unitType(SVG_ANGLETYPE_UNSPECIFIED)
35 , m_valueInSpecifiedUnits(0)
36{
37}
38
39float SVGAngle::value() const
40{
41 switch (m_unitType) {
42 case SVG_ANGLETYPE_GRAD:
43 return grad2deg(m_valueInSpecifiedUnits);
44 case SVG_ANGLETYPE_RAD:
45 return rad2deg(m_valueInSpecifiedUnits);
46 case SVG_ANGLETYPE_UNSPECIFIED:
47 case SVG_ANGLETYPE_UNKNOWN:
48 case SVG_ANGLETYPE_DEG:
49 return m_valueInSpecifiedUnits;
50 }
51
52 ASSERT_NOT_REACHED();
53 return 0;
54}
55
56void SVGAngle::setValue(float value)
57{
58 switch (m_unitType) {
59 case SVG_ANGLETYPE_GRAD:
60 m_valueInSpecifiedUnits = deg2grad(value);
61 break;
62 case SVG_ANGLETYPE_RAD:
63 m_valueInSpecifiedUnits = deg2rad(value);
64 break;
65 case SVG_ANGLETYPE_UNSPECIFIED:
66 case SVG_ANGLETYPE_UNKNOWN:
67 case SVG_ANGLETYPE_DEG:
68 m_valueInSpecifiedUnits = value;
69 break;
70 }
71}
72
Ben Murdoch591b9582013-07-10 11:41:44 +010073template<typename CharType>
74static SVGAngle::SVGAngleType stringToAngleType(const CharType*& ptr, const CharType* end)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010075{
76 // If there's no unit given, the angle type is unspecified.
77 if (ptr == end)
78 return SVGAngle::SVG_ANGLETYPE_UNSPECIFIED;
79
Ben Murdoch591b9582013-07-10 11:41:44 +010080 const CharType firstChar = *ptr;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010081
82 // If the unit contains only one character, the angle type is unknown.
83 ++ptr;
84 if (ptr == end)
85 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
86
Ben Murdoch591b9582013-07-10 11:41:44 +010087 const CharType secondChar = *ptr;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010088
89 // If the unit contains only two characters, the angle type is unknown.
90 ++ptr;
91 if (ptr == end)
92 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
93
Ben Murdoch591b9582013-07-10 11:41:44 +010094 const CharType thirdChar = *ptr;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010095 if (firstChar == 'd' && secondChar == 'e' && thirdChar == 'g')
96 return SVGAngle::SVG_ANGLETYPE_DEG;
97 if (firstChar == 'r' && secondChar == 'a' && thirdChar == 'd')
98 return SVGAngle::SVG_ANGLETYPE_RAD;
99
100 // If the unit contains three characters, but is not deg or rad, then it's unknown.
101 ++ptr;
102 if (ptr == end)
103 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
104
Ben Murdoch591b9582013-07-10 11:41:44 +0100105 const CharType fourthChar = *ptr;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100106
107 if (firstChar == 'g' && secondChar == 'r' && thirdChar == 'a' && fourthChar == 'd')
108 return SVGAngle::SVG_ANGLETYPE_GRAD;
109
110 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
111}
112
113String SVGAngle::valueAsString() const
114{
115 switch (m_unitType) {
116 case SVG_ANGLETYPE_DEG: {
117 DEFINE_STATIC_LOCAL(String, degString, (ASCIILiteral("deg")));
118 return String::number(m_valueInSpecifiedUnits) + degString;
119 }
120 case SVG_ANGLETYPE_RAD: {
121 DEFINE_STATIC_LOCAL(String, radString, (ASCIILiteral("rad")));
122 return String::number(m_valueInSpecifiedUnits) + radString;
123 }
124 case SVG_ANGLETYPE_GRAD: {
125 DEFINE_STATIC_LOCAL(String, gradString, (ASCIILiteral("grad")));
126 return String::number(m_valueInSpecifiedUnits) + gradString;
127 }
128 case SVG_ANGLETYPE_UNSPECIFIED:
129 case SVG_ANGLETYPE_UNKNOWN:
130 return String::number(m_valueInSpecifiedUnits);
131 }
132
133 ASSERT_NOT_REACHED();
134 return String();
135}
136
Ben Murdoch591b9582013-07-10 11:41:44 +0100137template<typename CharType>
138static bool parseValue(const String& value, float& valueInSpecifiedUnits, SVGAngle::SVGAngleType& unitType)
139{
140 const CharType* ptr = value.getCharacters<CharType>();
141 const CharType* end = ptr + value.length();
142
143 if (!parseNumber(ptr, end, valueInSpecifiedUnits, false))
144 return false;
145
146 unitType = stringToAngleType(ptr, end);
147 if (unitType == SVGAngle::SVG_ANGLETYPE_UNKNOWN)
148 return false;
149
150 return true;
151}
152
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100153void SVGAngle::setValueAsString(const String& value, ExceptionCode& ec)
154{
155 if (value.isEmpty()) {
156 m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
157 return;
158 }
159
160 float valueInSpecifiedUnits = 0;
Ben Murdoch591b9582013-07-10 11:41:44 +0100161 SVGAngleType unitType = SVG_ANGLETYPE_UNKNOWN;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100162
Ben Murdoch591b9582013-07-10 11:41:44 +0100163 bool success = value.is8Bit() ? parseValue<LChar>(value, valueInSpecifiedUnits, unitType)
164 : parseValue<UChar>(value, valueInSpecifiedUnits, unitType);
165 if (!success) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100166 ec = SYNTAX_ERR;
167 return;
168 }
169
170 m_unitType = unitType;
171 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
172}
173
174void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits, ExceptionCode& ec)
175{
176 if (unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
177 ec = NOT_SUPPORTED_ERR;
178 return;
179 }
180
181 if (unitType != m_unitType)
182 m_unitType = static_cast<SVGAngleType>(unitType);
183
184 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
185}
186
187void SVGAngle::convertToSpecifiedUnits(unsigned short unitType, ExceptionCode& ec)
188{
189 if (unitType == SVG_ANGLETYPE_UNKNOWN || m_unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
190 ec = NOT_SUPPORTED_ERR;
191 return;
192 }
193
194 if (unitType == m_unitType)
195 return;
196
197 switch (m_unitType) {
198 case SVG_ANGLETYPE_RAD:
199 switch (unitType) {
200 case SVG_ANGLETYPE_GRAD:
201 m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits);
202 break;
203 case SVG_ANGLETYPE_UNSPECIFIED:
204 case SVG_ANGLETYPE_DEG:
205 m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits);
206 break;
207 case SVG_ANGLETYPE_RAD:
208 case SVG_ANGLETYPE_UNKNOWN:
209 ASSERT_NOT_REACHED();
210 break;
211 }
212 break;
213 case SVG_ANGLETYPE_GRAD:
214 switch (unitType) {
215 case SVG_ANGLETYPE_RAD:
216 m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits);
217 break;
218 case SVG_ANGLETYPE_UNSPECIFIED:
219 case SVG_ANGLETYPE_DEG:
220 m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits);
221 break;
222 case SVG_ANGLETYPE_GRAD:
223 case SVG_ANGLETYPE_UNKNOWN:
224 ASSERT_NOT_REACHED();
225 break;
226 }
227 break;
228 case SVG_ANGLETYPE_UNSPECIFIED:
229 // Spec: For angles, a unitless value is treated the same as if degrees were specified.
230 case SVG_ANGLETYPE_DEG:
231 switch (unitType) {
232 case SVG_ANGLETYPE_RAD:
233 m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits);
234 break;
235 case SVG_ANGLETYPE_GRAD:
236 m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits);
237 break;
238 case SVG_ANGLETYPE_UNSPECIFIED:
239 break;
240 case SVG_ANGLETYPE_DEG:
241 case SVG_ANGLETYPE_UNKNOWN:
242 ASSERT_NOT_REACHED();
243 break;
244 }
245 break;
246 case SVG_ANGLETYPE_UNKNOWN:
247 ASSERT_NOT_REACHED();
248 break;
249 }
250
251 m_unitType = static_cast<SVGAngleType>(unitType);
252}
253
254}