Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2007 Eric Seidel <eric (at) webkit.org>
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Library General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Library General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Library General Public License
     17  * along with this library; see the file COPYING.LIB.  If not, write to
     18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  * Boston, MA 02110-1301, USA.
     20  */
     21 
     22 #include "config.h"
     23 
     24 #include "core/svg/SVGTransformable.h"
     25 
     26 #include "core/platform/graphics/transforms/AffineTransform.h"
     27 #include "core/svg/SVGParserUtilities.h"
     28 #include "core/svg/SVGTransformList.h"
     29 
     30 namespace WebCore {
     31 
     32 template<typename CharType>
     33 static int parseTransformParamList(const CharType*& ptr, const CharType* end, float* values, int required, int optional)
     34 {
     35     int optionalParams = 0, requiredParams = 0;
     36 
     37     if (!skipOptionalSVGSpaces(ptr, end) || *ptr != '(')
     38         return -1;
     39 
     40     ptr++;
     41 
     42     skipOptionalSVGSpaces(ptr, end);
     43 
     44     while (requiredParams < required) {
     45         if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false))
     46             return -1;
     47         requiredParams++;
     48         if (requiredParams < required)
     49             skipOptionalSVGSpacesOrDelimiter(ptr, end);
     50     }
     51     if (!skipOptionalSVGSpaces(ptr, end))
     52         return -1;
     53 
     54     bool delimParsed = skipOptionalSVGSpacesOrDelimiter(ptr, end);
     55 
     56     if (ptr >= end)
     57         return -1;
     58 
     59     if (*ptr == ')') { // skip optionals
     60         ptr++;
     61         if (delimParsed)
     62             return -1;
     63     } else {
     64         while (optionalParams < optional) {
     65             if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false))
     66                 return -1;
     67             optionalParams++;
     68             if (optionalParams < optional)
     69                 skipOptionalSVGSpacesOrDelimiter(ptr, end);
     70         }
     71 
     72         if (!skipOptionalSVGSpaces(ptr, end))
     73             return -1;
     74 
     75         delimParsed = skipOptionalSVGSpacesOrDelimiter(ptr, end);
     76 
     77         if (ptr >= end || *ptr != ')' || delimParsed)
     78             return -1;
     79         ptr++;
     80     }
     81 
     82     return requiredParams + optionalParams;
     83 }
     84 
     85 // These should be kept in sync with enum SVGTransformType
     86 static const int requiredValuesForType[] =  {0, 6, 1, 1, 1, 1, 1};
     87 static const int optionalValuesForType[] =  {0, 0, 1, 1, 2, 0, 0};
     88 
     89 // This destructor is needed in order to link correctly with Intel ICC.
     90 SVGTransformable::~SVGTransformable()
     91 {
     92 }
     93 
     94 template<typename CharType>
     95 static bool parseTransformValueInternal(unsigned type, const CharType*& ptr, const CharType* end, SVGTransform& transform)
     96 {
     97     if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN)
     98         return false;
     99 
    100     int valueCount = 0;
    101     float values[] = {0, 0, 0, 0, 0, 0};
    102     if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0)
    103         return false;
    104 
    105     switch (type) {
    106     case SVGTransform::SVG_TRANSFORM_SKEWX:
    107         transform.setSkewX(values[0]);
    108         break;
    109     case SVGTransform::SVG_TRANSFORM_SKEWY:
    110         transform.setSkewY(values[0]);
    111         break;
    112     case SVGTransform::SVG_TRANSFORM_SCALE:
    113         if (valueCount == 1) // Spec: if only one param given, assume uniform scaling
    114             transform.setScale(values[0], values[0]);
    115         else
    116             transform.setScale(values[0], values[1]);
    117         break;
    118     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
    119         if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0
    120             transform.setTranslate(values[0], 0);
    121         else
    122             transform.setTranslate(values[0], values[1]);
    123         break;
    124     case SVGTransform::SVG_TRANSFORM_ROTATE:
    125         if (valueCount == 1)
    126             transform.setRotate(values[0], 0, 0);
    127         else
    128             transform.setRotate(values[0], values[1], values[2]);
    129         break;
    130     case SVGTransform::SVG_TRANSFORM_MATRIX:
    131         transform.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5]));
    132         break;
    133     }
    134 
    135     return true;
    136 }
    137 
    138 bool SVGTransformable::parseTransformValue(unsigned type, const LChar*& ptr, const LChar* end, SVGTransform& transform)
    139 {
    140     return parseTransformValueInternal(type, ptr, end, transform);
    141 }
    142 
    143 bool SVGTransformable::parseTransformValue(unsigned type, const UChar*& ptr, const UChar* end, SVGTransform& transform)
    144 {
    145     return parseTransformValueInternal(type, ptr, end, transform);
    146 }
    147 
    148 static const LChar skewXDesc[] =  {'s', 'k', 'e', 'w', 'X'};
    149 static const LChar skewYDesc[] =  {'s', 'k', 'e', 'w', 'Y'};
    150 static const LChar scaleDesc[] =  {'s', 'c', 'a', 'l', 'e'};
    151 static const LChar translateDesc[] =  {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'};
    152 static const LChar rotateDesc[] =  {'r', 'o', 't', 'a', 't', 'e'};
    153 static const LChar matrixDesc[] =  {'m', 'a', 't', 'r', 'i', 'x'};
    154 
    155 template<typename CharType>
    156 static inline bool parseAndSkipType(const CharType*& ptr, const CharType* end, unsigned short& type)
    157 {
    158     if (ptr >= end)
    159         return false;
    160 
    161     if (*ptr == 's') {
    162         if (skipString(ptr, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc)))
    163             type = SVGTransform::SVG_TRANSFORM_SKEWX;
    164         else if (skipString(ptr, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc)))
    165             type = SVGTransform::SVG_TRANSFORM_SKEWY;
    166         else if (skipString(ptr, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc)))
    167             type = SVGTransform::SVG_TRANSFORM_SCALE;
    168         else
    169             return false;
    170     } else if (skipString(ptr, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc)))
    171         type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
    172     else if (skipString(ptr, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc)))
    173         type = SVGTransform::SVG_TRANSFORM_ROTATE;
    174     else if (skipString(ptr, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc)))
    175         type = SVGTransform::SVG_TRANSFORM_MATRIX;
    176     else
    177         return false;
    178 
    179     return true;
    180 }
    181 
    182 SVGTransform::SVGTransformType SVGTransformable::parseTransformType(const String& string)
    183 {
    184     if (string.isEmpty())
    185         return SVGTransform::SVG_TRANSFORM_UNKNOWN;
    186     unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
    187     if (string.is8Bit()) {
    188         const LChar* ptr = string.characters8();
    189         const LChar* end = ptr + string.length();
    190         parseAndSkipType(ptr, end, type);
    191     } else {
    192         const UChar* ptr = string.characters16();
    193         const UChar* end = ptr + string.length();
    194         parseAndSkipType(ptr, end, type);
    195     }
    196     return static_cast<SVGTransform::SVGTransformType>(type);
    197 }
    198 
    199 template<typename CharType>
    200 bool SVGTransformable::parseTransformAttributeInternal(SVGTransformList& list, const CharType*& ptr, const CharType* end, TransformParsingMode mode)
    201 {
    202     if (mode == ClearList)
    203         list.clear();
    204 
    205     bool delimParsed = false;
    206     while (ptr < end) {
    207         delimParsed = false;
    208         unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
    209         skipOptionalSVGSpaces(ptr, end);
    210 
    211         if (!parseAndSkipType(ptr, end, type))
    212             return false;
    213 
    214         SVGTransform transform;
    215         if (!parseTransformValue(type, ptr, end, transform))
    216             return false;
    217 
    218         list.append(transform);
    219         skipOptionalSVGSpaces(ptr, end);
    220         if (ptr < end && *ptr == ',') {
    221             delimParsed = true;
    222             ++ptr;
    223         }
    224         skipOptionalSVGSpaces(ptr, end);
    225     }
    226 
    227     return !delimParsed;
    228 }
    229 
    230 bool SVGTransformable::parseTransformAttribute(SVGTransformList& list, const LChar*& ptr, const LChar* end, TransformParsingMode mode)
    231 {
    232     return parseTransformAttributeInternal(list, ptr, end, mode);
    233 }
    234 
    235 bool SVGTransformable::parseTransformAttribute(SVGTransformList& list, const UChar*& ptr, const UChar* end, TransformParsingMode mode)
    236 {
    237     return parseTransformAttributeInternal(list, ptr, end, mode);
    238 }
    239 
    240 }
    241