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
24 #if ENABLE(SVG)
25 #include "SVGAngle.h"
26
27 #include "SVGParserUtilities.h"
28 #include <wtf/MathExtras.h>
29 #include <wtf/text/StringConcatenate.h>
30
31 namespace WebCore {
32
SVGAngle()33 SVGAngle::SVGAngle()
34 : m_unitType(SVG_ANGLETYPE_UNSPECIFIED)
35 , m_valueInSpecifiedUnits(0)
36 {
37 }
38
value() const39 float 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
setValue(float value)56 void 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
stringToAngleType(const UChar * & ptr,const UChar * end)73 inline SVGAngle::SVGAngleType stringToAngleType(const UChar*& ptr, const UChar* end)
74 {
75 // If there's no unit given, the angle type is unspecified.
76 if (ptr == end)
77 return SVGAngle::SVG_ANGLETYPE_UNSPECIFIED;
78
79 const UChar firstChar = *ptr;
80
81 // If the unit contains only one character, the angle type is unknown.
82 ++ptr;
83 if (ptr == end)
84 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
85
86 const UChar secondChar = *ptr;
87
88 // If the unit contains only two characters, the angle type is unknown.
89 ++ptr;
90 if (ptr == end)
91 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
92
93 const UChar thirdChar = *ptr;
94 if (firstChar == 'd' && secondChar == 'e' && thirdChar == 'g')
95 return SVGAngle::SVG_ANGLETYPE_DEG;
96 if (firstChar == 'r' && secondChar == 'a' && thirdChar == 'd')
97 return SVGAngle::SVG_ANGLETYPE_RAD;
98
99 // If the unit contains three characters, but is not deg or rad, then it's unknown.
100 ++ptr;
101 if (ptr == end)
102 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
103
104 const UChar fourthChar = *ptr;
105
106 if (firstChar == 'g' && secondChar == 'r' && thirdChar == 'a' && fourthChar == 'd')
107 return SVGAngle::SVG_ANGLETYPE_GRAD;
108
109 return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
110 }
111
valueAsString() const112 String SVGAngle::valueAsString() const
113 {
114 switch (m_unitType) {
115 case SVG_ANGLETYPE_DEG:
116 return makeString(String::number(m_valueInSpecifiedUnits), "deg");
117 case SVG_ANGLETYPE_RAD:
118 return makeString(String::number(m_valueInSpecifiedUnits), "rad");
119 case SVG_ANGLETYPE_GRAD:
120 return makeString(String::number(m_valueInSpecifiedUnits), "grad");
121 case SVG_ANGLETYPE_UNSPECIFIED:
122 case SVG_ANGLETYPE_UNKNOWN:
123 return makeString(String::number(m_valueInSpecifiedUnits));
124 }
125
126 ASSERT_NOT_REACHED();
127 return String();
128 }
129
setValueAsString(const String & value,ExceptionCode & ec)130 void SVGAngle::setValueAsString(const String& value, ExceptionCode& ec)
131 {
132 if (value.isEmpty()) {
133 m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
134 return;
135 }
136
137 float valueInSpecifiedUnits = 0;
138 const UChar* ptr = value.characters();
139 const UChar* end = ptr + value.length();
140
141 if (!parseNumber(ptr, end, valueInSpecifiedUnits, false)) {
142 ec = SYNTAX_ERR;
143 return;
144 }
145
146 SVGAngleType unitType = stringToAngleType(ptr, end);
147 if (unitType == SVG_ANGLETYPE_UNKNOWN) {
148 ec = SYNTAX_ERR;
149 return;
150 }
151
152 m_unitType = unitType;
153 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
154 }
155
newValueSpecifiedUnits(unsigned short unitType,float valueInSpecifiedUnits,ExceptionCode & ec)156 void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits, ExceptionCode& ec)
157 {
158 if (unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
159 ec = NOT_SUPPORTED_ERR;
160 return;
161 }
162
163 if (unitType != m_unitType)
164 m_unitType = static_cast<SVGAngleType>(unitType);
165
166 m_valueInSpecifiedUnits = valueInSpecifiedUnits;
167 }
168
convertToSpecifiedUnits(unsigned short unitType,ExceptionCode & ec)169 void SVGAngle::convertToSpecifiedUnits(unsigned short unitType, ExceptionCode& ec)
170 {
171 if (unitType == SVG_ANGLETYPE_UNKNOWN || m_unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
172 ec = NOT_SUPPORTED_ERR;
173 return;
174 }
175
176 if (unitType == m_unitType)
177 return;
178
179 switch (m_unitType) {
180 case SVG_ANGLETYPE_RAD:
181 switch (unitType) {
182 case SVG_ANGLETYPE_GRAD:
183 m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits);
184 break;
185 case SVG_ANGLETYPE_UNSPECIFIED:
186 case SVG_ANGLETYPE_DEG:
187 m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits);
188 break;
189 case SVG_ANGLETYPE_RAD:
190 case SVG_ANGLETYPE_UNKNOWN:
191 ASSERT_NOT_REACHED();
192 break;
193 }
194 break;
195 case SVG_ANGLETYPE_GRAD:
196 switch (unitType) {
197 case SVG_ANGLETYPE_RAD:
198 m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits);
199 break;
200 case SVG_ANGLETYPE_UNSPECIFIED:
201 case SVG_ANGLETYPE_DEG:
202 m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits);
203 break;
204 case SVG_ANGLETYPE_GRAD:
205 case SVG_ANGLETYPE_UNKNOWN:
206 ASSERT_NOT_REACHED();
207 break;
208 }
209 break;
210 case SVG_ANGLETYPE_UNSPECIFIED:
211 // Spec: For angles, a unitless value is treated the same as if degrees were specified.
212 case SVG_ANGLETYPE_DEG:
213 switch (unitType) {
214 case SVG_ANGLETYPE_RAD:
215 m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits);
216 break;
217 case SVG_ANGLETYPE_GRAD:
218 m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits);
219 break;
220 case SVG_ANGLETYPE_UNSPECIFIED:
221 break;
222 case SVG_ANGLETYPE_DEG:
223 case SVG_ANGLETYPE_UNKNOWN:
224 ASSERT_NOT_REACHED();
225 break;
226 }
227 break;
228 case SVG_ANGLETYPE_UNKNOWN:
229 ASSERT_NOT_REACHED();
230 break;
231 }
232
233 m_unitType = static_cast<SVGAngleType>(unitType);
234 }
235
236 }
237
238 #endif // ENABLE(SVG)
239