diff -r 000000000000 -r 4f2f89ce4247 WebCore/svg/SVGParserUtilities.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/svg/SVGParserUtilities.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,348 @@ +/* + Copyright (C) 2002, 2003 The Karbon Developers + 2006 Alexander Kellett + 2006, 2007 Rob Buis + Copyrigth (C) 2007, 2009 Apple, Inc. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(SVG) +#include "SVGParserUtilities.h" + +#include "Document.h" +#include "ExceptionCode.h" +#include "FloatPoint.h" +#include "PlatformString.h" +#include "SVGPointList.h" +#include + +namespace WebCore { + +/* We use this generic _parseNumber function to allow the Path parsing code to work + * at a higher precision internally, without any unnecessary runtime cost or code + * complexity + */ +template static bool _parseNumber(const UChar*& ptr, const UChar* end, FloatType& number, bool skip) +{ + int integer, exponent; + FloatType decimal, frac; + int sign, expsign; + const UChar* start = ptr; + + exponent = 0; + integer = 0; + frac = 1; + decimal = 0; + sign = 1; + expsign = 1; + + // read the sign + if (ptr < end && *ptr == '+') + ptr++; + else if (ptr < end && *ptr == '-') { + ptr++; + sign = -1; + } + + if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.')) + // The first character of a number must be one of [0-9+-.] + return false; + + // read the integer part + while (ptr < end && *ptr >= '0' && *ptr <= '9') + integer = (integer * 10) + *(ptr++) - '0'; + + if (ptr < end && *ptr == '.') { // read the decimals + ptr++; + + // There must be a least one digit following the . + if (ptr >= end || *ptr < '0' || *ptr > '9') + return false; + + while (ptr < end && *ptr >= '0' && *ptr <= '9') + decimal += (*(ptr++) - '0') * (frac *= static_cast(0.1)); + } + + // read the exponent part + if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') + && (ptr[1] != 'x' && ptr[1] != 'm')) { + ptr++; + + // read the sign of the exponent + if (*ptr == '+') + ptr++; + else if (*ptr == '-') { + ptr++; + expsign = -1; + } + + // There must be an exponent + if (ptr >= end || *ptr < '0' || *ptr > '9') + return false; + + while (ptr < end && *ptr >= '0' && *ptr <= '9') { + exponent *= 10; + exponent += *ptr - '0'; + ptr++; + } + } + + number = integer + decimal; + number *= sign * static_cast(pow(10.0, expsign * exponent)); + + if (start == ptr) + return false; + + if (skip) + skipOptionalSpacesOrDelimiter(ptr, end); + + return true; +} + +bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip) +{ + return _parseNumber(ptr, end, number, skip); +} + +// only used to parse largeArcFlag and sweepFlag which must be a "0" or "1" +// and might not have any whitespace/comma after it +bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag) +{ + const UChar flagChar = *ptr++; + if (flagChar == '0') + flag = false; + else if (flagChar == '1') + flag = true; + else + return false; + + skipOptionalSpacesOrDelimiter(ptr, end); + + return true; +} + +bool parseNumberOptionalNumber(const String& s, float& x, float& y) +{ + if (s.isEmpty()) + return false; + const UChar* cur = s.characters(); + const UChar* end = cur + s.length(); + + if (!parseNumber(cur, end, x)) + return false; + + if (cur == end) + y = x; + else if (!parseNumber(cur, end, y, false)) + return false; + + return cur == end; +} + +bool pointsListFromSVGData(SVGPointList* pointsList, const String& points) +{ + if (points.isEmpty()) + return true; + const UChar* cur = points.characters(); + const UChar* end = cur + points.length(); + + skipOptionalSpaces(cur, end); + + bool delimParsed = false; + while (cur < end) { + delimParsed = false; + float xPos = 0.0f; + if (!parseNumber(cur, end, xPos)) + return false; + + float yPos = 0.0f; + if (!parseNumber(cur, end, yPos, false)) + return false; + + skipOptionalSpaces(cur, end); + + if (cur < end && *cur == ',') { + delimParsed = true; + cur++; + } + skipOptionalSpaces(cur, end); + + ExceptionCode ec = 0; + pointsList->appendItem(FloatPoint(xPos, yPos), ec); + } + return cur == end && !delimParsed; +} + +bool parseGlyphName(const String& input, HashSet& values) +{ + // FIXME: Parsing error detection is missing. + values.clear(); + + const UChar* ptr = input.characters(); + const UChar* end = ptr + input.length(); + skipOptionalSpaces(ptr, end); + + while (ptr < end) { + // Leading and trailing white space, and white space before and after separators, will be ignored. + const UChar* inputStart = ptr; + while (ptr < end && *ptr != ',') + ++ptr; + + if (ptr == inputStart) + break; + + // walk backwards from the ; to ignore any whitespace + const UChar* inputEnd = ptr - 1; + while (inputStart < inputEnd && isWhitespace(*inputEnd)) + --inputEnd; + + values.add(String(inputStart, inputEnd - inputStart + 1)); + skipOptionalSpacesOrDelimiter(ptr, end, ','); + } + + return true; +} + +static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeRange& range) +{ + if (length < 2 || characters[0] != 'U' || characters[1] != '+') + return false; + + // Parse the starting hex number (or its prefix). + unsigned startRange = 0; + unsigned startLength = 0; + + const UChar* ptr = characters + 2; + const UChar* end = characters + length; + while (ptr < end) { + if (!isASCIIHexDigit(*ptr)) + break; + ++startLength; + if (startLength > 6) + return false; + startRange = (startRange << 4) | toASCIIHexValue(*ptr); + ++ptr; + } + + // Handle the case of ranges separated by "-" sign. + if (2 + startLength < length && *ptr == '-') { + if (!startLength) + return false; + + // Parse the ending hex number (or its prefix). + unsigned endRange = 0; + unsigned endLength = 0; + ++ptr; + while (ptr < end) { + if (!isASCIIHexDigit(*ptr)) + break; + ++endLength; + if (endLength > 6) + return false; + endRange = (endRange << 4) | toASCIIHexValue(*ptr); + ++ptr; + } + + if (!endLength) + return false; + + range.first = startRange; + range.second = endRange; + return true; + } + + // Handle the case of a number with some optional trailing question marks. + unsigned endRange = startRange; + while (ptr < end) { + if (*ptr != '?') + break; + ++startLength; + if (startLength > 6) + return false; + startRange <<= 4; + endRange = (endRange << 4) | 0xF; + ++ptr; + } + + if (!startLength) + return false; + + range.first = startRange; + range.second = endRange; + return true; +} + +bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet& stringList) +{ + // FIXME: Parsing error detection is missing. + const UChar* ptr = input.characters(); + const UChar* end = ptr + input.length(); + + while (ptr < end) { + const UChar* inputStart = ptr; + while (ptr < end && *ptr != ',') + ++ptr; + + if (ptr == inputStart) + break; + + // Try to parse unicode range first + UnicodeRange range; + if (parseUnicodeRange(inputStart, ptr - inputStart, range)) + rangeList.append(range); + else + stringList.add(String(inputStart, ptr - inputStart)); + ++ptr; + } + + return true; +} + +Vector parseDelimitedString(const String& input, const char seperator) +{ + Vector values; + + const UChar* ptr = input.characters(); + const UChar* end = ptr + input.length(); + skipOptionalSpaces(ptr, end); + + while (ptr < end) { + // Leading and trailing white space, and white space before and after semicolon separators, will be ignored. + const UChar* inputStart = ptr; + while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs + ptr++; + + if (ptr == inputStart) + break; + + // walk backwards from the ; to ignore any whitespace + const UChar* inputEnd = ptr - 1; + while (inputStart < inputEnd && isWhitespace(*inputEnd)) + inputEnd--; + + values.append(String(inputStart, inputEnd - inputStart + 1)); + skipOptionalSpacesOrDelimiter(ptr, end, seperator); + } + + return values; +} + +} + +#endif // ENABLE(SVG)