00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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 == ')') {
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
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)
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)
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
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
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)