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)