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 #if ENABLE(SVG)
     25 #include "SVGTransformable.h"
     26 
     27 #include "AffineTransform.h"
     28 #include "FloatConversion.h"
     29 #include "SVGNames.h"
     30 #include "SVGParserUtilities.h"
     31 #include "SVGStyledElement.h"
     32 #include "SVGTransformList.h"
     33 
     34 namespace WebCore {
     35 
     36 static int parseTransformParamList(const UChar*& ptr, const UChar* end, float* values, int required, int optional)
     37 {
     38     int optionalParams = 0, requiredParams = 0;
     39 
     40     if (!skipOptionalSpaces(ptr, end) || *ptr != '(')
     41         return -1;
     42 
     43     ptr++;
     44 
     45     skipOptionalSpaces(ptr, end);
     46 
     47     while (requiredParams < required) {
     48         if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false))
     49             return -1;
     50         requiredParams++;
     51         if (requiredParams < required)
     52             skipOptionalSpacesOrDelimiter(ptr, end);
     53     }
     54     if (!skipOptionalSpaces(ptr, end))
     55         return -1;
     56 
     57     bool delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
     58 
     59     if (ptr >= end)
     60         return -1;
     61 
     62     if (*ptr == ')') { // skip optionals
     63         ptr++;
     64         if (delimParsed)
     65             return -1;
     66     } else {
     67         while (optionalParams < optional) {
     68             if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false))
     69                 return -1;
     70             optionalParams++;
     71             if (optionalParams < optional)
     72                 skipOptionalSpacesOrDelimiter(ptr, end);
     73         }
     74 
     75         if (!skipOptionalSpaces(ptr, end))
     76             return -1;
     77 
     78         delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
     79 
     80         if (ptr >= end || *ptr != ')' || delimParsed)
     81             return -1;
     82         ptr++;
     83     }
     84 
     85     return requiredParams + optionalParams;
     86 }
     87 
     88 // These should be kept in sync with enum SVGTransformType
     89 static const int requiredValuesForType[] =  {0, 6, 1, 1, 1, 1, 1};
     90 static const int optionalValuesForType[] =  {0, 0, 1, 1, 2, 0, 0};
     91 
     92 // This destructor is needed in order to link correctly with Intel ICC.
     93 SVGTransformable::~SVGTransformable()
     94 {
     95 }
     96 
     97 bool SVGTransformable::parseTransformValue(unsigned type, const UChar*& ptr, const UChar* end, SVGTransform& transform)
     98 {
     99     if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN)
    100         return false;
    101 
    102     int valueCount = 0;
    103     float values[] = {0, 0, 0, 0, 0, 0};
    104     if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0)
    105         return false;
    106 
    107     switch (type) {
    108     case SVGTransform::SVG_TRANSFORM_SKEWX:
    109         transform.setSkewX(values[0]);
    110         break;
    111     case SVGTransform::SVG_TRANSFORM_SKEWY:
    112         transform.setSkewY(values[0]);
    113         break;
    114     case SVGTransform::SVG_TRANSFORM_SCALE:
    115         if (valueCount == 1) // Spec: if only one param given, assume uniform scaling
    116             transform.setScale(values[0], values[0]);
    117         else
    118             transform.setScale(values[0], values[1]);
    119         break;
    120     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
    121         if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0
    122             transform.setTranslate(values[0], 0);
    123         else
    124             transform.setTranslate(values[0], values[1]);
    125         break;
    126     case SVGTransform::SVG_TRANSFORM_ROTATE:
    127         if (valueCount == 1)
    128             transform.setRotate(values[0], 0, 0);
    129         else
    130             transform.setRotate(values[0], values[1], values[2]);
    131         break;
    132     case SVGTransform::SVG_TRANSFORM_MATRIX:
    133         transform.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5]));
    134         break;
    135     }
    136 
    137     return true;
    138 }
    139 
    140 static const UChar skewXDesc[] =  {'s', 'k', 'e', 'w', 'X'};
    141 static const UChar skewYDesc[] =  {'s', 'k', 'e', 'w', 'Y'};
    142 static const UChar scaleDesc[] =  {'s', 'c', 'a', 'l', 'e'};
    143 static const UChar translateDesc[] =  {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'};
    144 static const UChar rotateDesc[] =  {'r', 'o', 't', 'a', 't', 'e'};
    145 static const UChar matrixDesc[] =  {'m', 'a', 't', 'r', 'i', 'x'};
    146 
    147 static inline bool parseAndSkipType(const UChar*& currTransform, const UChar* end, unsigned short& type)
    148 {
    149     if (currTransform >= end)
    150         return false;
    151 
    152     if (*currTransform == 's') {
    153         if (skipString(currTransform, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc)))
    154             type = SVGTransform::SVG_TRANSFORM_SKEWX;
    155         else if (skipString(currTransform, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc)))
    156             type = SVGTransform::SVG_TRANSFORM_SKEWY;
    157         else if (skipString(currTransform, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc)))
    158             type = SVGTransform::SVG_TRANSFORM_SCALE;
    159         else
    160             return false;
    161     } else if (skipString(currTransform, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc)))
    162         type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
    163     else if (skipString(currTransform, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc)))
    164         type = SVGTransform::SVG_TRANSFORM_ROTATE;
    165     else if (skipString(currTransform, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc)))
    166         type = SVGTransform::SVG_TRANSFORM_MATRIX;
    167     else
    168         return false;
    169 
    170     return true;
    171 }
    172 
    173 bool SVGTransformable::parseTransformAttribute(SVGTransformList& list, const AtomicString& transform)
    174 {
    175     const UChar* start = transform.characters();
    176     return parseTransformAttribute(list, start, start + transform.length());
    177 }
    178 
    179 bool SVGTransformable::parseTransformAttribute(SVGTransformList& list, const UChar*& currTransform, const UChar* end, TransformParsingMode mode)
    180 {
    181     if (mode == ClearList)
    182         list.clear();
    183 
    184     bool delimParsed = false;
    185     while (currTransform < end) {
    186         delimParsed = false;
    187         unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
    188         skipOptionalSpaces(currTransform, end);
    189 
    190         if (!parseAndSkipType(currTransform, end, type))
    191             return false;
    192 
    193         SVGTransform transform;
    194         if (!parseTransformValue(type, currTransform, end, transform))
    195             return false;
    196 
    197         list.append(transform);
    198         skipOptionalSpaces(currTransform, end);
    199         if (currTransform < end && *currTransform == ',') {
    200             delimParsed = true;
    201             ++currTransform;
    202         }
    203         skipOptionalSpaces(currTransform, end);
    204     }
    205 
    206     return !delimParsed;
    207 }
    208 
    209 bool SVGTransformable::isKnownAttribute(const QualifiedName& attrName)
    210 {
    211     return attrName == SVGNames::transformAttr;
    212 }
    213 
    214 }
    215 
    216 #endif // ENABLE(SVG)
    217