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