1 /* 2 * Copyright (C) 2002, 2003 The Karbon Developers 3 * Copyright (C) 2006 Alexander Kellett <lypanov (at) kde.org> 4 * Copyright (C) 2006, 2007 Rob Buis <buis (at) kde.org> 5 * Copyright (C) 2007, 2009, 2013 Apple Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23 #include "config.h" 24 #include "core/svg/SVGParserUtilities.h" 25 26 #include "core/dom/Document.h" 27 #include "core/svg/SVGPointList.h" 28 #include "platform/geometry/FloatRect.h" 29 #include "platform/transforms/AffineTransform.h" 30 #include "wtf/ASCIICType.h" 31 #include <limits> 32 33 namespace WebCore { 34 35 template <typename FloatType> 36 static inline bool isValidRange(const FloatType& x) 37 { 38 static const FloatType max = std::numeric_limits<FloatType>::max(); 39 return x >= -max && x <= max; 40 } 41 42 // We use this generic parseNumber function to allow the Path parsing code to work 43 // at a higher precision internally, without any unnecessary runtime cost or code 44 // complexity. 45 template <typename CharType, typename FloatType> 46 static bool genericParseNumber(const CharType*& ptr, const CharType* end, FloatType& number, WhitespaceMode mode) 47 { 48 FloatType integer, decimal, frac, exponent; 49 int sign, expsign; 50 const CharType* start = ptr; 51 52 exponent = 0; 53 integer = 0; 54 frac = 1; 55 decimal = 0; 56 sign = 1; 57 expsign = 1; 58 59 if (mode & AllowLeadingWhitespace) 60 skipOptionalSVGSpaces(ptr, end); 61 62 // read the sign 63 if (ptr < end && *ptr == '+') 64 ptr++; 65 else if (ptr < end && *ptr == '-') { 66 ptr++; 67 sign = -1; 68 } 69 70 if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.')) 71 // The first character of a number must be one of [0-9+-.] 72 return false; 73 74 // read the integer part, build right-to-left 75 const CharType* ptrStartIntPart = ptr; 76 while (ptr < end && *ptr >= '0' && *ptr <= '9') 77 ++ptr; // Advance to first non-digit. 78 79 if (ptr != ptrStartIntPart) { 80 const CharType* ptrScanIntPart = ptr - 1; 81 FloatType multiplier = 1; 82 while (ptrScanIntPart >= ptrStartIntPart) { 83 integer += multiplier * static_cast<FloatType>(*(ptrScanIntPart--) - '0'); 84 multiplier *= 10; 85 } 86 // Bail out early if this overflows. 87 if (!isValidRange(integer)) 88 return false; 89 } 90 91 if (ptr < end && *ptr == '.') { // read the decimals 92 ptr++; 93 94 // There must be a least one digit following the . 95 if (ptr >= end || *ptr < '0' || *ptr > '9') 96 return false; 97 98 while (ptr < end && *ptr >= '0' && *ptr <= '9') 99 decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1)); 100 } 101 102 // read the exponent part 103 if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') 104 && (ptr[1] != 'x' && ptr[1] != 'm')) { 105 ptr++; 106 107 // read the sign of the exponent 108 if (*ptr == '+') 109 ptr++; 110 else if (*ptr == '-') { 111 ptr++; 112 expsign = -1; 113 } 114 115 // There must be an exponent 116 if (ptr >= end || *ptr < '0' || *ptr > '9') 117 return false; 118 119 while (ptr < end && *ptr >= '0' && *ptr <= '9') { 120 exponent *= static_cast<FloatType>(10); 121 exponent += *ptr - '0'; 122 ptr++; 123 } 124 // Make sure exponent is valid. 125 if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent) 126 return false; 127 } 128 129 number = integer + decimal; 130 number *= sign; 131 132 if (exponent) 133 number *= static_cast<FloatType>(pow(10.0, expsign * static_cast<int>(exponent))); 134 135 // Don't return Infinity() or NaN(). 136 if (!isValidRange(number)) 137 return false; 138 139 if (start == ptr) 140 return false; 141 142 if (mode & AllowTrailingWhitespace) 143 skipOptionalSVGSpacesOrDelimiter(ptr, end); 144 145 return true; 146 } 147 148 template <typename CharType> 149 bool parseSVGNumber(CharType* begin, size_t length, double& number) 150 { 151 const CharType* ptr = begin; 152 const CharType* end = ptr + length; 153 return genericParseNumber(ptr, end, number, AllowLeadingAndTrailingWhitespace); 154 } 155 156 // Explicitly instantiate the two flavors of parseSVGNumber() to satisfy external callers 157 template bool parseSVGNumber(LChar* begin, size_t length, double&); 158 template bool parseSVGNumber(UChar* begin, size_t length, double&); 159 160 bool parseNumber(const LChar*& ptr, const LChar* end, float& number, WhitespaceMode mode) 161 { 162 return genericParseNumber(ptr, end, number, mode); 163 } 164 165 bool parseNumber(const UChar*& ptr, const UChar* end, float& number, WhitespaceMode mode) 166 { 167 return genericParseNumber(ptr, end, number, mode); 168 } 169 170 // only used to parse largeArcFlag and sweepFlag which must be a "0" or "1" 171 // and might not have any whitespace/comma after it 172 template <typename CharType> 173 bool genericParseArcFlag(const CharType*& ptr, const CharType* end, bool& flag) 174 { 175 if (ptr >= end) 176 return false; 177 const CharType flagChar = *ptr++; 178 if (flagChar == '0') 179 flag = false; 180 else if (flagChar == '1') 181 flag = true; 182 else 183 return false; 184 185 skipOptionalSVGSpacesOrDelimiter(ptr, end); 186 187 return true; 188 } 189 190 bool parseArcFlag(const LChar*& ptr, const LChar* end, bool& flag) 191 { 192 return genericParseArcFlag(ptr, end, flag); 193 } 194 195 bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag) 196 { 197 return genericParseArcFlag(ptr, end, flag); 198 } 199 200 template<typename CharType> 201 static bool genericParseNumberOptionalNumber(const CharType*& ptr, const CharType* end, float& x, float& y) 202 { 203 if (!parseNumber(ptr, end, x)) 204 return false; 205 206 if (ptr == end) 207 y = x; 208 else if (!parseNumber(ptr, end, y, AllowLeadingAndTrailingWhitespace)) 209 return false; 210 211 return ptr == end; 212 } 213 214 bool parseNumberOptionalNumber(const String& string, float& x, float& y) 215 { 216 if (string.isEmpty()) 217 return false; 218 219 if (string.is8Bit()) { 220 const LChar* ptr = string.characters8(); 221 const LChar* end = ptr + string.length(); 222 return genericParseNumberOptionalNumber(ptr, end, x, y); 223 } 224 const UChar* ptr = string.characters16(); 225 const UChar* end = ptr + string.length(); 226 return genericParseNumberOptionalNumber(ptr, end, x, y); 227 } 228 229 template<typename CharType> 230 bool genericParseNumberOrPercentage(const CharType*& ptr, const CharType* end, float& number) 231 { 232 if (genericParseNumber(ptr, end, number, AllowLeadingWhitespace)) { 233 if (ptr == end) 234 return true; 235 236 bool isPercentage = (*ptr == '%'); 237 if (isPercentage) 238 ptr++; 239 240 skipOptionalSVGSpaces(ptr, end); 241 242 if (isPercentage) 243 number /= 100.f; 244 245 return ptr == end; 246 } 247 248 return false; 249 } 250 251 bool parseNumberOrPercentage(const String& string, float& number) 252 { 253 if (string.isEmpty()) 254 return false; 255 256 if (string.is8Bit()) { 257 const LChar* ptr = string.characters8(); 258 const LChar* end = ptr + string.length(); 259 return genericParseNumberOrPercentage(ptr, end, number); 260 } 261 const UChar* ptr = string.characters16(); 262 const UChar* end = ptr + string.length(); 263 return genericParseNumberOrPercentage(ptr, end, number); 264 } 265 266 template<typename CharType> 267 static bool parseGlyphName(const CharType*& ptr, const CharType* end, HashSet<String>& values) 268 { 269 skipOptionalSVGSpaces(ptr, end); 270 271 while (ptr < end) { 272 // Leading and trailing white space, and white space before and after separators, will be ignored. 273 const CharType* inputStart = ptr; 274 while (ptr < end && *ptr != ',') 275 ++ptr; 276 277 if (ptr == inputStart) 278 break; 279 280 // walk backwards from the ; to ignore any whitespace 281 const CharType* inputEnd = ptr - 1; 282 while (inputStart < inputEnd && isHTMLSpace<CharType>(*inputEnd)) 283 --inputEnd; 284 285 values.add(String(inputStart, inputEnd - inputStart + 1)); 286 skipOptionalSVGSpacesOrDelimiter(ptr, end, ','); 287 } 288 289 return true; 290 } 291 292 bool parseGlyphName(const String& input, HashSet<String>& values) 293 { 294 // FIXME: Parsing error detection is missing. 295 values.clear(); 296 if (input.isEmpty()) 297 return true; 298 if (input.is8Bit()) { 299 const LChar* ptr = input.characters8(); 300 const LChar* end = ptr + input.length(); 301 return parseGlyphName(ptr, end, values); 302 } 303 const UChar* ptr = input.characters16(); 304 const UChar* end = ptr + input.length(); 305 return parseGlyphName(ptr, end, values); 306 } 307 308 template<typename CharType> 309 static bool parseUnicodeRange(const CharType* characters, unsigned length, UnicodeRange& range) 310 { 311 if (length < 2 || characters[0] != 'U' || characters[1] != '+') 312 return false; 313 314 // Parse the starting hex number (or its prefix). 315 unsigned startRange = 0; 316 unsigned startLength = 0; 317 318 const CharType* ptr = characters + 2; 319 const CharType* end = characters + length; 320 while (ptr < end) { 321 if (!isASCIIHexDigit(*ptr)) 322 break; 323 ++startLength; 324 if (startLength > 6) 325 return false; 326 startRange = (startRange << 4) | toASCIIHexValue(*ptr); 327 ++ptr; 328 } 329 330 // Handle the case of ranges separated by "-" sign. 331 if (2 + startLength < length && *ptr == '-') { 332 if (!startLength) 333 return false; 334 335 // Parse the ending hex number (or its prefix). 336 unsigned endRange = 0; 337 unsigned endLength = 0; 338 ++ptr; 339 while (ptr < end) { 340 if (!isASCIIHexDigit(*ptr)) 341 break; 342 ++endLength; 343 if (endLength > 6) 344 return false; 345 endRange = (endRange << 4) | toASCIIHexValue(*ptr); 346 ++ptr; 347 } 348 349 if (!endLength) 350 return false; 351 352 range.first = startRange; 353 range.second = endRange; 354 return true; 355 } 356 357 // Handle the case of a number with some optional trailing question marks. 358 unsigned endRange = startRange; 359 while (ptr < end) { 360 if (*ptr != '?') 361 break; 362 ++startLength; 363 if (startLength > 6) 364 return false; 365 startRange <<= 4; 366 endRange = (endRange << 4) | 0xF; 367 ++ptr; 368 } 369 370 if (!startLength) 371 return false; 372 373 range.first = startRange; 374 range.second = endRange; 375 return true; 376 } 377 378 template<typename CharType> 379 static bool genericParseKerningUnicodeString(const CharType*& ptr, const CharType* end, UnicodeRanges& rangeList, HashSet<String>& stringList) 380 { 381 while (ptr < end) { 382 const CharType* inputStart = ptr; 383 while (ptr < end && *ptr != ',') 384 ++ptr; 385 386 if (ptr == inputStart) 387 break; 388 389 // Try to parse unicode range first 390 UnicodeRange range; 391 if (parseUnicodeRange(inputStart, ptr - inputStart, range)) 392 rangeList.append(range); 393 else 394 stringList.add(String(inputStart, ptr - inputStart)); 395 ++ptr; 396 } 397 398 return true; 399 } 400 401 bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet<String>& stringList) 402 { 403 // FIXME: Parsing error detection is missing. 404 if (input.isEmpty()) 405 return true; 406 if (input.is8Bit()) { 407 const LChar* ptr = input.characters8(); 408 const LChar* end = ptr + input.length(); 409 return genericParseKerningUnicodeString(ptr, end, rangeList, stringList); 410 } 411 const UChar* ptr = input.characters16(); 412 const UChar* end = ptr + input.length(); 413 return genericParseKerningUnicodeString(ptr, end, rangeList, stringList); 414 } 415 416 template<typename CharType> 417 static Vector<String> genericParseDelimitedString(const CharType*& ptr, const CharType* end, const char seperator) 418 { 419 Vector<String> values; 420 421 skipOptionalSVGSpaces(ptr, end); 422 423 while (ptr < end) { 424 // Leading and trailing white space, and white space before and after semicolon separators, will be ignored. 425 const CharType* inputStart = ptr; 426 while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs 427 ptr++; 428 429 if (ptr == inputStart) 430 break; 431 432 // walk backwards from the ; to ignore any whitespace 433 const CharType* inputEnd = ptr - 1; 434 while (inputStart < inputEnd && isHTMLSpace<CharType>(*inputEnd)) 435 inputEnd--; 436 437 values.append(String(inputStart, inputEnd - inputStart + 1)); 438 skipOptionalSVGSpacesOrDelimiter(ptr, end, seperator); 439 } 440 441 return values; 442 } 443 444 Vector<String> parseDelimitedString(const String& input, const char seperator) 445 { 446 if (input.isEmpty()) 447 return Vector<String>(); 448 if (input.is8Bit()) { 449 const LChar* ptr = input.characters8(); 450 const LChar* end = ptr + input.length(); 451 return genericParseDelimitedString(ptr, end, seperator); 452 } 453 const UChar* ptr = input.characters16(); 454 const UChar* end = ptr + input.length(); 455 return genericParseDelimitedString(ptr, end, seperator); 456 } 457 458 template <typename CharType> 459 bool parseFloatPoint(const CharType*& current, const CharType* end, FloatPoint& point) 460 { 461 float x; 462 float y; 463 if (!parseNumber(current, end, x) 464 || !parseNumber(current, end, y)) 465 return false; 466 point = FloatPoint(x, y); 467 return true; 468 } 469 470 template bool parseFloatPoint(const LChar*& current, const LChar* end, FloatPoint& point1); 471 template bool parseFloatPoint(const UChar*& current, const UChar* end, FloatPoint& point1); 472 473 template <typename CharType> 474 inline bool parseFloatPoint2(const CharType*& current, const CharType* end, FloatPoint& point1, FloatPoint& point2) 475 { 476 float x1; 477 float y1; 478 float x2; 479 float y2; 480 if (!parseNumber(current, end, x1) 481 || !parseNumber(current, end, y1) 482 || !parseNumber(current, end, x2) 483 || !parseNumber(current, end, y2)) 484 return false; 485 point1 = FloatPoint(x1, y1); 486 point2 = FloatPoint(x2, y2); 487 return true; 488 } 489 490 template bool parseFloatPoint2(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2); 491 template bool parseFloatPoint2(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2); 492 493 template <typename CharType> 494 bool parseFloatPoint3(const CharType*& current, const CharType* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3) 495 { 496 float x1; 497 float y1; 498 float x2; 499 float y2; 500 float x3; 501 float y3; 502 if (!parseNumber(current, end, x1) 503 || !parseNumber(current, end, y1) 504 || !parseNumber(current, end, x2) 505 || !parseNumber(current, end, y2) 506 || !parseNumber(current, end, x3) 507 || !parseNumber(current, end, y3)) 508 return false; 509 point1 = FloatPoint(x1, y1); 510 point2 = FloatPoint(x2, y2); 511 point3 = FloatPoint(x3, y3); 512 return true; 513 } 514 515 template bool parseFloatPoint3(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3); 516 template bool parseFloatPoint3(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3); 517 518 static const LChar skewXDesc[] = {'s', 'k', 'e', 'w', 'X'}; 519 static const LChar skewYDesc[] = {'s', 'k', 'e', 'w', 'Y'}; 520 static const LChar scaleDesc[] = {'s', 'c', 'a', 'l', 'e'}; 521 static const LChar translateDesc[] = {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'}; 522 static const LChar rotateDesc[] = {'r', 'o', 't', 'a', 't', 'e'}; 523 static const LChar matrixDesc[] = {'m', 'a', 't', 'r', 'i', 'x'}; 524 525 template<typename CharType> 526 bool parseAndSkipTransformType(const CharType*& ptr, const CharType* end, SVGTransformType& type) 527 { 528 if (ptr >= end) 529 return false; 530 531 if (*ptr == 's') { 532 if (skipString(ptr, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc))) 533 type = SVG_TRANSFORM_SKEWX; 534 else if (skipString(ptr, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc))) 535 type = SVG_TRANSFORM_SKEWY; 536 else if (skipString(ptr, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc))) 537 type = SVG_TRANSFORM_SCALE; 538 else 539 return false; 540 } else if (skipString(ptr, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc))) 541 type = SVG_TRANSFORM_TRANSLATE; 542 else if (skipString(ptr, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc))) 543 type = SVG_TRANSFORM_ROTATE; 544 else if (skipString(ptr, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc))) 545 type = SVG_TRANSFORM_MATRIX; 546 else 547 return false; 548 549 return true; 550 } 551 552 template bool parseAndSkipTransformType(const UChar*& current, const UChar* end, SVGTransformType&); 553 template bool parseAndSkipTransformType(const LChar*& current, const LChar* end, SVGTransformType&); 554 555 SVGTransformType parseTransformType(const String& string) 556 { 557 if (string.isEmpty()) 558 return SVG_TRANSFORM_UNKNOWN; 559 SVGTransformType type = SVG_TRANSFORM_UNKNOWN; 560 if (string.is8Bit()) { 561 const LChar* ptr = string.characters8(); 562 const LChar* end = ptr + string.length(); 563 parseAndSkipTransformType(ptr, end, type); 564 } else { 565 const UChar* ptr = string.characters16(); 566 const UChar* end = ptr + string.length(); 567 parseAndSkipTransformType(ptr, end, type); 568 } 569 return type; 570 } 571 572 } 573