--- /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 <lypanov@kde.org>
+ 2006, 2007 Rob Buis <buis@kde.org>
+ 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 <wtf/ASCIICType.h>
+
+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 <typename FloatType> 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<FloatType>(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<FloatType>(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<String>& 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<String>& 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<String> parseDelimitedString(const String& input, const char seperator)
+{
+ Vector<String> 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)