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