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