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 "core/svg/SVGAngle.h" 24 25#include "bindings/v8/ExceptionState.h" 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 73template<typename CharType> 74static SVGAngle::SVGAngleType stringToAngleType(const CharType*& ptr, const CharType* end) 75{ 76 // If there's no unit given, the angle type is unspecified. 77 if (ptr == end) 78 return SVGAngle::SVG_ANGLETYPE_UNSPECIFIED; 79 80 const CharType firstChar = *ptr; 81 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 87 const CharType secondChar = *ptr; 88 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 94 const CharType thirdChar = *ptr; 95 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 105 const CharType fourthChar = *ptr; 106 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, ("deg")); 118 return String::number(m_valueInSpecifiedUnits) + degString; 119 } 120 case SVG_ANGLETYPE_RAD: { 121 DEFINE_STATIC_LOCAL(String, radString, ("rad")); 122 return String::number(m_valueInSpecifiedUnits) + radString; 123 } 124 case SVG_ANGLETYPE_GRAD: { 125 DEFINE_STATIC_LOCAL(String, gradString, ("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 137template<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 153void SVGAngle::setValueAsString(const String& value, ExceptionState& es) 154{ 155 if (value.isEmpty()) { 156 m_unitType = SVG_ANGLETYPE_UNSPECIFIED; 157 return; 158 } 159 160 float valueInSpecifiedUnits = 0; 161 SVGAngleType unitType = SVG_ANGLETYPE_UNKNOWN; 162 163 bool success = value.is8Bit() ? parseValue<LChar>(value, valueInSpecifiedUnits, unitType) 164 : parseValue<UChar>(value, valueInSpecifiedUnits, unitType); 165 if (!success) { 166 es.throwDOMException(SyntaxError); 167 return; 168 } 169 170 m_unitType = unitType; 171 m_valueInSpecifiedUnits = valueInSpecifiedUnits; 172} 173 174void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits, ExceptionState& es) 175{ 176 if (unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) { 177 es.throwDOMException(NotSupportedError); 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, ExceptionState& es) 188{ 189 if (unitType == SVG_ANGLETYPE_UNKNOWN || m_unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) { 190 es.throwDOMException(NotSupportedError); 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} 255