blob: 8526c8b8004425e449d49008b4ef1b1d8de6e0fb [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 "core/animation/SVGPathSegInterpolationFunctions.h"
namespace blink {
PassOwnPtr<InterpolableNumber> consumeControlAxis(double value, bool isAbsolute, double currentValue)
{
return InterpolableNumber::create(isAbsolute ? value : currentValue + value);
}
double consumeInterpolableControlAxis(const InterpolableValue* number, bool isAbsolute, double currentValue)
{
double value = toInterpolableNumber(number)->value();
return isAbsolute ? value : value - currentValue;
}
PassOwnPtr<InterpolableNumber> consumeCoordinateAxis(double value, bool isAbsolute, double& currentValue)
{
if (isAbsolute)
currentValue = value;
else
currentValue += value;
return InterpolableNumber::create(currentValue);
}
double consumeInterpolableCoordinateAxis(const InterpolableValue* number, bool isAbsolute, double& currentValue)
{
double previousValue = currentValue;
currentValue = toInterpolableNumber(number)->value();
return isAbsolute ? currentValue : currentValue - previousValue;
}
PassOwnPtr<InterpolableValue> consumeClosePath(const PathSegmentData&, PathCoordinates& coordinates)
{
coordinates.currentX = coordinates.initialX;
coordinates.currentY = coordinates.initialY;
return InterpolableList::create(0);
}
PathSegmentData consumeInterpolableClosePath(const InterpolableValue&, SVGPathSegType segType, PathCoordinates& coordinates)
{
coordinates.currentX = coordinates.initialX;
coordinates.currentY = coordinates.initialY;
PathSegmentData segment;
segment.command = segType;
return segment;
}
PassOwnPtr<InterpolableValue> consumeSingleCoordinate(const PathSegmentData& segment, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segment.command);
OwnPtr<InterpolableList> result = InterpolableList::create(2);
result->set(0, consumeCoordinateAxis(segment.x(), isAbsolute, coordinates.currentX));
result->set(1, consumeCoordinateAxis(segment.y(), isAbsolute, coordinates.currentY));
if (toAbsolutePathSegType(segment.command) == PathSegMoveToAbs) {
// Any upcoming 'closepath' commands bring us back to the location we have just moved to.
coordinates.initialX = coordinates.currentX;
coordinates.initialY = coordinates.currentY;
}
return result.release();
}
PathSegmentData consumeInterpolableSingleCoordinate(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
const InterpolableList& list = toInterpolableList(value);
bool isAbsolute = isAbsolutePathSegType(segType);
PathSegmentData segment;
segment.command = segType;
segment.targetPoint.setX(consumeInterpolableCoordinateAxis(list.get(0), isAbsolute, coordinates.currentX));
segment.targetPoint.setY(consumeInterpolableCoordinateAxis(list.get(1), isAbsolute, coordinates.currentY));
if (toAbsolutePathSegType(segType) == PathSegMoveToAbs) {
// Any upcoming 'closepath' commands bring us back to the location we have just moved to.
coordinates.initialX = coordinates.currentX;
coordinates.initialY = coordinates.currentY;
}
return segment;
}
PassOwnPtr<InterpolableValue> consumeCurvetoCubic(const PathSegmentData& segment, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segment.command);
OwnPtr<InterpolableList> result = InterpolableList::create(6);
result->set(0, consumeControlAxis(segment.x1(), isAbsolute, coordinates.currentX));
result->set(1, consumeControlAxis(segment.y1(), isAbsolute, coordinates.currentY));
result->set(2, consumeControlAxis(segment.x2(), isAbsolute, coordinates.currentX));
result->set(3, consumeControlAxis(segment.y2(), isAbsolute, coordinates.currentY));
result->set(4, consumeCoordinateAxis(segment.x(), isAbsolute, coordinates.currentX));
result->set(5, consumeCoordinateAxis(segment.y(), isAbsolute, coordinates.currentY));
return result.release();
}
PathSegmentData consumeInterpolableCurvetoCubic(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
const InterpolableList& list = toInterpolableList(value);
bool isAbsolute = isAbsolutePathSegType(segType);
PathSegmentData segment;
segment.command = segType;
segment.point1.setX(consumeInterpolableControlAxis(list.get(0), isAbsolute, coordinates.currentX));
segment.point1.setY(consumeInterpolableControlAxis(list.get(1), isAbsolute, coordinates.currentY));
segment.point2.setX(consumeInterpolableControlAxis(list.get(2), isAbsolute, coordinates.currentX));
segment.point2.setY(consumeInterpolableControlAxis(list.get(3), isAbsolute, coordinates.currentY));
segment.targetPoint.setX(consumeInterpolableCoordinateAxis(list.get(4), isAbsolute, coordinates.currentX));
segment.targetPoint.setY(consumeInterpolableCoordinateAxis(list.get(5), isAbsolute, coordinates.currentY));
return segment;
}
PassOwnPtr<InterpolableValue> consumeCurvetoQuadratic(const PathSegmentData& segment, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segment.command);
OwnPtr<InterpolableList> result = InterpolableList::create(4);
result->set(0, consumeControlAxis(segment.x1(), isAbsolute, coordinates.currentX));
result->set(1, consumeControlAxis(segment.y1(), isAbsolute, coordinates.currentY));
result->set(2, consumeCoordinateAxis(segment.x(), isAbsolute, coordinates.currentX));
result->set(3, consumeCoordinateAxis(segment.y(), isAbsolute, coordinates.currentY));
return result.release();
}
PathSegmentData consumeInterpolableCurvetoQuadratic(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
const InterpolableList& list = toInterpolableList(value);
bool isAbsolute = isAbsolutePathSegType(segType);
PathSegmentData segment;
segment.command = segType;
segment.point1.setX(consumeInterpolableControlAxis(list.get(0), isAbsolute, coordinates.currentX));
segment.point1.setY(consumeInterpolableControlAxis(list.get(1), isAbsolute, coordinates.currentY));
segment.targetPoint.setX(consumeInterpolableCoordinateAxis(list.get(2), isAbsolute, coordinates.currentX));
segment.targetPoint.setY(consumeInterpolableCoordinateAxis(list.get(3), isAbsolute, coordinates.currentY));
return segment;
}
PassOwnPtr<InterpolableValue> consumeArc(const PathSegmentData& segment, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segment.command);
OwnPtr<InterpolableList> result = InterpolableList::create(7);
result->set(0, consumeCoordinateAxis(segment.x(), isAbsolute, coordinates.currentX));
result->set(1, consumeCoordinateAxis(segment.y(), isAbsolute, coordinates.currentY));
result->set(2, InterpolableNumber::create(segment.r1()));
result->set(3, InterpolableNumber::create(segment.r2()));
result->set(4, InterpolableNumber::create(segment.arcAngle()));
result->set(5, InterpolableBool::create(segment.largeArcFlag()));
result->set(6, InterpolableBool::create(segment.sweepFlag()));
return result.release();
}
PathSegmentData consumeInterpolableArc(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
const InterpolableList& list = toInterpolableList(value);
bool isAbsolute = isAbsolutePathSegType(segType);
PathSegmentData segment;
segment.command = segType;
segment.targetPoint.setX(consumeInterpolableCoordinateAxis(list.get(0), isAbsolute, coordinates.currentX));
segment.targetPoint.setY(consumeInterpolableCoordinateAxis(list.get(1), isAbsolute, coordinates.currentY));
segment.arcRadii().setX(toInterpolableNumber(list.get(2))->value());
segment.arcRadii().setY(toInterpolableNumber(list.get(3))->value());
segment.setArcAngle(toInterpolableNumber(list.get(4))->value());
segment.arcLarge = toInterpolableBool(list.get(5))->value();
segment.arcSweep = toInterpolableBool(list.get(6))->value();
return segment;
}
PassOwnPtr<InterpolableValue> consumeLinetoHorizontal(const PathSegmentData& segment, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segment.command);
return consumeCoordinateAxis(segment.x(), isAbsolute, coordinates.currentX);
}
PathSegmentData consumeInterpolableLinetoHorizontal(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segType);
PathSegmentData segment;
segment.command = segType;
segment.targetPoint.setX(consumeInterpolableCoordinateAxis(&value, isAbsolute, coordinates.currentX));
return segment;
}
PassOwnPtr<InterpolableValue> consumeLinetoVertical(const PathSegmentData& segment, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segment.command);
return consumeCoordinateAxis(segment.y(), isAbsolute, coordinates.currentY);
}
PathSegmentData consumeInterpolableLinetoVertical(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segType);
PathSegmentData segment;
segment.command = segType;
segment.targetPoint.setY(consumeInterpolableCoordinateAxis(&value, isAbsolute, coordinates.currentY));
return segment;
}
PassOwnPtr<InterpolableValue> consumeCurvetoCubicSmooth(const PathSegmentData& segment, PathCoordinates& coordinates)
{
bool isAbsolute = isAbsolutePathSegType(segment.command);
OwnPtr<InterpolableList> result = InterpolableList::create(4);
result->set(0, consumeControlAxis(segment.x2(), isAbsolute, coordinates.currentX));
result->set(1, consumeControlAxis(segment.y2(), isAbsolute, coordinates.currentY));
result->set(2, consumeCoordinateAxis(segment.x(), isAbsolute, coordinates.currentX));
result->set(3, consumeCoordinateAxis(segment.y(), isAbsolute, coordinates.currentY));
return result.release();
}
PathSegmentData consumeInterpolableCurvetoCubicSmooth(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
const InterpolableList& list = toInterpolableList(value);
bool isAbsolute = isAbsolutePathSegType(segType);
PathSegmentData segment;
segment.command = segType;
segment.point2.setX(consumeInterpolableControlAxis(list.get(0), isAbsolute, coordinates.currentX));
segment.point2.setY(consumeInterpolableControlAxis(list.get(1), isAbsolute, coordinates.currentY));
segment.targetPoint.setX(consumeInterpolableCoordinateAxis(list.get(2), isAbsolute, coordinates.currentX));
segment.targetPoint.setY(consumeInterpolableCoordinateAxis(list.get(3), isAbsolute, coordinates.currentY));
return segment;
}
PassOwnPtr<InterpolableValue> SVGPathSegInterpolationFunctions::consumePathSeg(const PathSegmentData& segment, PathCoordinates& coordinates)
{
switch (segment.command) {
case PathSegClosePath:
return consumeClosePath(segment, coordinates);
case PathSegMoveToAbs:
case PathSegMoveToRel:
case PathSegLineToAbs:
case PathSegLineToRel:
case PathSegCurveToQuadraticSmoothAbs:
case PathSegCurveToQuadraticSmoothRel:
return consumeSingleCoordinate(segment, coordinates);
case PathSegCurveToCubicAbs:
case PathSegCurveToCubicRel:
return consumeCurvetoCubic(segment, coordinates);
case PathSegCurveToQuadraticAbs:
case PathSegCurveToQuadraticRel:
return consumeCurvetoQuadratic(segment, coordinates);
case PathSegArcAbs:
case PathSegArcRel:
return consumeArc(segment, coordinates);
case PathSegLineToHorizontalAbs:
case PathSegLineToHorizontalRel:
return consumeLinetoHorizontal(segment, coordinates);
case PathSegLineToVerticalAbs:
case PathSegLineToVerticalRel:
return consumeLinetoVertical(segment, coordinates);
case PathSegCurveToCubicSmoothAbs:
case PathSegCurveToCubicSmoothRel:
return consumeCurvetoCubicSmooth(segment, coordinates);
case PathSegUnknown:
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
PathSegmentData SVGPathSegInterpolationFunctions::consumeInterpolablePathSeg(const InterpolableValue& value, SVGPathSegType segType, PathCoordinates& coordinates)
{
switch (segType) {
case PathSegClosePath:
return consumeInterpolableClosePath(value, segType, coordinates);
case PathSegMoveToAbs:
case PathSegMoveToRel:
case PathSegLineToAbs:
case PathSegLineToRel:
case PathSegCurveToQuadraticSmoothAbs:
case PathSegCurveToQuadraticSmoothRel:
return consumeInterpolableSingleCoordinate(value, segType, coordinates);
case PathSegCurveToCubicAbs:
case PathSegCurveToCubicRel:
return consumeInterpolableCurvetoCubic(value, segType, coordinates);
case PathSegCurveToQuadraticAbs:
case PathSegCurveToQuadraticRel:
return consumeInterpolableCurvetoQuadratic(value, segType, coordinates);
case PathSegArcAbs:
case PathSegArcRel:
return consumeInterpolableArc(value, segType, coordinates);
case PathSegLineToHorizontalAbs:
case PathSegLineToHorizontalRel:
return consumeInterpolableLinetoHorizontal(value, segType, coordinates);
case PathSegLineToVerticalAbs:
case PathSegLineToVerticalRel:
return consumeInterpolableLinetoVertical(value, segType, coordinates);
case PathSegCurveToCubicSmoothAbs:
case PathSegCurveToCubicSmoothRel:
return consumeInterpolableCurvetoCubicSmooth(value, segType, coordinates);
case PathSegUnknown:
default:
ASSERT_NOT_REACHED();
return PathSegmentData();
}
}
} // namespace blink