1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/*
2dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2002, 2003 The Karbon Developers
3dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
4dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2006, 2007 Rob Buis <buis@kde.org>
5dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
6dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch *
7dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * This library is free software; you can redistribute it and/or
8dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * modify it under the terms of the GNU Library General Public
9dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * License as published by the Free Software Foundation; either
10dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * version 2 of the License, or (at your option) any later version.
11dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch *
12dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * This library is distributed in the hope that it will be useful,
13dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * but WITHOUT ANY WARRANTY; without even the implied warranty of
14dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Library General Public License for more details.
16dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch *
17dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * You should have received a copy of the GNU Library General Public License
18dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * along with this library; see the file COPYING.LIB.  If not, write to
19dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch * Boston, MA 02110-1301, USA.
21dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch */
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
24967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if ENABLE(SVG)
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SVGParserUtilities.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
28967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#include "Document.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FloatPoint.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SVGPointList.h"
31f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
32f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include <limits>
3321939df44de1705786c545cd1bf519d47250322dBen Murdoch#include <wtf/ASCIICType.h>
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
374576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangtemplate <typename FloatType> static inline bool isValidRange(const FloatType& x)
384576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang{
394576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    static const FloatType max = std::numeric_limits<FloatType>::max();
404576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return x >= -max && x <= max;
414576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang}
424576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
435ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen// We use this generic parseNumber function to allow the Path parsing code to work
445ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen// at a higher precision internally, without any unnecessary runtime cost or code
455ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen// complexity.
465ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsentemplate <typename FloatType> static bool genericParseNumber(const UChar*& ptr, const UChar* end, FloatType& number, bool skip)
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
484576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    FloatType integer, decimal, frac, exponent;
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int sign, expsign;
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* start = ptr;
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    exponent = 0;
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    integer = 0;
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    frac = 1;
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    decimal = 0;
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    sign = 1;
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    expsign = 1;
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // read the sign
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (ptr < end && *ptr == '+')
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ptr++;
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else if (ptr < end && *ptr == '-') {
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ptr++;
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        sign = -1;
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.'))
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The first character of a number must be one of [0-9+-.]
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
71db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    // read the integer part, build right-to-left
72db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    const UChar* ptrStartIntPart = ptr;
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (ptr < end && *ptr >= '0' && *ptr <= '9')
74db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        ++ptr; // Advance to first non-digit.
75db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
76db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (ptr != ptrStartIntPart) {
77db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        const UChar* ptrScanIntPart = ptr - 1;
78db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        FloatType multiplier = 1;
79db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        while (ptrScanIntPart >= ptrStartIntPart) {
80db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            integer += multiplier * static_cast<FloatType>(*(ptrScanIntPart--) - '0');
81db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            multiplier *= 10;
82db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        }
834576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        // Bail out early if this overflows.
844576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        if (!isValidRange(integer))
854576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang            return false;
86db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    }
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (ptr < end && *ptr == '.') { // read the decimals
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ptr++;
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // There must be a least one digit following the .
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (ptr >= end || *ptr < '0' || *ptr > '9')
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (ptr < end && *ptr >= '0' && *ptr <= '9')
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1));
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // read the exponent part
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E')
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && (ptr[1] != 'x' && ptr[1] != 'm')) {
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ptr++;
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // read the sign of the exponent
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (*ptr == '+')
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ptr++;
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else if (*ptr == '-') {
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ptr++;
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            expsign = -1;
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // There must be an exponent
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (ptr >= end || *ptr < '0' || *ptr > '9')
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (ptr < end && *ptr >= '0' && *ptr <= '9') {
1174576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang            exponent *= static_cast<FloatType>(10);
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            exponent += *ptr - '0';
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ptr++;
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1214576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        // Make sure exponent is valid.
1224576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent)
1234576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang            return false;
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    number = integer + decimal;
127bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    number *= sign;
128bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
129bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    if (exponent)
1304576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        number *= static_cast<FloatType>(pow(10.0, expsign * static_cast<int>(exponent)));
1314576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
1324576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    // Don't return Infinity() or NaN().
1334576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    if (!isValidRange(number))
1344576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return false;
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (start == ptr)
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (skip)
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        skipOptionalSpacesOrDelimiter(ptr, end);
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip)
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1475ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    return genericParseNumber(ptr, end, number, skip);
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// only used to parse largeArcFlag and sweepFlag which must be a "0" or "1"
151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// and might not have any whitespace/comma after it
152967717af5423377c967781471ee106e2bb4e11c8Ben Murdochbool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag)
153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const UChar flagChar = *ptr++;
155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (flagChar == '0')
156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        flag = false;
157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    else if (flagChar == '1')
158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        flag = true;
159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    else
160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return false;
161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    skipOptionalSpacesOrDelimiter(ptr, end);
163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return true;
165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool parseNumberOptionalNumber(const String& s, float& x, float& y)
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (s.isEmpty())
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* cur = s.characters();
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* end = cur + s.length();
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!parseNumber(cur, end, x))
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (cur == end)
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        y = x;
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else if (!parseNumber(cur, end, y, false))
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return cur == end;
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
18528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhubool pointsListFromSVGData(SVGPointList& pointsList, const String& points)
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (points.isEmpty())
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return true;
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* cur = points.characters();
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* end = cur + points.length();
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    skipOptionalSpaces(cur, end);
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool delimParsed = false;
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (cur < end) {
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        delimParsed = false;
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        float xPos = 0.0f;
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!parseNumber(cur, end, xPos))
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project           return false;
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        float yPos = 0.0f;
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!parseNumber(cur, end, yPos, false))
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        skipOptionalSpaces(cur, end);
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (cur < end && *cur == ',') {
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            delimParsed = true;
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            cur++;
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        skipOptionalSpaces(cur, end);
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
21328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        pointsList.append(FloatPoint(xPos, yPos));
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return cur == end && !delimParsed;
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2186c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenbool parseGlyphName(const String& input, HashSet<String>& values)
21921939df44de1705786c545cd1bf519d47250322dBen Murdoch{
2206c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // FIXME: Parsing error detection is missing.
22121939df44de1705786c545cd1bf519d47250322dBen Murdoch    values.clear();
22221939df44de1705786c545cd1bf519d47250322dBen Murdoch
22321939df44de1705786c545cd1bf519d47250322dBen Murdoch    const UChar* ptr = input.characters();
22421939df44de1705786c545cd1bf519d47250322dBen Murdoch    const UChar* end = ptr + input.length();
22521939df44de1705786c545cd1bf519d47250322dBen Murdoch    skipOptionalSpaces(ptr, end);
22621939df44de1705786c545cd1bf519d47250322dBen Murdoch
22721939df44de1705786c545cd1bf519d47250322dBen Murdoch    while (ptr < end) {
22821939df44de1705786c545cd1bf519d47250322dBen Murdoch        // Leading and trailing white space, and white space before and after separators, will be ignored.
22921939df44de1705786c545cd1bf519d47250322dBen Murdoch        const UChar* inputStart = ptr;
23021939df44de1705786c545cd1bf519d47250322dBen Murdoch        while (ptr < end && *ptr != ',')
23121939df44de1705786c545cd1bf519d47250322dBen Murdoch            ++ptr;
23221939df44de1705786c545cd1bf519d47250322dBen Murdoch
23321939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (ptr == inputStart)
23421939df44de1705786c545cd1bf519d47250322dBen Murdoch            break;
23521939df44de1705786c545cd1bf519d47250322dBen Murdoch
23621939df44de1705786c545cd1bf519d47250322dBen Murdoch        // walk backwards from the ; to ignore any whitespace
23721939df44de1705786c545cd1bf519d47250322dBen Murdoch        const UChar* inputEnd = ptr - 1;
23821939df44de1705786c545cd1bf519d47250322dBen Murdoch        while (inputStart < inputEnd && isWhitespace(*inputEnd))
23921939df44de1705786c545cd1bf519d47250322dBen Murdoch            --inputEnd;
24021939df44de1705786c545cd1bf519d47250322dBen Murdoch
24121939df44de1705786c545cd1bf519d47250322dBen Murdoch        values.add(String(inputStart, inputEnd - inputStart + 1));
24221939df44de1705786c545cd1bf519d47250322dBen Murdoch        skipOptionalSpacesOrDelimiter(ptr, end, ',');
24321939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
2446c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2456c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    return true;
24621939df44de1705786c545cd1bf519d47250322dBen Murdoch}
24721939df44de1705786c545cd1bf519d47250322dBen Murdoch
24821939df44de1705786c545cd1bf519d47250322dBen Murdochstatic bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeRange& range)
24921939df44de1705786c545cd1bf519d47250322dBen Murdoch{
25021939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (length < 2 || characters[0] != 'U' || characters[1] != '+')
25121939df44de1705786c545cd1bf519d47250322dBen Murdoch        return false;
25221939df44de1705786c545cd1bf519d47250322dBen Murdoch
25321939df44de1705786c545cd1bf519d47250322dBen Murdoch    // Parse the starting hex number (or its prefix).
25421939df44de1705786c545cd1bf519d47250322dBen Murdoch    unsigned startRange = 0;
25521939df44de1705786c545cd1bf519d47250322dBen Murdoch    unsigned startLength = 0;
25621939df44de1705786c545cd1bf519d47250322dBen Murdoch
25721939df44de1705786c545cd1bf519d47250322dBen Murdoch    const UChar* ptr = characters + 2;
25821939df44de1705786c545cd1bf519d47250322dBen Murdoch    const UChar* end = characters + length;
25921939df44de1705786c545cd1bf519d47250322dBen Murdoch    while (ptr < end) {
26021939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (!isASCIIHexDigit(*ptr))
26121939df44de1705786c545cd1bf519d47250322dBen Murdoch            break;
26221939df44de1705786c545cd1bf519d47250322dBen Murdoch        ++startLength;
26321939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (startLength > 6)
26421939df44de1705786c545cd1bf519d47250322dBen Murdoch            return false;
26521939df44de1705786c545cd1bf519d47250322dBen Murdoch        startRange = (startRange << 4) | toASCIIHexValue(*ptr);
26621939df44de1705786c545cd1bf519d47250322dBen Murdoch        ++ptr;
26721939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
26821939df44de1705786c545cd1bf519d47250322dBen Murdoch
26921939df44de1705786c545cd1bf519d47250322dBen Murdoch    // Handle the case of ranges separated by "-" sign.
27021939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (2 + startLength < length && *ptr == '-') {
27121939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (!startLength)
27221939df44de1705786c545cd1bf519d47250322dBen Murdoch            return false;
27321939df44de1705786c545cd1bf519d47250322dBen Murdoch
27421939df44de1705786c545cd1bf519d47250322dBen Murdoch        // Parse the ending hex number (or its prefix).
27521939df44de1705786c545cd1bf519d47250322dBen Murdoch        unsigned endRange = 0;
27621939df44de1705786c545cd1bf519d47250322dBen Murdoch        unsigned endLength = 0;
27721939df44de1705786c545cd1bf519d47250322dBen Murdoch        ++ptr;
27821939df44de1705786c545cd1bf519d47250322dBen Murdoch        while (ptr < end) {
27921939df44de1705786c545cd1bf519d47250322dBen Murdoch            if (!isASCIIHexDigit(*ptr))
28021939df44de1705786c545cd1bf519d47250322dBen Murdoch                break;
28121939df44de1705786c545cd1bf519d47250322dBen Murdoch            ++endLength;
28221939df44de1705786c545cd1bf519d47250322dBen Murdoch            if (endLength > 6)
28321939df44de1705786c545cd1bf519d47250322dBen Murdoch                return false;
28421939df44de1705786c545cd1bf519d47250322dBen Murdoch            endRange = (endRange << 4) | toASCIIHexValue(*ptr);
28521939df44de1705786c545cd1bf519d47250322dBen Murdoch            ++ptr;
28621939df44de1705786c545cd1bf519d47250322dBen Murdoch        }
28721939df44de1705786c545cd1bf519d47250322dBen Murdoch
28821939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (!endLength)
28921939df44de1705786c545cd1bf519d47250322dBen Murdoch            return false;
29021939df44de1705786c545cd1bf519d47250322dBen Murdoch
29121939df44de1705786c545cd1bf519d47250322dBen Murdoch        range.first = startRange;
29221939df44de1705786c545cd1bf519d47250322dBen Murdoch        range.second = endRange;
29321939df44de1705786c545cd1bf519d47250322dBen Murdoch        return true;
29421939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
29521939df44de1705786c545cd1bf519d47250322dBen Murdoch
29621939df44de1705786c545cd1bf519d47250322dBen Murdoch    // Handle the case of a number with some optional trailing question marks.
29721939df44de1705786c545cd1bf519d47250322dBen Murdoch    unsigned endRange = startRange;
29821939df44de1705786c545cd1bf519d47250322dBen Murdoch    while (ptr < end) {
29921939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (*ptr != '?')
30021939df44de1705786c545cd1bf519d47250322dBen Murdoch            break;
30121939df44de1705786c545cd1bf519d47250322dBen Murdoch        ++startLength;
30221939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (startLength > 6)
30321939df44de1705786c545cd1bf519d47250322dBen Murdoch            return false;
30421939df44de1705786c545cd1bf519d47250322dBen Murdoch        startRange <<= 4;
30521939df44de1705786c545cd1bf519d47250322dBen Murdoch        endRange = (endRange << 4) | 0xF;
30621939df44de1705786c545cd1bf519d47250322dBen Murdoch        ++ptr;
30721939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
30821939df44de1705786c545cd1bf519d47250322dBen Murdoch
30921939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (!startLength)
31021939df44de1705786c545cd1bf519d47250322dBen Murdoch        return false;
31121939df44de1705786c545cd1bf519d47250322dBen Murdoch
31221939df44de1705786c545cd1bf519d47250322dBen Murdoch    range.first = startRange;
31321939df44de1705786c545cd1bf519d47250322dBen Murdoch    range.second = endRange;
31421939df44de1705786c545cd1bf519d47250322dBen Murdoch    return true;
31521939df44de1705786c545cd1bf519d47250322dBen Murdoch}
31621939df44de1705786c545cd1bf519d47250322dBen Murdoch
3176c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenbool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet<String>& stringList)
31821939df44de1705786c545cd1bf519d47250322dBen Murdoch{
3196c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // FIXME: Parsing error detection is missing.
32021939df44de1705786c545cd1bf519d47250322dBen Murdoch    const UChar* ptr = input.characters();
32121939df44de1705786c545cd1bf519d47250322dBen Murdoch    const UChar* end = ptr + input.length();
32221939df44de1705786c545cd1bf519d47250322dBen Murdoch
32321939df44de1705786c545cd1bf519d47250322dBen Murdoch    while (ptr < end) {
32421939df44de1705786c545cd1bf519d47250322dBen Murdoch        const UChar* inputStart = ptr;
32521939df44de1705786c545cd1bf519d47250322dBen Murdoch        while (ptr < end && *ptr != ',')
32621939df44de1705786c545cd1bf519d47250322dBen Murdoch            ++ptr;
32721939df44de1705786c545cd1bf519d47250322dBen Murdoch
32821939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (ptr == inputStart)
32921939df44de1705786c545cd1bf519d47250322dBen Murdoch            break;
33021939df44de1705786c545cd1bf519d47250322dBen Murdoch
33121939df44de1705786c545cd1bf519d47250322dBen Murdoch        // Try to parse unicode range first
33221939df44de1705786c545cd1bf519d47250322dBen Murdoch        UnicodeRange range;
33321939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (parseUnicodeRange(inputStart, ptr - inputStart, range))
33421939df44de1705786c545cd1bf519d47250322dBen Murdoch            rangeList.append(range);
33521939df44de1705786c545cd1bf519d47250322dBen Murdoch        else
33621939df44de1705786c545cd1bf519d47250322dBen Murdoch            stringList.add(String(inputStart, ptr - inputStart));
33721939df44de1705786c545cd1bf519d47250322dBen Murdoch        ++ptr;
33821939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
3396c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
3406c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    return true;
34121939df44de1705786c545cd1bf519d47250322dBen Murdoch}
34221939df44de1705786c545cd1bf519d47250322dBen Murdoch
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVector<String> parseDelimitedString(const String& input, const char seperator)
3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<String> values;
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* ptr = input.characters();
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UChar* end = ptr + input.length();
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    skipOptionalSpaces(ptr, end);
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (ptr < end) {
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Leading and trailing white space, and white space before and after semicolon separators, will be ignored.
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const UChar* inputStart = ptr;
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ptr++;
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (ptr == inputStart)
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // walk backwards from the ; to ignore any whitespace
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const UChar* inputEnd = ptr - 1;
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (inputStart < inputEnd && isWhitespace(*inputEnd))
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            inputEnd--;
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        values.append(String(inputStart, inputEnd - inputStart + 1));
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        skipOptionalSpacesOrDelimiter(ptr, end, seperator);
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return values;
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif // ENABLE(SVG)
375