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 30namespace WebCore { 31 32SVGAngle::SVGAngle() 33 : m_unitType(SVG_ANGLETYPE_UNSPECIFIED) 34 , m_valueInSpecifiedUnits(0) 35{ 36} 37 38float 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 55void 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 72inline 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 111String 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 135void 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 162void 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 175void 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} 243