KHTML
SVGTransformable.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org> 00003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 00004 2007 Eric Seidel <eric@webkit.org> 00005 00006 This file is part of the WebKit project 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "config.h" 00025 #include "Document.h" 00026 00027 #if ENABLE(SVG) 00028 #include "SVGTransformable.h" 00029 00030 #include "AffineTransform.h" 00031 #include "FloatConversion.h" 00032 //#include "RegularExpression.h" 00033 #include "SVGNames.h" 00034 #include "SVGParserUtilities.h" 00035 #include "SVGStyledElement.h" 00036 #include "SVGTransformList.h" 00037 00038 namespace WebCore { 00039 00040 SVGTransformable::SVGTransformable() : SVGLocatable() 00041 { 00042 } 00043 00044 SVGTransformable::~SVGTransformable() 00045 { 00046 } 00047 00048 AffineTransform SVGTransformable::getCTM(const SVGElement* element) const 00049 { 00050 AffineTransform ctm = SVGLocatable::getCTM(element); 00051 return animatedLocalTransform() * ctm; 00052 } 00053 00054 AffineTransform SVGTransformable::getScreenCTM(const SVGElement* element) const 00055 { 00056 AffineTransform ctm = SVGLocatable::getScreenCTM(element); 00057 return animatedLocalTransform() * ctm; 00058 } 00059 00060 int parseTransformParamList(const UChar*& ptr, const UChar* end, float* values, int required, int optional) 00061 { 00062 int optionalParams = 0, requiredParams = 0; 00063 00064 if (!skipOptionalSpaces(ptr, end) || *ptr != '(') 00065 return -1; 00066 00067 ptr++; 00068 00069 skipOptionalSpaces(ptr, end); 00070 00071 while (requiredParams < required) { 00072 if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false)) 00073 return -1; 00074 requiredParams++; 00075 if (requiredParams < required) 00076 skipOptionalSpacesOrDelimiter(ptr, end); 00077 } 00078 if (!skipOptionalSpaces(ptr, end)) 00079 return -1; 00080 00081 bool delimParsed = skipOptionalSpacesOrDelimiter(ptr, end); 00082 00083 if (ptr >= end) 00084 return -1; 00085 00086 if (*ptr == ')') { // skip optionals 00087 ptr++; 00088 if (delimParsed) 00089 return -1; 00090 } else { 00091 while (optionalParams < optional) { 00092 if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false)) 00093 return -1; 00094 optionalParams++; 00095 if (optionalParams < optional) 00096 skipOptionalSpacesOrDelimiter(ptr, end); 00097 } 00098 00099 if (!skipOptionalSpaces(ptr, end)) 00100 return -1; 00101 00102 delimParsed = skipOptionalSpacesOrDelimiter(ptr, end); 00103 00104 if (ptr >= end || *ptr != ')' || delimParsed) 00105 return -1; 00106 ptr++; 00107 } 00108 00109 return requiredParams + optionalParams; 00110 } 00111 00112 // These should be kept in sync with enum SVGTransformType 00113 static const int requiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1}; 00114 static const int optionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0}; 00115 00116 bool SVGTransformable::parseTransformValue(unsigned type, const UChar*& ptr, const UChar* end, SVGTransform& t) 00117 { 00118 if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN) 00119 return false; 00120 00121 int valueCount = 0; 00122 float values[] = {0, 0, 0, 0, 0, 0}; 00123 if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0) 00124 return false; 00125 00126 switch (type) { 00127 case SVGTransform::SVG_TRANSFORM_SKEWX: 00128 t.setSkewX(values[0]); 00129 break; 00130 case SVGTransform::SVG_TRANSFORM_SKEWY: 00131 t.setSkewY(values[0]); 00132 break; 00133 case SVGTransform::SVG_TRANSFORM_SCALE: 00134 if (valueCount == 1) // Spec: if only one param given, assume uniform scaling 00135 t.setScale(values[0], values[0]); 00136 else 00137 t.setScale(values[0], values[1]); 00138 break; 00139 case SVGTransform::SVG_TRANSFORM_TRANSLATE: 00140 if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0 00141 t.setTranslate(values[0], 0); 00142 else 00143 t.setTranslate(values[0], values[1]); 00144 break; 00145 case SVGTransform::SVG_TRANSFORM_ROTATE: 00146 if (valueCount == 1) 00147 t.setRotate(values[0], 0, 0); 00148 else 00149 t.setRotate(values[0], values[1], values[2]); 00150 break; 00151 case SVGTransform::SVG_TRANSFORM_MATRIX: 00152 t.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5])); 00153 break; 00154 } 00155 00156 return true; 00157 } 00158 00159 static const UChar skewXDesc[] = {'s','k','e','w', 'X'}; 00160 static const UChar skewYDesc[] = {'s','k','e','w', 'Y'}; 00161 static const UChar scaleDesc[] = {'s','c','a','l', 'e'}; 00162 static const UChar translateDesc[] = {'t','r','a','n', 's', 'l', 'a', 't', 'e'}; 00163 static const UChar rotateDesc[] = {'r','o','t','a', 't', 'e'}; 00164 static const UChar matrixDesc[] = {'m','a','t','r', 'i', 'x'}; 00165 00166 // KHTML 00167 /*static inline bool skipString(const UChar*& currTransform, const UChar* end, const UChar* pattern, int len) 00168 { 00169 int i = len; 00170 const UChar* curr = currTransform; 00171 while (i && curr < end) { 00172 if (*curr++ != *pattern++) 00173 return false; 00174 --i; 00175 } 00176 if (i) 00177 return false; 00178 currTransform += len; 00179 return true; 00180 }*/ 00181 00182 static inline bool parseAndSkipType(const UChar*& currTransform, const UChar* end, unsigned short& type) 00183 { 00184 if (currTransform >= end) 00185 return false; 00186 00187 if (*currTransform == 's') { 00188 if (skipString(currTransform, end, skewXDesc, sizeof(skewXDesc) / sizeof(UChar))) 00189 type = SVGTransform::SVG_TRANSFORM_SKEWX; 00190 else if (skipString(currTransform, end, skewYDesc, sizeof(skewYDesc) / sizeof(UChar))) 00191 type = SVGTransform::SVG_TRANSFORM_SKEWY; 00192 else if (skipString(currTransform, end, scaleDesc, sizeof(scaleDesc) / sizeof(UChar))) 00193 type = SVGTransform::SVG_TRANSFORM_SCALE; 00194 else 00195 return false; 00196 } else if (skipString(currTransform, end, translateDesc, sizeof(translateDesc) / sizeof(UChar))) 00197 type = SVGTransform::SVG_TRANSFORM_TRANSLATE; 00198 else if (skipString(currTransform, end, rotateDesc, sizeof(rotateDesc) / sizeof(UChar))) 00199 type = SVGTransform::SVG_TRANSFORM_ROTATE; 00200 else if (skipString(currTransform, end, matrixDesc, sizeof(matrixDesc) / sizeof(UChar))) 00201 type = SVGTransform::SVG_TRANSFORM_MATRIX; 00202 else 00203 return false; 00204 00205 return true; 00206 } 00207 00208 bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const AtomicString& transform) 00209 { 00210 const UChar* start = transform.characters(); 00211 const UChar* end = start + transform.length(); 00212 return parseTransformAttribute(list, start, end); 00213 } 00214 00215 bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const UChar*& currTransform, const UChar* end) 00216 { 00217 bool delimParsed = false; 00218 while (currTransform < end) { 00219 delimParsed = false; 00220 unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN; 00221 skipOptionalSpaces(currTransform, end); 00222 00223 if (!parseAndSkipType(currTransform, end, type)) 00224 return false; 00225 00226 SVGTransform t; 00227 if (!parseTransformValue(type, currTransform, end, t)) 00228 return false; 00229 00230 ExceptionCode ec = 0; 00231 list->appendItem(t, ec); 00232 skipOptionalSpaces(currTransform, end); 00233 if (currTransform < end && *currTransform == ',') { 00234 delimParsed = true; 00235 currTransform++; 00236 } 00237 skipOptionalSpaces(currTransform, end); 00238 } 00239 00240 return !delimParsed; 00241 } 00242 00243 bool SVGTransformable::isKnownAttribute(const QualifiedName& attrName) 00244 { 00245 return attrName.matches(SVGNames::transformAttr); 00246 } 00247 00248 } 00249 00250 #endif // ENABLE(SVG)
KDE 4.6 API Reference