blob: 6dfafe2197dc2d43143f150f238de73aa3ca3e2b [file] [log] [blame]
// 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