blob: 8320890663acf2b0bc646376a2c45c706d823aa0 [file] [log] [blame]
/*
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#if ENABLE(SVG)
#include "SVGPathBlender.h"
#include "SVGPathSeg.h"
namespace WebCore {
SVGPathBlender::SVGPathBlender()
: m_fromSource(0)
, m_toSource(0)
, m_consumer(0)
, m_progress(0)
{
}
SVGPathBlender::~SVGPathBlender()
{
}
float SVGPathBlender::blendAnimatedFloat(float from, float to)
{
return (to - from) * m_progress + from;
}
FloatPoint SVGPathBlender::blendAnimatedFloatPoint(FloatPoint& from, FloatPoint& to)
{
return FloatPoint((to.x() - from.x()) * m_progress + from.x(), (to.y() - from.y()) * m_progress + from.y());
}
bool SVGPathBlender::blendMoveToSegment()
{
FloatPoint fromTargetPoint;
FloatPoint toTargetPoint;
if (!m_fromSource->parseMoveToSegment(fromTargetPoint)
|| !m_toSource->parseMoveToSegment(toTargetPoint))
return false;
m_consumer->moveTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint), false, m_mode);
return true;
}
bool SVGPathBlender::blendLineToSegment()
{
FloatPoint fromTargetPoint;
FloatPoint toTargetPoint;
if (!m_fromSource->parseLineToSegment(fromTargetPoint)
|| !m_toSource->parseLineToSegment(toTargetPoint))
return false;
m_consumer->lineTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint), m_mode);
return true;
}
bool SVGPathBlender::blendLineToHorizontalSegment()
{
float fromX;
float toX;
if (!m_fromSource->parseLineToHorizontalSegment(fromX)
|| !m_toSource->parseLineToHorizontalSegment(toX))
return false;
m_consumer->lineToHorizontal(blendAnimatedFloat(fromX, toX), m_mode);
return true;
}
bool SVGPathBlender::blendLineToVerticalSegment()
{
float fromY;
float toY;
if (!m_fromSource->parseLineToVerticalSegment(fromY)
|| !m_toSource->parseLineToVerticalSegment(toY))
return false;
m_consumer->lineToVertical(blendAnimatedFloat(fromY, toY), m_mode);
return true;
}
bool SVGPathBlender::blendCurveToCubicSegment()
{
FloatPoint fromTargetPoint;
FloatPoint fromPoint1;
FloatPoint fromPoint2;
FloatPoint toTargetPoint;
FloatPoint toPoint1;
FloatPoint toPoint2;
if (!m_fromSource->parseCurveToCubicSegment(fromPoint1, fromPoint2, fromTargetPoint)
|| !m_toSource->parseCurveToCubicSegment(toPoint1, toPoint2, toTargetPoint))
return false;
m_consumer->curveToCubic(blendAnimatedFloatPoint(fromPoint1, toPoint1),
blendAnimatedFloatPoint(fromPoint2, toPoint2),
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
m_mode);
return true;
}
bool SVGPathBlender::blendCurveToCubicSmoothSegment()
{
FloatPoint fromTargetPoint;
FloatPoint fromPoint2;
FloatPoint toTargetPoint;
FloatPoint toPoint2;
if (!m_fromSource->parseCurveToCubicSmoothSegment(fromPoint2, fromTargetPoint)
|| !m_toSource->parseCurveToCubicSmoothSegment(toPoint2, toTargetPoint))
return false;
m_consumer->curveToCubicSmooth(blendAnimatedFloatPoint(fromPoint2, toPoint2),
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
m_mode);
return true;
}
bool SVGPathBlender::blendCurveToQuadraticSegment()
{
FloatPoint fromTargetPoint;
FloatPoint fromPoint1;
FloatPoint toTargetPoint;
FloatPoint toPoint1;
if (!m_fromSource->parseCurveToQuadraticSegment(fromPoint1, fromTargetPoint)
|| !m_toSource->parseCurveToQuadraticSegment(toPoint1, toTargetPoint))
return false;
m_consumer->curveToQuadratic(blendAnimatedFloatPoint(fromPoint1, toPoint1),
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
m_mode);
return true;
}
bool SVGPathBlender::blendCurveToQuadraticSmoothSegment()
{
FloatPoint fromTargetPoint;
FloatPoint toTargetPoint;
if (!m_fromSource->parseCurveToQuadraticSmoothSegment(fromTargetPoint)
|| !m_toSource->parseCurveToQuadraticSmoothSegment(toTargetPoint))
return false;
m_consumer->curveToQuadraticSmooth(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint), m_mode);
return true;
}
bool SVGPathBlender::blendArcToSegment()
{
float fromRx;
float fromRy;
float fromAngle;
bool fromLargeArc;
bool fromSweep;
FloatPoint fromTargetPoint;
float toRx;
float toRy;
float toAngle;
bool toLargeArc;
bool toSweep;
FloatPoint toTargetPoint;
if (!m_fromSource->parseArcToSegment(fromRx, fromRy, fromAngle, fromLargeArc, fromSweep, fromTargetPoint)
|| !m_toSource->parseArcToSegment(toRx, toRy, toAngle, toLargeArc, toSweep, toTargetPoint))
return false;
m_consumer->arcTo(blendAnimatedFloat(fromRx, toRx),
blendAnimatedFloat(fromRy, toRy),
blendAnimatedFloat(fromAngle, toAngle),
m_progress < 0.5 ? fromLargeArc : toLargeArc,
m_progress < 0.5 ? fromSweep : toSweep,
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
m_mode);
return true;
}
bool SVGPathBlender::blendAnimatedPath(float progress, SVGPathSource* fromSource, SVGPathSource* toSource, SVGPathConsumer* consumer)
{
ASSERT(fromSource);
ASSERT(toSource);
ASSERT(consumer);
m_fromSource = fromSource;
m_toSource = toSource;
m_consumer = consumer;
m_progress = progress;
while (true) {
SVGPathSegType fromCommand;
SVGPathSegType toCommand;
if (!m_fromSource->parseSVGSegmentType(fromCommand) || !m_toSource->parseSVGSegmentType(toCommand))
return false;
if (fromCommand != toCommand)
return false;
m_mode = AbsoluteCoordinates;
switch (fromCommand) {
case PathSegMoveToRel:
m_mode = RelativeCoordinates;
case PathSegMoveToAbs:
if (!blendMoveToSegment())
return false;
break;
case PathSegLineToRel:
m_mode = RelativeCoordinates;
case PathSegLineToAbs:
if (!blendLineToSegment())
return false;
break;
case PathSegLineToHorizontalRel:
m_mode = RelativeCoordinates;
case PathSegLineToHorizontalAbs:
if (!blendLineToHorizontalSegment())
return false;
break;
case PathSegLineToVerticalRel:
m_mode = RelativeCoordinates;
case PathSegLineToVerticalAbs:
if (!blendLineToVerticalSegment())
return false;
break;
case PathSegClosePath:
m_consumer->closePath();
break;
case PathSegCurveToCubicRel:
m_mode = RelativeCoordinates;
case PathSegCurveToCubicAbs:
if (!blendCurveToCubicSegment())
return false;
break;
case PathSegCurveToCubicSmoothRel:
m_mode = RelativeCoordinates;
case PathSegCurveToCubicSmoothAbs:
if (!blendCurveToCubicSmoothSegment())
return false;
break;
case PathSegCurveToQuadraticRel:
m_mode = RelativeCoordinates;
case PathSegCurveToQuadraticAbs:
if (!blendCurveToQuadraticSegment())
return false;
break;
case PathSegCurveToQuadraticSmoothRel:
m_mode = RelativeCoordinates;
case PathSegCurveToQuadraticSmoothAbs:
if (!blendCurveToQuadraticSmoothSegment())
return false;
break;
case PathSegArcRel:
m_mode = RelativeCoordinates;
case PathSegArcAbs:
if (!blendArcToSegment())
return false;
break;
default:
return false;
}
if (m_fromSource->hasMoreData() != m_toSource->hasMoreData())
return false;
if (!m_fromSource->hasMoreData() || !m_toSource->hasMoreData())
break;
}
return true;
}
void SVGPathBlender::cleanup()
{
ASSERT(m_toSource);
ASSERT(m_fromSource);
ASSERT(m_consumer);
m_consumer->cleanup();
m_toSource = 0;
m_fromSource = 0;
m_consumer = 0;
}
}
#endif // ENABLE(SVG)