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