2010-10-23 Nikolas Zimmermann <nzimmermann@rim.com>
[WebKit-https.git] / WebCore / svg / SVGAngle.cpp
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/text/StringConcatenate.h>
29 #include <wtf/MathExtras.h>
30
31 namespace WebCore {
32
33 SVGAngle::SVGAngle()
34     : m_unitType(SVG_ANGLETYPE_UNSPECIFIED)
35     , m_valueInSpecifiedUnits(0)
36 {
37 }
38
39 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
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
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
112 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
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
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
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)