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