1 /* 2 * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2007 Apple Inc. 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 #include "core/svg/SVGLength.h" 25 26 #include "SVGNames.h" 27 #include "bindings/v8/ExceptionState.h" 28 #include "bindings/v8/ExceptionStatePlaceholder.h" 29 #include "core/css/CSSPrimitiveValue.h" 30 #include "core/dom/ExceptionCode.h" 31 #include "core/svg/SVGParserUtilities.h" 32 #include "wtf/MathExtras.h" 33 #include "wtf/text/WTFString.h" 34 35 namespace WebCore { 36 37 static inline unsigned int storeUnit(SVGLengthMode mode, SVGLengthType type) 38 { 39 return (mode << 4) | type; 40 } 41 42 static inline SVGLengthMode extractMode(unsigned int unit) 43 { 44 unsigned int mode = unit >> 4; 45 return static_cast<SVGLengthMode>(mode); 46 } 47 48 static inline SVGLengthType extractType(unsigned int unit) 49 { 50 unsigned int mode = unit >> 4; 51 unsigned int type = unit ^ (mode << 4); 52 return static_cast<SVGLengthType>(type); 53 } 54 55 static inline String lengthTypeToString(SVGLengthType type) 56 { 57 switch (type) { 58 case LengthTypeUnknown: 59 case LengthTypeNumber: 60 return ""; 61 case LengthTypePercentage: 62 return "%"; 63 case LengthTypeEMS: 64 return "em"; 65 case LengthTypeEXS: 66 return "ex"; 67 case LengthTypePX: 68 return "px"; 69 case LengthTypeCM: 70 return "cm"; 71 case LengthTypeMM: 72 return "mm"; 73 case LengthTypeIN: 74 return "in"; 75 case LengthTypePT: 76 return "pt"; 77 case LengthTypePC: 78 return "pc"; 79 } 80 81 ASSERT_NOT_REACHED(); 82 return String(); 83 } 84 85 template<typename CharType> 86 static SVGLengthType stringToLengthType(const CharType*& ptr, const CharType* end) 87 { 88 if (ptr == end) 89 return LengthTypeNumber; 90 91 const UChar firstChar = *ptr; 92 93 if (++ptr == end) 94 return firstChar == '%' ? LengthTypePercentage : LengthTypeUnknown; 95 96 const UChar secondChar = *ptr; 97 98 if (++ptr != end) 99 return LengthTypeUnknown; 100 101 if (firstChar == 'e' && secondChar == 'm') 102 return LengthTypeEMS; 103 if (firstChar == 'e' && secondChar == 'x') 104 return LengthTypeEXS; 105 if (firstChar == 'p' && secondChar == 'x') 106 return LengthTypePX; 107 if (firstChar == 'c' && secondChar == 'm') 108 return LengthTypeCM; 109 if (firstChar == 'm' && secondChar == 'm') 110 return LengthTypeMM; 111 if (firstChar == 'i' && secondChar == 'n') 112 return LengthTypeIN; 113 if (firstChar == 'p' && secondChar == 't') 114 return LengthTypePT; 115 if (firstChar == 'p' && secondChar == 'c') 116 return LengthTypePC; 117 118 return LengthTypeUnknown; 119 } 120 121 SVGLength::SVGLength(SVGLengthMode mode, const String& valueAsString) 122 : m_valueInSpecifiedUnits(0) 123 , m_unit(storeUnit(mode, LengthTypeNumber)) 124 { 125 setValueAsString(valueAsString, IGNORE_EXCEPTION); 126 } 127 128 SVGLength::SVGLength(const SVGLengthContext& context, float value, SVGLengthMode mode, SVGLengthType unitType) 129 : m_valueInSpecifiedUnits(0) 130 , m_unit(storeUnit(mode, unitType)) 131 { 132 setValue(value, context, ASSERT_NO_EXCEPTION); 133 } 134 135 SVGLength::SVGLength(const SVGLength& other) 136 : m_valueInSpecifiedUnits(other.m_valueInSpecifiedUnits) 137 , m_unit(other.m_unit) 138 { 139 } 140 141 void SVGLength::setValueAsString(const String& valueAsString, SVGLengthMode mode, ExceptionState& es) 142 { 143 m_valueInSpecifiedUnits = 0; 144 m_unit = storeUnit(mode, LengthTypeNumber); 145 setValueAsString(valueAsString, es); 146 } 147 148 bool SVGLength::operator==(const SVGLength& other) const 149 { 150 return m_unit == other.m_unit 151 && m_valueInSpecifiedUnits == other.m_valueInSpecifiedUnits; 152 } 153 154 bool SVGLength::operator!=(const SVGLength& other) const 155 { 156 return !operator==(other); 157 } 158 159 SVGLength SVGLength::construct(SVGLengthMode mode, const String& valueAsString, SVGParsingError& parseError, SVGLengthNegativeValuesMode negativeValuesMode) 160 { 161 TrackExceptionState es; 162 SVGLength length(mode); 163 164 length.setValueAsString(valueAsString, es); 165 166 if (es.hadException()) 167 parseError = ParsingAttributeFailedError; 168 else if (negativeValuesMode == ForbidNegativeLengths && length.valueInSpecifiedUnits() < 0) 169 parseError = NegativeValueForbiddenError; 170 171 return length; 172 } 173 174 SVGLengthType SVGLength::unitType() const 175 { 176 return extractType(m_unit); 177 } 178 179 SVGLengthMode SVGLength::unitMode() const 180 { 181 return extractMode(m_unit); 182 } 183 184 float SVGLength::value(const SVGLengthContext& context) const 185 { 186 return value(context, IGNORE_EXCEPTION); 187 } 188 189 float SVGLength::value(const SVGLengthContext& context, ExceptionState& es) const 190 { 191 return context.convertValueToUserUnits(m_valueInSpecifiedUnits, extractMode(m_unit), extractType(m_unit), es); 192 } 193 194 void SVGLength::setValue(const SVGLengthContext& context, float value, SVGLengthMode mode, SVGLengthType unitType, ExceptionState& es) 195 { 196 m_unit = storeUnit(mode, unitType); 197 setValue(value, context, es); 198 } 199 200 void SVGLength::setValue(float value, const SVGLengthContext& context, ExceptionState& es) 201 { 202 // 100% = 100.0 instead of 1.0 for historical reasons, this could eventually be changed 203 if (extractType(m_unit) == LengthTypePercentage) 204 value = value / 100; 205 206 float convertedValue = context.convertValueFromUserUnits(value, extractMode(m_unit), extractType(m_unit), es); 207 if (!es.hadException()) 208 m_valueInSpecifiedUnits = convertedValue; 209 } 210 float SVGLength::valueAsPercentage() const 211 { 212 // 100% = 100.0 instead of 1.0 for historical reasons, this could eventually be changed 213 if (extractType(m_unit) == LengthTypePercentage) 214 return m_valueInSpecifiedUnits / 100; 215 216 return m_valueInSpecifiedUnits; 217 } 218 219 template<typename CharType> 220 static bool parseValueInternal(const String& string, float& convertedNumber, SVGLengthType& type) 221 { 222 const CharType* ptr = string.getCharacters<CharType>(); 223 const CharType* end = ptr + string.length(); 224 225 if (!parseNumber(ptr, end, convertedNumber, false)) 226 return false; 227 228 type = stringToLengthType(ptr, end); 229 ASSERT(ptr <= end); 230 if (type == LengthTypeUnknown) 231 return false; 232 233 return true; 234 } 235 236 void SVGLength::setValueAsString(const String& string, ExceptionState& es) 237 { 238 if (string.isEmpty()) 239 return; 240 241 float convertedNumber = 0; 242 SVGLengthType type = LengthTypeUnknown; 243 244 bool success = string.is8Bit() ? 245 parseValueInternal<LChar>(string, convertedNumber, type) : 246 parseValueInternal<UChar>(string, convertedNumber, type); 247 248 if (!success) { 249 es.throwDOMException(SyntaxError); 250 return; 251 } 252 253 m_unit = storeUnit(extractMode(m_unit), type); 254 m_valueInSpecifiedUnits = convertedNumber; 255 } 256 257 String SVGLength::valueAsString() const 258 { 259 return String::number(m_valueInSpecifiedUnits) + lengthTypeToString(extractType(m_unit)); 260 } 261 262 void SVGLength::newValueSpecifiedUnits(unsigned short type, float value, ExceptionState& es) 263 { 264 if (type == LengthTypeUnknown || type > LengthTypePC) { 265 es.throwDOMException(NotSupportedError); 266 return; 267 } 268 269 m_unit = storeUnit(extractMode(m_unit), static_cast<SVGLengthType>(type)); 270 m_valueInSpecifiedUnits = value; 271 } 272 273 void SVGLength::convertToSpecifiedUnits(unsigned short type, const SVGLengthContext& context, ExceptionState& es) 274 { 275 if (type == LengthTypeUnknown || type > LengthTypePC) { 276 es.throwDOMException(NotSupportedError); 277 return; 278 } 279 280 float valueInUserUnits = value(context, es); 281 if (es.hadException()) 282 return; 283 284 unsigned int originalUnitAndType = m_unit; 285 m_unit = storeUnit(extractMode(m_unit), static_cast<SVGLengthType>(type)); 286 setValue(valueInUserUnits, context, es); 287 if (!es.hadException()) 288 return; 289 290 // Eventually restore old unit and type 291 m_unit = originalUnitAndType; 292 } 293 294 SVGLength SVGLength::fromCSSPrimitiveValue(CSSPrimitiveValue* value) 295 { 296 ASSERT(value); 297 298 SVGLengthType svgType; 299 switch (value->primitiveType()) { 300 case CSSPrimitiveValue::CSS_NUMBER: 301 svgType = LengthTypeNumber; 302 break; 303 case CSSPrimitiveValue::CSS_PERCENTAGE: 304 svgType = LengthTypePercentage; 305 break; 306 case CSSPrimitiveValue::CSS_EMS: 307 svgType = LengthTypeEMS; 308 break; 309 case CSSPrimitiveValue::CSS_EXS: 310 svgType = LengthTypeEXS; 311 break; 312 case CSSPrimitiveValue::CSS_PX: 313 svgType = LengthTypePX; 314 break; 315 case CSSPrimitiveValue::CSS_CM: 316 svgType = LengthTypeCM; 317 break; 318 case CSSPrimitiveValue::CSS_MM: 319 svgType = LengthTypeMM; 320 break; 321 case CSSPrimitiveValue::CSS_IN: 322 svgType = LengthTypeIN; 323 break; 324 case CSSPrimitiveValue::CSS_PT: 325 svgType = LengthTypePT; 326 break; 327 case CSSPrimitiveValue::CSS_PC: 328 svgType = LengthTypePC; 329 break; 330 case CSSPrimitiveValue::CSS_UNKNOWN: 331 default: 332 svgType = LengthTypeUnknown; 333 break; 334 }; 335 336 if (svgType == LengthTypeUnknown) 337 return SVGLength(); 338 339 TrackExceptionState es; 340 SVGLength length; 341 length.newValueSpecifiedUnits(svgType, value->getFloatValue(), es); 342 if (es.hadException()) 343 return SVGLength(); 344 345 return length; 346 } 347 348 PassRefPtr<CSSPrimitiveValue> SVGLength::toCSSPrimitiveValue(const SVGLength& length) 349 { 350 CSSPrimitiveValue::UnitTypes cssType = CSSPrimitiveValue::CSS_UNKNOWN; 351 switch (length.unitType()) { 352 case LengthTypeUnknown: 353 break; 354 case LengthTypeNumber: 355 cssType = CSSPrimitiveValue::CSS_NUMBER; 356 break; 357 case LengthTypePercentage: 358 cssType = CSSPrimitiveValue::CSS_PERCENTAGE; 359 break; 360 case LengthTypeEMS: 361 cssType = CSSPrimitiveValue::CSS_EMS; 362 break; 363 case LengthTypeEXS: 364 cssType = CSSPrimitiveValue::CSS_EXS; 365 break; 366 case LengthTypePX: 367 cssType = CSSPrimitiveValue::CSS_PX; 368 break; 369 case LengthTypeCM: 370 cssType = CSSPrimitiveValue::CSS_CM; 371 break; 372 case LengthTypeMM: 373 cssType = CSSPrimitiveValue::CSS_MM; 374 break; 375 case LengthTypeIN: 376 cssType = CSSPrimitiveValue::CSS_IN; 377 break; 378 case LengthTypePT: 379 cssType = CSSPrimitiveValue::CSS_PT; 380 break; 381 case LengthTypePC: 382 cssType = CSSPrimitiveValue::CSS_PC; 383 break; 384 }; 385 386 return CSSPrimitiveValue::create(length.valueInSpecifiedUnits(), cssType); 387 } 388 389 SVGLengthMode SVGLength::lengthModeForAnimatedLengthAttribute(const QualifiedName& attrName) 390 { 391 typedef HashMap<QualifiedName, SVGLengthMode> LengthModeForLengthAttributeMap; 392 DEFINE_STATIC_LOCAL(LengthModeForLengthAttributeMap, s_lengthModeMap, ()); 393 394 if (s_lengthModeMap.isEmpty()) { 395 s_lengthModeMap.set(SVGNames::xAttr, LengthModeWidth); 396 s_lengthModeMap.set(SVGNames::yAttr, LengthModeHeight); 397 s_lengthModeMap.set(SVGNames::cxAttr, LengthModeWidth); 398 s_lengthModeMap.set(SVGNames::cyAttr, LengthModeHeight); 399 s_lengthModeMap.set(SVGNames::dxAttr, LengthModeWidth); 400 s_lengthModeMap.set(SVGNames::dyAttr, LengthModeHeight); 401 s_lengthModeMap.set(SVGNames::fxAttr, LengthModeWidth); 402 s_lengthModeMap.set(SVGNames::fyAttr, LengthModeHeight); 403 s_lengthModeMap.set(SVGNames::rAttr, LengthModeOther); 404 s_lengthModeMap.set(SVGNames::widthAttr, LengthModeWidth); 405 s_lengthModeMap.set(SVGNames::heightAttr, LengthModeHeight); 406 s_lengthModeMap.set(SVGNames::x1Attr, LengthModeWidth); 407 s_lengthModeMap.set(SVGNames::x2Attr, LengthModeWidth); 408 s_lengthModeMap.set(SVGNames::y1Attr, LengthModeHeight); 409 s_lengthModeMap.set(SVGNames::y2Attr, LengthModeHeight); 410 s_lengthModeMap.set(SVGNames::refXAttr, LengthModeWidth); 411 s_lengthModeMap.set(SVGNames::refYAttr, LengthModeHeight); 412 s_lengthModeMap.set(SVGNames::markerWidthAttr, LengthModeWidth); 413 s_lengthModeMap.set(SVGNames::markerHeightAttr, LengthModeHeight); 414 s_lengthModeMap.set(SVGNames::textLengthAttr, LengthModeWidth); 415 s_lengthModeMap.set(SVGNames::startOffsetAttr, LengthModeWidth); 416 } 417 418 if (s_lengthModeMap.contains(attrName)) 419 return s_lengthModeMap.get(attrName); 420 421 return LengthModeOther; 422 } 423 424 } 425