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