Index: third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp |
diff --git a/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp b/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6dfafe2197dc2d43143f150f238de73aa3ca3e2b |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/animation/SVGPathInterpolationType.cpp |
@@ -0,0 +1,170 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/animation/SVGPathInterpolationType.h" |
+ |
+#include "core/animation/InterpolatedSVGPathSource.h" |
+#include "core/animation/InterpolationEnvironment.h" |
+#include "core/animation/SVGPathSegInterpolationFunctions.h" |
+#include "core/svg/SVGPath.h" |
+#include "core/svg/SVGPathByteStreamBuilder.h" |
+#include "core/svg/SVGPathByteStreamSource.h" |
+#include "core/svg/SVGPathParser.h" |
+ |
+namespace blink { |
+ |
+class SVGPathNonInterpolableValue : public NonInterpolableValue { |
+public: |
+ virtual ~SVGPathNonInterpolableValue() {} |
+ |
+ static PassRefPtr<SVGPathNonInterpolableValue> create(Vector<SVGPathSegType>& pathSegTypes) |
+ { |
+ return adoptRef(new SVGPathNonInterpolableValue(pathSegTypes)); |
+ } |
+ |
+ const Vector<SVGPathSegType>& pathSegTypes() const { return m_pathSegTypes; } |
+ |
+ DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); |
+ |
+private: |
+ SVGPathNonInterpolableValue(Vector<SVGPathSegType>& pathSegTypes) |
+ { |
+ m_pathSegTypes.swap(pathSegTypes); |
+ } |
+ |
+ Vector<SVGPathSegType> m_pathSegTypes; |
+}; |
+ |
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue); |
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(SVGPathNonInterpolableValue); |
+ |
+enum PathComponentIndex { |
+ PathArgsIndex, |
+ PathNeutralIndex, |
+ PathComponentIndexCount, |
+}; |
+ |
+PassOwnPtr<InterpolationValue> SVGPathInterpolationType::maybeConvertSVGValue(const SVGPropertyBase& svgValue) const |
+{ |
+ if (svgValue.type() != AnimatedPath) |
+ return nullptr; |
+ |
+ SVGPathByteStreamSource pathSource(toSVGPath(svgValue).byteStream()); |
+ size_t length = 0; |
+ PathCoordinates currentCoordinates; |
+ Vector<OwnPtr<InterpolableValue>> interpolablePathSegs; |
+ Vector<SVGPathSegType> pathSegTypes; |
+ |
+ while (pathSource.hasMoreData()) { |
+ const PathSegmentData segment = pathSource.parseSegment(); |
+ interpolablePathSegs.append(SVGPathSegInterpolationFunctions::consumePathSeg(segment, currentCoordinates)); |
+ pathSegTypes.append(segment.command); |
+ length++; |
+ } |
+ |
+ OwnPtr<InterpolableList> pathArgs = InterpolableList::create(length); |
+ for (size_t i = 0; i < interpolablePathSegs.size(); i++) |
+ pathArgs->set(i, interpolablePathSegs[i].release()); |
+ |
+ OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount); |
+ result->set(PathArgsIndex, pathArgs.release()); |
+ result->set(PathNeutralIndex, InterpolableNumber::create(0)); |
+ |
+ return InterpolationValue::create(*this, result.release(), SVGPathNonInterpolableValue::create(pathSegTypes)); |
+} |
+ |
+class UnderlyingPathSegTypesChecker : public InterpolationType::ConversionChecker { |
+public: |
+ ~UnderlyingPathSegTypesChecker() final {} |
+ |
+ static PassOwnPtr<UnderlyingPathSegTypesChecker> create(const InterpolationType& type, const UnderlyingValue& underlyingValue) |
+ { |
+ return adoptPtr(new UnderlyingPathSegTypesChecker(type, getPathSegTypes(underlyingValue))); |
+ } |
+ |
+private: |
+ UnderlyingPathSegTypesChecker(const InterpolationType& type, const Vector<SVGPathSegType>& pathSegTypes) |
+ : ConversionChecker(type) |
+ , m_pathSegTypes(pathSegTypes) |
+ { } |
+ |
+ static const Vector<SVGPathSegType>& getPathSegTypes(const UnderlyingValue& underlyingValue) |
+ { |
+ return toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(); |
+ } |
+ |
+ bool isValid(const InterpolationEnvironment&, const UnderlyingValue& underlyingValue) const final |
+ { |
+ return m_pathSegTypes == getPathSegTypes(underlyingValue); |
+ } |
+ |
+ Vector<SVGPathSegType> m_pathSegTypes; |
+}; |
+ |
+PassOwnPtr<InterpolationValue> SVGPathInterpolationType::maybeConvertNeutral(const UnderlyingValue& underlyingValue, ConversionCheckers& conversionCheckers) const |
+{ |
+ conversionCheckers.append(UnderlyingPathSegTypesChecker::create(*this, underlyingValue)); |
+ OwnPtr<InterpolableList> result = InterpolableList::create(PathComponentIndexCount); |
+ result->set(PathArgsIndex, toInterpolableList(underlyingValue->interpolableValue()).get(PathArgsIndex)->cloneAndZero()); |
+ result->set(PathNeutralIndex, InterpolableNumber::create(1)); |
+ return InterpolationValue::create(*this, result.release(), |
+ const_cast<NonInterpolableValue*>(underlyingValue->nonInterpolableValue())); // Take ref. |
+} |
+ |
+static bool pathSegTypesMatch(const Vector<SVGPathSegType>& a, const Vector<SVGPathSegType>& b) |
+{ |
+ if (a.size() != b.size()) |
+ return false; |
+ |
+ for (size_t i = 0; i < a.size(); i++) { |
+ if (toAbsolutePathSegType(a[i]) != toAbsolutePathSegType(b[i])) |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+PassOwnPtr<PairwisePrimitiveInterpolation> SVGPathInterpolationType::mergeSingleConversions(InterpolationValue& startValue, InterpolationValue& endValue) const |
+{ |
+ const Vector<SVGPathSegType>& startTypes = toSVGPathNonInterpolableValue(startValue.nonInterpolableValue())->pathSegTypes(); |
+ const Vector<SVGPathSegType>& endTypes = toSVGPathNonInterpolableValue(endValue.nonInterpolableValue())->pathSegTypes(); |
+ if (!pathSegTypesMatch(startTypes, endTypes)) |
+ return nullptr; |
+ |
+ return PairwisePrimitiveInterpolation::create(*this, |
+ startValue.mutableComponent().interpolableValue.release(), |
+ endValue.mutableComponent().interpolableValue.release(), |
+ const_cast<NonInterpolableValue*>(endValue.nonInterpolableValue())); // Take ref. |
+} |
+ |
+void SVGPathInterpolationType::composite(UnderlyingValue& underlyingValue, double underlyingFraction, const InterpolationValue& value) const |
+{ |
+ const InterpolableList& list = toInterpolableList(value.interpolableValue()); |
+ double neutralComponent = toInterpolableNumber(list.get(PathNeutralIndex))->value(); |
+ |
+ if (neutralComponent == 0) { |
+ underlyingValue.set(&value); |
+ return; |
+ } |
+ |
+ ASSERT(pathSegTypesMatch( |
+ toSVGPathNonInterpolableValue(underlyingValue->nonInterpolableValue())->pathSegTypes(), |
+ toSVGPathNonInterpolableValue(value.nonInterpolableValue())->pathSegTypes())); |
+ underlyingValue.mutableComponent().interpolableValue->scaleAndAdd(neutralComponent, value.interpolableValue()); |
+ underlyingValue.mutableComponent().nonInterpolableValue = const_cast<NonInterpolableValue*>(value.nonInterpolableValue()); // Take ref. |
+} |
+ |
+PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGPathInterpolationType::appliedSVGValue(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue) const |
+{ |
+ OwnPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create(); |
+ InterpolatedSVGPathSource source( |
+ toInterpolableList(*toInterpolableList(interpolableValue).get(PathArgsIndex)), |
+ toSVGPathNonInterpolableValue(nonInterpolableValue)->pathSegTypes()); |
+ SVGPathByteStreamBuilder builder(*pathByteStream); |
+ SVGPathParser(&source, &builder).parsePathDataFromSource(UnalteredParsing, false); |
+ return SVGPath::create(CSSPathValue::create(pathByteStream.release())); |
+} |
+ |
+} // namespace blink |