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