File indexing completed on 2024-04-28 15:24:42

0001 /*
0002     Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
0003                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
0004                   2007 Eric Seidel <eric@webkit.org>
0005 
0006     This file is part of the WebKit project
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Library General Public
0010     License as published by the Free Software Foundation; either
0011     version 2 of the License, or (at your option) any later version.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Library General Public License for more details.
0017 
0018     You should have received a copy of the GNU Library General Public License
0019     along with this library; see the file COPYING.LIB.  If not, write to
0020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021     Boston, MA 02110-1301, USA.
0022 */
0023 
0024 #include "Document.h"
0025 
0026 #if ENABLE(SVG)
0027 #include "SVGTransformable.h"
0028 
0029 #include "AffineTransform.h"
0030 #include "FloatConversion.h"
0031 //#include "RegularExpression.h"
0032 #include "SVGNames.h"
0033 #include "SVGParserUtilities.h"
0034 #include "SVGStyledElement.h"
0035 #include "SVGTransformList.h"
0036 
0037 namespace WebCore
0038 {
0039 
0040 SVGTransformable::SVGTransformable() : SVGLocatable()
0041 {
0042 }
0043 
0044 SVGTransformable::~SVGTransformable()
0045 {
0046 }
0047 
0048 AffineTransform SVGTransformable::getCTM(const SVGElement *element) const
0049 {
0050     AffineTransform ctm = SVGLocatable::getCTM(element);
0051     return animatedLocalTransform() * ctm;
0052 }
0053 
0054 AffineTransform SVGTransformable::getScreenCTM(const SVGElement *element) const
0055 {
0056     AffineTransform ctm = SVGLocatable::getScreenCTM(element);
0057     return animatedLocalTransform() * ctm;
0058 }
0059 
0060 int parseTransformParamList(const UChar *&ptr, const UChar *end, float *values, int required, int optional)
0061 {
0062     int optionalParams = 0, requiredParams = 0;
0063 
0064     if (!skipOptionalSpaces(ptr, end) || *ptr != '(') {
0065         return -1;
0066     }
0067 
0068     ptr++;
0069 
0070     skipOptionalSpaces(ptr, end);
0071 
0072     while (requiredParams < required) {
0073         if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false)) {
0074             return -1;
0075         }
0076         requiredParams++;
0077         if (requiredParams < required) {
0078             skipOptionalSpacesOrDelimiter(ptr, end);
0079         }
0080     }
0081     if (!skipOptionalSpaces(ptr, end)) {
0082         return -1;
0083     }
0084 
0085     bool delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
0086 
0087     if (ptr >= end) {
0088         return -1;
0089     }
0090 
0091     if (*ptr == ')') { // skip optionals
0092         ptr++;
0093         if (delimParsed) {
0094             return -1;
0095         }
0096     } else {
0097         while (optionalParams < optional) {
0098             if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false)) {
0099                 return -1;
0100             }
0101             optionalParams++;
0102             if (optionalParams < optional) {
0103                 skipOptionalSpacesOrDelimiter(ptr, end);
0104             }
0105         }
0106 
0107         if (!skipOptionalSpaces(ptr, end)) {
0108             return -1;
0109         }
0110 
0111         delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
0112 
0113         if (ptr >= end || *ptr != ')' || delimParsed) {
0114             return -1;
0115         }
0116         ptr++;
0117     }
0118 
0119     return requiredParams + optionalParams;
0120 }
0121 
0122 // These should be kept in sync with enum SVGTransformType
0123 static const int requiredValuesForType[] =  {0, 6, 1, 1, 1, 1, 1};
0124 static const int optionalValuesForType[] =  {0, 0, 1, 1, 2, 0, 0};
0125 
0126 bool SVGTransformable::parseTransformValue(unsigned type, const UChar *&ptr, const UChar *end, SVGTransform &t)
0127 {
0128     if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN) {
0129         return false;
0130     }
0131 
0132     int valueCount = 0;
0133     float values[] = {0, 0, 0, 0, 0, 0};
0134     if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0) {
0135         return false;
0136     }
0137 
0138     switch (type) {
0139     case SVGTransform::SVG_TRANSFORM_SKEWX:
0140         t.setSkewX(values[0]);
0141         break;
0142     case SVGTransform::SVG_TRANSFORM_SKEWY:
0143         t.setSkewY(values[0]);
0144         break;
0145     case SVGTransform::SVG_TRANSFORM_SCALE:
0146         if (valueCount == 1) { // Spec: if only one param given, assume uniform scaling
0147             t.setScale(values[0], values[0]);
0148         } else {
0149             t.setScale(values[0], values[1]);
0150         }
0151         break;
0152     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
0153         if (valueCount == 1) { // Spec: if only one param given, assume 2nd param to be 0
0154             t.setTranslate(values[0], 0);
0155         } else {
0156             t.setTranslate(values[0], values[1]);
0157         }
0158         break;
0159     case SVGTransform::SVG_TRANSFORM_ROTATE:
0160         if (valueCount == 1) {
0161             t.setRotate(values[0], 0, 0);
0162         } else {
0163             t.setRotate(values[0], values[1], values[2]);
0164         }
0165         break;
0166     case SVGTransform::SVG_TRANSFORM_MATRIX:
0167         t.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5]));
0168         break;
0169     }
0170 
0171     return true;
0172 }
0173 
0174 static const UChar skewXDesc[] =  {'s', 'k', 'e', 'w', 'X'};
0175 static const UChar skewYDesc[] =  {'s', 'k', 'e', 'w', 'Y'};
0176 static const UChar scaleDesc[] =  {'s', 'c', 'a', 'l', 'e'};
0177 static const UChar translateDesc[] =  {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'};
0178 static const UChar rotateDesc[] =  {'r', 'o', 't', 'a', 't', 'e'};
0179 static const UChar matrixDesc[] =  {'m', 'a', 't', 'r', 'i', 'x'};
0180 
0181 // KHTML
0182 /*static inline bool skipString(const UChar*& currTransform, const UChar* end, const UChar* pattern, int len)
0183 {
0184     int i = len;
0185     const UChar* curr = currTransform;
0186     while (i && curr < end) {
0187         if (*curr++ != *pattern++)
0188             return false;
0189         --i;
0190     }
0191     if (i)
0192         return false;
0193     currTransform += len;
0194     return true;
0195 }*/
0196 
0197 static inline bool parseAndSkipType(const UChar *&currTransform, const UChar *end, unsigned short &type)
0198 {
0199     if (currTransform >= end) {
0200         return false;
0201     }
0202 
0203     if (*currTransform == 's') {
0204         if (skipString(currTransform, end, skewXDesc, sizeof(skewXDesc) / sizeof(UChar))) {
0205             type = SVGTransform::SVG_TRANSFORM_SKEWX;
0206         } else if (skipString(currTransform, end, skewYDesc, sizeof(skewYDesc) / sizeof(UChar))) {
0207             type = SVGTransform::SVG_TRANSFORM_SKEWY;
0208         } else if (skipString(currTransform, end, scaleDesc, sizeof(scaleDesc) / sizeof(UChar))) {
0209             type = SVGTransform::SVG_TRANSFORM_SCALE;
0210         } else {
0211             return false;
0212         }
0213     } else if (skipString(currTransform, end, translateDesc, sizeof(translateDesc) / sizeof(UChar))) {
0214         type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
0215     } else if (skipString(currTransform, end, rotateDesc, sizeof(rotateDesc) / sizeof(UChar))) {
0216         type = SVGTransform::SVG_TRANSFORM_ROTATE;
0217     } else if (skipString(currTransform, end, matrixDesc, sizeof(matrixDesc) / sizeof(UChar))) {
0218         type = SVGTransform::SVG_TRANSFORM_MATRIX;
0219     } else {
0220         return false;
0221     }
0222 
0223     return true;
0224 }
0225 
0226 bool SVGTransformable::parseTransformAttribute(SVGTransformList *list, const AtomicString &transform)
0227 {
0228     const UChar *start = transform.characters();
0229     const UChar *end = start + transform.length();
0230     return parseTransformAttribute(list, start, end);
0231 }
0232 
0233 bool SVGTransformable::parseTransformAttribute(SVGTransformList *list, const UChar *&currTransform, const UChar *end)
0234 {
0235     bool delimParsed = false;
0236     while (currTransform < end) {
0237         delimParsed = false;
0238         unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
0239         skipOptionalSpaces(currTransform, end);
0240 
0241         if (!parseAndSkipType(currTransform, end, type)) {
0242             return false;
0243         }
0244 
0245         SVGTransform t;
0246         if (!parseTransformValue(type, currTransform, end, t)) {
0247             return false;
0248         }
0249 
0250         ExceptionCode ec = 0;
0251         list->appendItem(t, ec);
0252         skipOptionalSpaces(currTransform, end);
0253         if (currTransform < end && *currTransform == ',') {
0254             delimParsed = true;
0255             currTransform++;
0256         }
0257         skipOptionalSpaces(currTransform, end);
0258     }
0259 
0260     return !delimParsed;
0261 }
0262 
0263 bool SVGTransformable::isKnownAttribute(const QualifiedName &attrName)
0264 {
0265     return attrName.matches(SVGNames::transformAttr);
0266 }
0267 
0268 }
0269 
0270 #endif // ENABLE(SVG)