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 "ExceptionCode.h" 28#include "SVGParserUtilities.h" 29#include <wtf/MathExtras.h> 30#include <wtf/text/WTFString.h> 31 32namespace WebCore { 33 34SVGAngle::SVGAngle() 35 : m_unitType(SVG_ANGLETYPE_UNSPECIFIED) 36 , m_valueInSpecifiedUnits(0) 37{ 38} 39 40float SVGAngle::value() const 41{ 42 switch (m_unitType) { 43 case SVG_ANGLETYPE_GRAD: 44 return grad2deg(m_valueInSpecifiedUnits); 45 case SVG_ANGLETYPE_RAD: 46 return rad2deg(m_valueInSpecifiedUnits); 47 case SVG_ANGLETYPE_UNSPECIFIED: 48 case SVG_ANGLETYPE_UNKNOWN: 49 case SVG_ANGLETYPE_DEG: 50 return m_valueInSpecifiedUnits; 51 } 52 53 ASSERT_NOT_REACHED(); 54 return 0; 55} 56 57void SVGAngle::setValue(float value) 58{ 59 switch (m_unitType) { 60 case SVG_ANGLETYPE_GRAD: 61 m_valueInSpecifiedUnits = deg2grad(value); 62 break; 63 case SVG_ANGLETYPE_RAD: 64 m_valueInSpecifiedUnits = deg2rad(value); 65 break; 66 case SVG_ANGLETYPE_UNSPECIFIED: 67 case SVG_ANGLETYPE_UNKNOWN: 68 case SVG_ANGLETYPE_DEG: 69 m_valueInSpecifiedUnits = value; 70 break; 71 } 72} 73 74inline SVGAngle::SVGAngleType stringToAngleType(const UChar*& ptr, const UChar* 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 UChar 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 UChar 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 UChar 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 UChar 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, (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 137void SVGAngle::setValueAsString(const String& value, ExceptionCode& ec) 138{ 139 if (value.isEmpty()) { 140 m_unitType = SVG_ANGLETYPE_UNSPECIFIED; 141 return; 142 } 143 144 float valueInSpecifiedUnits = 0; 145 const UChar* ptr = value.characters(); 146 const UChar* end = ptr + value.length(); 147 148 if (!parseNumber(ptr, end, valueInSpecifiedUnits, false)) { 149 ec = SYNTAX_ERR; 150 return; 151 } 152 153 SVGAngleType unitType = stringToAngleType(ptr, end); 154 if (unitType == SVG_ANGLETYPE_UNKNOWN) { 155 ec = SYNTAX_ERR; 156 return; 157 } 158 159 m_unitType = unitType; 160 m_valueInSpecifiedUnits = valueInSpecifiedUnits; 161} 162 163void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits, ExceptionCode& ec) 164{ 165 if (unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) { 166 ec = NOT_SUPPORTED_ERR; 167 return; 168 } 169 170 if (unitType != m_unitType) 171 m_unitType = static_cast<SVGAngleType>(unitType); 172 173 m_valueInSpecifiedUnits = valueInSpecifiedUnits; 174} 175 176void SVGAngle::convertToSpecifiedUnits(unsigned short unitType, ExceptionCode& ec) 177{ 178 if (unitType == SVG_ANGLETYPE_UNKNOWN || m_unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) { 179 ec = NOT_SUPPORTED_ERR; 180 return; 181 } 182 183 if (unitType == m_unitType) 184 return; 185 186 switch (m_unitType) { 187 case SVG_ANGLETYPE_RAD: 188 switch (unitType) { 189 case SVG_ANGLETYPE_GRAD: 190 m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits); 191 break; 192 case SVG_ANGLETYPE_UNSPECIFIED: 193 case SVG_ANGLETYPE_DEG: 194 m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits); 195 break; 196 case SVG_ANGLETYPE_RAD: 197 case SVG_ANGLETYPE_UNKNOWN: 198 ASSERT_NOT_REACHED(); 199 break; 200 } 201 break; 202 case SVG_ANGLETYPE_GRAD: 203 switch (unitType) { 204 case SVG_ANGLETYPE_RAD: 205 m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits); 206 break; 207 case SVG_ANGLETYPE_UNSPECIFIED: 208 case SVG_ANGLETYPE_DEG: 209 m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits); 210 break; 211 case SVG_ANGLETYPE_GRAD: 212 case SVG_ANGLETYPE_UNKNOWN: 213 ASSERT_NOT_REACHED(); 214 break; 215 } 216 break; 217 case SVG_ANGLETYPE_UNSPECIFIED: 218 // Spec: For angles, a unitless value is treated the same as if degrees were specified. 219 case SVG_ANGLETYPE_DEG: 220 switch (unitType) { 221 case SVG_ANGLETYPE_RAD: 222 m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits); 223 break; 224 case SVG_ANGLETYPE_GRAD: 225 m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits); 226 break; 227 case SVG_ANGLETYPE_UNSPECIFIED: 228 break; 229 case SVG_ANGLETYPE_DEG: 230 case SVG_ANGLETYPE_UNKNOWN: 231 ASSERT_NOT_REACHED(); 232 break; 233 } 234 break; 235 case SVG_ANGLETYPE_UNKNOWN: 236 ASSERT_NOT_REACHED(); 237 break; 238 } 239 240 m_unitType = static_cast<SVGAngleType>(unitType); 241} 242 243} 244 245#endif // ENABLE(SVG) 246