Index: third_party/WebKit/Source/core/svg/SVGTransformList.cpp |
diff --git a/third_party/WebKit/Source/core/svg/SVGTransformList.cpp b/third_party/WebKit/Source/core/svg/SVGTransformList.cpp |
index 10ec3125c7459f9d29adf03d1b64f4aa411e703e..ad281f0b6720f545954effb619f98c7a166c216b 100644 |
--- a/third_party/WebKit/Source/core/svg/SVGTransformList.cpp |
+++ b/third_party/WebKit/Source/core/svg/SVGTransformList.cpp |
@@ -46,9 +46,7 @@ PassRefPtrWillBeRawPtr<SVGTransform> SVGTransformList::consolidate() |
if (!concatenate(matrix)) |
return SVGTransform::create(); |
- RefPtrWillBeRawPtr<SVGTransform> transform = SVGTransform::create(matrix); |
- clear(); |
- return appendItem(transform); |
+ return initialize(SVGTransform::create(matrix)); |
} |
bool SVGTransformList::concatenate(AffineTransform& result) const |
@@ -74,111 +72,122 @@ const LChar rotateDesc[] = {'r', 'o', 't', 'a', 't', 'e'}; |
const LChar matrixDesc[] = {'m', 'a', 't', 'r', 'i', 'x'}; |
template<typename CharType> |
-bool parseAndSkipTransformType(const CharType*& ptr, const CharType* end, SVGTransformType& type) |
+SVGTransformType parseAndSkipTransformType(const CharType*& ptr, const CharType* end) |
{ |
if (ptr >= end) |
- return false; |
+ return SVG_TRANSFORM_UNKNOWN; |
if (*ptr == 's') { |
if (skipString(ptr, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc))) |
- type = SVG_TRANSFORM_SKEWX; |
- else if (skipString(ptr, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc))) |
- type = SVG_TRANSFORM_SKEWY; |
- else if (skipString(ptr, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc))) |
- type = SVG_TRANSFORM_SCALE; |
- else |
- return false; |
- } else if (skipString(ptr, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc))) { |
- type = SVG_TRANSFORM_TRANSLATE; |
- } else if (skipString(ptr, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc))) { |
- type = SVG_TRANSFORM_ROTATE; |
- } else if (skipString(ptr, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc))) { |
- type = SVG_TRANSFORM_MATRIX; |
- } else { |
- return false; |
+ return SVG_TRANSFORM_SKEWX; |
+ if (skipString(ptr, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc))) |
+ return SVG_TRANSFORM_SKEWY; |
+ if (skipString(ptr, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc))) |
+ return SVG_TRANSFORM_SCALE; |
+ |
+ return SVG_TRANSFORM_UNKNOWN; |
} |
- return true; |
+ if (skipString(ptr, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc))) |
+ return SVG_TRANSFORM_TRANSLATE; |
+ if (skipString(ptr, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc))) |
+ return SVG_TRANSFORM_ROTATE; |
+ if (skipString(ptr, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc))) |
+ return SVG_TRANSFORM_MATRIX; |
+ |
+ return SVG_TRANSFORM_UNKNOWN; |
} |
+// These should be kept in sync with enum SVGTransformType |
+const unsigned requiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1}; |
+const unsigned optionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0}; |
+static_assert(SVG_TRANSFORM_UNKNOWN == 0, "index of SVG_TRANSFORM_UNKNOWN has changed"); |
+static_assert(SVG_TRANSFORM_MATRIX == 1, "index of SVG_TRANSFORM_MATRIX has changed"); |
+static_assert(SVG_TRANSFORM_TRANSLATE == 2, "index of SVG_TRANSFORM_TRANSLATE has changed"); |
+static_assert(SVG_TRANSFORM_SCALE == 3, "index of SVG_TRANSFORM_SCALE has changed"); |
+static_assert(SVG_TRANSFORM_ROTATE == 4, "index of SVG_TRANSFORM_ROTATE has changed"); |
+static_assert(SVG_TRANSFORM_SKEWX == 5, "index of SVG_TRANSFORM_SKEWX has changed"); |
+static_assert(SVG_TRANSFORM_SKEWY == 6, "index of SVG_TRANSFORM_SKEWY has changed"); |
+static_assert(WTF_ARRAY_LENGTH(requiredValuesForType) - 1 == SVG_TRANSFORM_SKEWY, "the number of transform types have changed"); |
+static_assert(WTF_ARRAY_LENGTH(requiredValuesForType) == WTF_ARRAY_LENGTH(optionalValuesForType), "the arrays should have the same number of elements"); |
+ |
+const unsigned kMaxTransformArguments = 6; |
+ |
+using TransformArguments = Vector<float, kMaxTransformArguments>; |
+ |
template<typename CharType> |
-int parseTransformParamList(const CharType*& ptr, const CharType* end, float* values, int required, int optional) |
+int parseTransformArgumentsForType( |
+ SVGTransformType type, |
+ const CharType*& ptr, const CharType* end, |
+ TransformArguments& arguments) |
{ |
- int parsedParams = 0; |
- int maxPossibleParams = required + optional; |
+ const size_t required = requiredValuesForType[type]; |
+ const size_t optional = optionalValuesForType[type]; |
+ const size_t maxPossibleParams = required + optional; |
+ ASSERT(maxPossibleParams <= kMaxTransformArguments); |
+ ASSERT(arguments.isEmpty()); |
bool trailingDelimiter = false; |
- skipOptionalSVGSpaces(ptr, end); |
- while (parsedParams < maxPossibleParams) { |
- if (!parseNumber(ptr, end, values[parsedParams], DisallowWhitespace)) |
+ while (arguments.size() < maxPossibleParams) { |
+ float argumentValue = 0; |
+ if (!parseNumber(ptr, end, argumentValue, AllowLeadingWhitespace)) |
break; |
- ++parsedParams; |
+ arguments.append(argumentValue); |
+ trailingDelimiter = false; |
+ |
+ if (arguments.size() == maxPossibleParams) |
+ break; |
if (skipOptionalSVGSpaces(ptr, end) && *ptr == ',') { |
++ptr; |
- skipOptionalSVGSpaces(ptr, end); |
- |
trailingDelimiter = true; |
- } else { |
- trailingDelimiter = false; |
} |
} |
- if (trailingDelimiter || !(parsedParams == required || parsedParams == maxPossibleParams)) |
+ if (trailingDelimiter || !(arguments.size() == required || arguments.size() == maxPossibleParams)) |
return -1; |
- return parsedParams; |
+ return safeCast<int>(arguments.size()); |
} |
-// These should be kept in sync with enum SVGTransformType |
-const int requiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1}; |
-const int optionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0}; |
- |
-template<typename CharType> |
-PassRefPtrWillBeRawPtr<SVGTransform> parseTransformOfType(unsigned type, const CharType*& ptr, const CharType* end) |
+PassRefPtrWillBeRawPtr<SVGTransform> createTransformFromValues(SVGTransformType type, const TransformArguments& arguments) |
{ |
- if (type == SVG_TRANSFORM_UNKNOWN) |
- return nullptr; |
- |
- int valueCount = 0; |
- float values[] = {0, 0, 0, 0, 0, 0}; |
- if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0) { |
- return nullptr; |
- } |
- |
RefPtrWillBeRawPtr<SVGTransform> transform = SVGTransform::create(); |
- |
switch (type) { |
case SVG_TRANSFORM_SKEWX: |
- transform->setSkewX(values[0]); |
+ transform->setSkewX(arguments[0]); |
break; |
case SVG_TRANSFORM_SKEWY: |
- transform->setSkewY(values[0]); |
+ transform->setSkewY(arguments[0]); |
break; |
case SVG_TRANSFORM_SCALE: |
- if (valueCount == 1) // Spec: if only one param given, assume uniform scaling |
- transform->setScale(values[0], values[0]); |
+ // Spec: if only one param given, assume uniform scaling. |
+ if (arguments.size() == 1) |
+ transform->setScale(arguments[0], arguments[0]); |
else |
- transform->setScale(values[0], values[1]); |
+ transform->setScale(arguments[0], arguments[1]); |
break; |
case SVG_TRANSFORM_TRANSLATE: |
- if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0 |
- transform->setTranslate(values[0], 0); |
+ // Spec: if only one param given, assume 2nd param to be 0. |
+ if (arguments.size() == 1) |
+ transform->setTranslate(arguments[0], 0); |
else |
- transform->setTranslate(values[0], values[1]); |
+ transform->setTranslate(arguments[0], arguments[1]); |
break; |
case SVG_TRANSFORM_ROTATE: |
- if (valueCount == 1) |
- transform->setRotate(values[0], 0, 0); |
+ if (arguments.size() == 1) |
+ transform->setRotate(arguments[0], 0, 0); |
else |
- transform->setRotate(values[0], values[1], values[2]); |
+ transform->setRotate(arguments[0], arguments[1], arguments[2]); |
break; |
case SVG_TRANSFORM_MATRIX: |
- transform->setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5])); |
+ transform->setMatrix(AffineTransform(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5])); |
+ break; |
+ case SVG_TRANSFORM_UNKNOWN: |
+ ASSERT_NOT_REACHED(); |
break; |
} |
- |
return transform.release(); |
} |
@@ -190,36 +199,34 @@ bool SVGTransformList::parseInternal(const CharType*& ptr, const CharType* end) |
clear(); |
bool delimParsed = false; |
- while (ptr < end) { |
+ while (skipOptionalSVGSpaces(ptr, end)) { |
delimParsed = false; |
- SVGTransformType transformType = SVG_TRANSFORM_UNKNOWN; |
- skipOptionalSVGSpaces(ptr, end); |
- if (!parseAndSkipTransformType(ptr, end, transformType)) |
+ SVGTransformType transformType = parseAndSkipTransformType(ptr, end); |
+ if (transformType == SVG_TRANSFORM_UNKNOWN) |
return false; |
if (!skipOptionalSVGSpaces(ptr, end) || *ptr != '(') |
return false; |
ptr++; |
- RefPtrWillBeRawPtr<SVGTransform> transform = parseTransformOfType(transformType, ptr, end); |
- if (!transform) |
+ TransformArguments arguments; |
+ int valueCount = parseTransformArgumentsForType(transformType, ptr, end, arguments); |
+ if (valueCount < 0) |
return false; |
+ ASSERT(static_cast<unsigned>(valueCount) >= requiredValuesForType[transformType]); |
if (!skipOptionalSVGSpaces(ptr, end) || *ptr != ')') |
return false; |
ptr++; |
- append(transform.release()); |
+ append(createTransformFromValues(transformType, arguments)); |
- skipOptionalSVGSpaces(ptr, end); |
- if (ptr < end && *ptr == ',') { |
- delimParsed = true; |
+ if (skipOptionalSVGSpaces(ptr, end) && *ptr == ',') { |
++ptr; |
- skipOptionalSVGSpaces(ptr, end); |
+ delimParsed = true; |
} |
} |
- |
return !delimParsed; |
} |
@@ -237,17 +244,14 @@ SVGTransformType parseTransformType(const String& string) |
{ |
if (string.isEmpty()) |
return SVG_TRANSFORM_UNKNOWN; |
- SVGTransformType type = SVG_TRANSFORM_UNKNOWN; |
if (string.is8Bit()) { |
const LChar* ptr = string.characters8(); |
const LChar* end = ptr + string.length(); |
- parseAndSkipTransformType(ptr, end, type); |
- } else { |
- const UChar* ptr = string.characters16(); |
- const UChar* end = ptr + string.length(); |
- parseAndSkipTransformType(ptr, end, type); |
+ return parseAndSkipTransformType(ptr, end); |
} |
- return type; |
+ const UChar* ptr = string.characters16(); |
+ const UChar* end = ptr + string.length(); |
+ return parseAndSkipTransformType(ptr, end); |
} |
String SVGTransformList::valueAsString() const |
@@ -300,21 +304,25 @@ PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGTransformList::cloneForAnimation(cons |
PassRefPtrWillBeRawPtr<SVGTransformList> SVGTransformList::create(SVGTransformType transformType, const String& value) |
{ |
- RefPtrWillBeRawPtr<SVGTransform> transform = nullptr; |
+ TransformArguments arguments; |
+ bool atEndOfValue = false; |
+ int valueCount = -1; |
if (value.isEmpty()) { |
} else if (value.is8Bit()) { |
const LChar* ptr = value.characters8(); |
const LChar* end = ptr + value.length(); |
- transform = parseTransformOfType(transformType, ptr, end); |
+ valueCount = parseTransformArgumentsForType(transformType, ptr, end, arguments); |
+ atEndOfValue = !skipOptionalSVGSpaces(ptr, end); |
} else { |
const UChar* ptr = value.characters16(); |
const UChar* end = ptr + value.length(); |
- transform = parseTransformOfType(transformType, ptr, end); |
+ valueCount = parseTransformArgumentsForType(transformType, ptr, end, arguments); |
+ atEndOfValue = !skipOptionalSVGSpaces(ptr, end); |
} |
RefPtrWillBeRawPtr<SVGTransformList> svgTransformList = SVGTransformList::create(); |
- if (transform) |
- svgTransformList->append(transform); |
+ if (atEndOfValue && valueCount > 0) |
+ svgTransformList->append(createTransformFromValues(transformType, arguments)); |
return svgTransformList.release(); |
} |
@@ -332,8 +340,7 @@ void SVGTransformList::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGEle |
RefPtrWillBeRawPtr<SVGTransform> toTransform = otherList->at(0); |
ASSERT(fromTransform->transformType() == toTransform->transformType()); |
- clear(); |
- append(SVGTransformDistance::addSVGTransforms(fromTransform, toTransform)); |
+ initialize(SVGTransformDistance::addSVGTransforms(fromTransform, toTransform)); |
} |
void SVGTransformList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtrWillBeRawPtr<SVGPropertyBase> fromValue, PassRefPtrWillBeRawPtr<SVGPropertyBase> toValue, PassRefPtrWillBeRawPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement) |