Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3787)

Unified Diff: Source/core/svg/SVGPathBlender.cpp

Issue 1056873002: Move SVG path blend state to its own object (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Re-order declarations. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/svg/SVGPathBlender.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/svg/SVGPathBlender.cpp
diff --git a/Source/core/svg/SVGPathBlender.cpp b/Source/core/svg/SVGPathBlender.cpp
index dbd5aabda028b20d82aeb66bd3007a5044ce4e9f..c4637cf5617d7b14cd1ff6927ccac7fa73147196 100644
--- a/Source/core/svg/SVGPathBlender.cpp
+++ b/Source/core/svg/SVGPathBlender.cpp
@@ -24,32 +24,44 @@
#include "core/svg/SVGPathSeg.h"
#include "core/svg/SVGPathSource.h"
#include "platform/animation/AnimationUtilities.h"
-#include "wtf/TemporaryChange.h"
namespace blink {
-SVGPathBlender::SVGPathBlender(SVGPathSource* fromSource, SVGPathSource* toSource, SVGPathConsumer* consumer)
- : m_fromSource(fromSource)
- , m_toSource(toSource)
- , m_consumer(consumer)
- , m_progress(0)
- , m_addTypesCount(0)
- , m_isInFirstHalfOfAnimation(false)
- , m_typesAreEqual(false)
- , m_fromIsAbsolute(false)
- , m_toIsAbsolute(false)
-{
- ASSERT(m_fromSource);
- ASSERT(m_toSource);
- ASSERT(m_consumer);
-}
+enum FloatBlendMode {
+ BlendHorizontal,
+ BlendVertical
+};
+
+class SVGPathBlender::BlendState {
+public:
+ BlendState(float progress, unsigned addTypesCount = 0)
+ : m_progress(progress)
+ , m_addTypesCount(addTypesCount)
+ , m_isInFirstHalfOfAnimation(progress < 0.5f)
+ , m_typesAreEqual(false)
+ , m_fromIsAbsolute(false)
+ {
+ }
-DEFINE_TRACE(SVGPathBlender)
-{
- visitor->trace(m_fromSource);
- visitor->trace(m_toSource);
- visitor->trace(m_consumer);
-}
+ bool blendSegments(const PathSegmentData& fromSeg, const PathSegmentData& toSeg, PathSegmentData&);
+
+private:
+ float blendAnimatedDimensonalFloat(float, float, FloatBlendMode);
+ FloatPoint blendAnimatedFloatPointSameCoordinates(const FloatPoint& from, const FloatPoint& to);
+ FloatPoint blendAnimatedFloatPoint(const FloatPoint& from, const FloatPoint& to);
+ bool canBlend(const PathSegmentData& fromSeg, const PathSegmentData& toSeg);
+
+ FloatPoint m_fromCurrentPoint;
+ FloatPoint m_toCurrentPoint;
+
+ float m_progress;
+ unsigned m_addTypesCount;
+ bool m_isInFirstHalfOfAnimation;
+ // This is per-segment blend state corresponding to the 'from' and 'to'
+ // segments currently being blended, and only used within blendSegments().
+ bool m_typesAreEqual;
+ bool m_fromIsAbsolute;
+};
// Helper functions
static inline FloatPoint blendFloatPoint(const FloatPoint& a, const FloatPoint& b, float progress)
@@ -57,7 +69,7 @@ static inline FloatPoint blendFloatPoint(const FloatPoint& a, const FloatPoint&
return FloatPoint(blend(a.x(), b.x(), progress), blend(a.y(), b.y(), progress));
}
-float SVGPathBlender::blendAnimatedDimensonalFloat(float from, float to, FloatBlendMode blendMode)
+float SVGPathBlender::BlendState::blendAnimatedDimensonalFloat(float from, float to, FloatBlendMode blendMode)
{
if (m_addTypesCount) {
ASSERT(m_typesAreEqual);
@@ -82,7 +94,7 @@ float SVGPathBlender::blendAnimatedDimensonalFloat(float from, float to, FloatBl
return !m_fromIsAbsolute ? animValue + currentValue : animValue - currentValue;
}
-FloatPoint SVGPathBlender::blendAnimatedFloatPointSameCoordinates(const FloatPoint& fromPoint, const FloatPoint& toPoint)
+FloatPoint SVGPathBlender::BlendState::blendAnimatedFloatPointSameCoordinates(const FloatPoint& fromPoint, const FloatPoint& toPoint)
{
if (m_addTypesCount) {
FloatPoint repeatedToPoint = toPoint;
@@ -92,7 +104,7 @@ FloatPoint SVGPathBlender::blendAnimatedFloatPointSameCoordinates(const FloatPoi
return blendFloatPoint(fromPoint, toPoint, m_progress);
}
-FloatPoint SVGPathBlender::blendAnimatedFloatPoint(const FloatPoint& fromPoint, const FloatPoint& toPoint)
+FloatPoint SVGPathBlender::BlendState::blendAnimatedFloatPoint(const FloatPoint& fromPoint, const FloatPoint& toPoint)
{
if (m_typesAreEqual)
return blendAnimatedFloatPointSameCoordinates(fromPoint, toPoint);
@@ -119,182 +131,154 @@ FloatPoint SVGPathBlender::blendAnimatedFloatPoint(const FloatPoint& fromPoint,
return animatedPoint;
}
-PathSegmentData SVGPathBlender::blendMoveToSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
-{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
-
- m_fromCurrentPoint = m_fromIsAbsolute ? fromSeg.targetPoint : m_fromCurrentPoint + fromSeg.targetPoint;
- m_toCurrentPoint = m_toIsAbsolute ? toSeg.targetPoint : m_toCurrentPoint + toSeg.targetPoint;
- return blendedSegment;
-}
-
-PathSegmentData SVGPathBlender::blendLineToSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
-{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
-
- m_fromCurrentPoint = m_fromIsAbsolute ? fromSeg.targetPoint : m_fromCurrentPoint + fromSeg.targetPoint;
- m_toCurrentPoint = m_toIsAbsolute ? toSeg.targetPoint : m_toCurrentPoint + toSeg.targetPoint;
- return blendedSegment;
-}
-
-PathSegmentData SVGPathBlender::blendLineToHorizontalSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
-{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint.setX(blendAnimatedDimensonalFloat(fromSeg.targetPoint.x(), toSeg.targetPoint.x(), BlendHorizontal));
-
- m_fromCurrentPoint.setX(m_fromIsAbsolute ? fromSeg.targetPoint.x() : m_fromCurrentPoint.x() + fromSeg.targetPoint.x());
- m_toCurrentPoint.setX(m_toIsAbsolute ? toSeg.targetPoint.x() : m_toCurrentPoint.x() + toSeg.targetPoint.x());
- return blendedSegment;
-}
-
-PathSegmentData SVGPathBlender::blendLineToVerticalSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
-{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint.setY(blendAnimatedDimensonalFloat(fromSeg.targetPoint.y(), toSeg.targetPoint.y(), BlendVertical));
-
- m_fromCurrentPoint.setY(m_fromIsAbsolute ? fromSeg.targetPoint.y() : m_fromCurrentPoint.y() + fromSeg.targetPoint.y());
- m_toCurrentPoint.setY(m_toIsAbsolute ? toSeg.targetPoint.y() : m_toCurrentPoint.y() + toSeg.targetPoint.y());
- return blendedSegment;
-}
-
-PathSegmentData SVGPathBlender::blendCurveToCubicSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
-{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
- blendedSegment.point1 = blendAnimatedFloatPoint(fromSeg.point1, toSeg.point1);
- blendedSegment.point2 = blendAnimatedFloatPoint(fromSeg.point2, toSeg.point2);
-
- m_fromCurrentPoint = m_fromIsAbsolute ? fromSeg.targetPoint : m_fromCurrentPoint + fromSeg.targetPoint;
- m_toCurrentPoint = m_toIsAbsolute ? toSeg.targetPoint : m_toCurrentPoint + toSeg.targetPoint;
- return blendedSegment;
-}
-
-PathSegmentData SVGPathBlender::blendCurveToCubicSmoothSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
+bool SVGPathBlender::BlendState::canBlend(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
- blendedSegment.point2 = blendAnimatedFloatPoint(fromSeg.point2, toSeg.point2);
+ // Update state first because we'll need it if we return true below.
+ m_typesAreEqual = fromSeg.command == toSeg.command;
+ m_fromIsAbsolute = isAbsolutePathSegType(fromSeg.command);
- m_fromCurrentPoint = m_fromIsAbsolute ? fromSeg.targetPoint : m_fromCurrentPoint + fromSeg.targetPoint;
- m_toCurrentPoint = m_toIsAbsolute ? toSeg.targetPoint : m_toCurrentPoint + toSeg.targetPoint;
- return blendedSegment;
-}
+ // If the types are equal, they'll blend regardless of parameters.
+ if (m_typesAreEqual)
+ return true;
-PathSegmentData SVGPathBlender::blendCurveToQuadraticSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
-{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
- blendedSegment.point1 = blendAnimatedFloatPoint(fromSeg.point1, toSeg.point1);
+ // Addition require segments with the same type.
+ if (m_addTypesCount)
+ return false;
- m_fromCurrentPoint = m_fromIsAbsolute ? fromSeg.targetPoint : m_fromCurrentPoint + fromSeg.targetPoint;
- m_toCurrentPoint = m_toIsAbsolute ? toSeg.targetPoint : m_toCurrentPoint + toSeg.targetPoint;
- return blendedSegment;
+ // Allow the segments to differ in "relativeness".
+ return toAbsolutePathSegType(fromSeg.command) == toAbsolutePathSegType(toSeg.command);
}
-PathSegmentData SVGPathBlender::blendCurveToQuadraticSmoothSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
+static void updateCurrentPoint(FloatPoint& currentPoint, const PathSegmentData& segment)
{
- PathSegmentData blendedSegment;
- blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
-
- m_fromCurrentPoint = m_fromIsAbsolute ? fromSeg.targetPoint : m_fromCurrentPoint + fromSeg.targetPoint;
- m_toCurrentPoint = m_toIsAbsolute ? toSeg.targetPoint : m_toCurrentPoint + toSeg.targetPoint;
- return blendedSegment;
+ switch (segment.command) {
+ case PathSegMoveToRel:
+ case PathSegLineToRel:
+ case PathSegCurveToCubicRel:
+ case PathSegCurveToQuadraticRel:
+ case PathSegArcRel:
+ case PathSegLineToHorizontalRel:
+ case PathSegLineToVerticalRel:
+ case PathSegCurveToCubicSmoothRel:
+ case PathSegCurveToQuadraticSmoothRel:
+ currentPoint += segment.targetPoint;
+ break;
+ case PathSegMoveToAbs:
+ case PathSegLineToAbs:
+ case PathSegCurveToCubicAbs:
+ case PathSegCurveToQuadraticAbs:
+ case PathSegArcAbs:
+ case PathSegCurveToCubicSmoothAbs:
+ case PathSegCurveToQuadraticSmoothAbs:
+ currentPoint = segment.targetPoint;
+ break;
+ case PathSegLineToHorizontalAbs:
+ currentPoint.setX(segment.targetPoint.x());
+ break;
+ case PathSegLineToVerticalAbs:
+ currentPoint.setY(segment.targetPoint.y());
+ break;
+ case PathSegClosePath:
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
}
-PathSegmentData SVGPathBlender::blendArcToSegment(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
+bool SVGPathBlender::BlendState::blendSegments(const PathSegmentData& fromSeg, const PathSegmentData& toSeg, PathSegmentData& blendedSegment)
{
- ASSERT(!m_addTypesCount || fromSeg.command == toSeg.command);
+ if (!canBlend(fromSeg, toSeg))
+ return false;
- PathSegmentData blendedSegment;
blendedSegment.command = m_isInFirstHalfOfAnimation ? fromSeg.command : toSeg.command;
- blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
- blendedSegment.point1 = blendAnimatedFloatPointSameCoordinates(fromSeg.arcRadii(), toSeg.arcRadii());
- blendedSegment.point2 = blendAnimatedFloatPointSameCoordinates(fromSeg.point2, toSeg.point2);
- if (m_addTypesCount) {
- blendedSegment.arcLarge = fromSeg.arcLarge || toSeg.arcLarge;
- blendedSegment.arcSweep = fromSeg.arcSweep || toSeg.arcSweep;
- } else {
- blendedSegment.arcLarge = m_isInFirstHalfOfAnimation ? fromSeg.arcLarge : toSeg.arcLarge;
- blendedSegment.arcSweep = m_isInFirstHalfOfAnimation ? fromSeg.arcSweep : toSeg.arcSweep;
- }
- m_fromCurrentPoint = m_fromIsAbsolute ? fromSeg.targetPoint : m_fromCurrentPoint + fromSeg.targetPoint;
- m_toCurrentPoint = m_toIsAbsolute ? toSeg.targetPoint : m_toCurrentPoint + toSeg.targetPoint;
- return blendedSegment;
-}
-
-void SVGPathBlender::blendSegments(const PathSegmentData& fromSeg, const PathSegmentData& toSeg)
-{
- PathSegmentData blendedSegment;
switch (toSeg.command) {
+ case PathSegCurveToCubicRel:
+ case PathSegCurveToCubicAbs:
+ blendedSegment.point1 = blendAnimatedFloatPoint(fromSeg.point1, toSeg.point1);
+ /* fall through */
+ case PathSegCurveToCubicSmoothRel:
+ case PathSegCurveToCubicSmoothAbs:
+ blendedSegment.point2 = blendAnimatedFloatPoint(fromSeg.point2, toSeg.point2);
+ /* fall through */
case PathSegMoveToRel:
case PathSegMoveToAbs:
- blendedSegment = blendMoveToSegment(fromSeg, toSeg);
- break;
case PathSegLineToRel:
case PathSegLineToAbs:
- blendedSegment = blendLineToSegment(fromSeg, toSeg);
+ case PathSegCurveToQuadraticSmoothRel:
+ case PathSegCurveToQuadraticSmoothAbs:
+ blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
break;
case PathSegLineToHorizontalRel:
case PathSegLineToHorizontalAbs:
- blendedSegment = blendLineToHorizontalSegment(fromSeg, toSeg);
+ blendedSegment.targetPoint.setX(blendAnimatedDimensonalFloat(fromSeg.targetPoint.x(), toSeg.targetPoint.x(), BlendHorizontal));
break;
case PathSegLineToVerticalRel:
case PathSegLineToVerticalAbs:
- blendedSegment = blendLineToVerticalSegment(fromSeg, toSeg);
+ blendedSegment.targetPoint.setY(blendAnimatedDimensonalFloat(fromSeg.targetPoint.y(), toSeg.targetPoint.y(), BlendVertical));
break;
case PathSegClosePath:
- blendedSegment = toSeg;
- break;
- case PathSegCurveToCubicRel:
- case PathSegCurveToCubicAbs:
- blendedSegment = blendCurveToCubicSegment(fromSeg, toSeg);
- break;
- case PathSegCurveToCubicSmoothRel:
- case PathSegCurveToCubicSmoothAbs:
- blendedSegment = blendCurveToCubicSmoothSegment(fromSeg, toSeg);
break;
case PathSegCurveToQuadraticRel:
case PathSegCurveToQuadraticAbs:
- blendedSegment = blendCurveToQuadraticSegment(fromSeg, toSeg);
- break;
- case PathSegCurveToQuadraticSmoothRel:
- case PathSegCurveToQuadraticSmoothAbs:
- blendedSegment = blendCurveToQuadraticSmoothSegment(fromSeg, toSeg);
+ blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
+ blendedSegment.point1 = blendAnimatedFloatPoint(fromSeg.point1, toSeg.point1);
break;
case PathSegArcRel:
case PathSegArcAbs:
- blendedSegment = blendArcToSegment(fromSeg, toSeg);
+ blendedSegment.targetPoint = blendAnimatedFloatPoint(fromSeg.targetPoint, toSeg.targetPoint);
+ blendedSegment.point1 = blendAnimatedFloatPointSameCoordinates(fromSeg.arcRadii(), toSeg.arcRadii());
+ blendedSegment.point2 = blendAnimatedFloatPointSameCoordinates(fromSeg.point2, toSeg.point2);
+ if (m_addTypesCount) {
+ blendedSegment.arcLarge = fromSeg.arcLarge || toSeg.arcLarge;
+ blendedSegment.arcSweep = fromSeg.arcSweep || toSeg.arcSweep;
+ } else {
+ blendedSegment.arcLarge = m_isInFirstHalfOfAnimation ? fromSeg.arcLarge : toSeg.arcLarge;
+ blendedSegment.arcSweep = m_isInFirstHalfOfAnimation ? fromSeg.arcSweep : toSeg.arcSweep;
+ }
break;
default:
ASSERT_NOT_REACHED();
}
- m_consumer->emitSegment(blendedSegment);
+ updateCurrentPoint(m_fromCurrentPoint, fromSeg);
+ updateCurrentPoint(m_toCurrentPoint, toSeg);
+
+ return true;
+}
+
+SVGPathBlender::SVGPathBlender(SVGPathSource* fromSource, SVGPathSource* toSource, SVGPathConsumer* consumer)
+ : m_fromSource(fromSource)
+ , m_toSource(toSource)
+ , m_consumer(consumer)
+{
+ ASSERT(m_fromSource);
+ ASSERT(m_toSource);
+ ASSERT(m_consumer);
+}
+
+DEFINE_TRACE(SVGPathBlender)
+{
+ visitor->trace(m_fromSource);
+ visitor->trace(m_toSource);
+ visitor->trace(m_consumer);
}
bool SVGPathBlender::addAnimatedPath(unsigned repeatCount)
{
- TemporaryChange<unsigned> change(m_addTypesCount, repeatCount);
- return blendAnimatedPath(0);
+ BlendState blendState(0, repeatCount);
+ return blendAnimatedPath(blendState);
}
bool SVGPathBlender::blendAnimatedPath(float progress)
{
- m_isInFirstHalfOfAnimation = progress < 0.5f;
- m_progress = progress;
+ BlendState blendState(progress);
+ return blendAnimatedPath(blendState);
+}
- bool fromSourceHadData = m_fromSource->hasMoreData();
+bool SVGPathBlender::blendAnimatedPath(BlendState& blendState)
+{
+ bool fromSourceIsEmpty = !m_fromSource->hasMoreData();
while (m_toSource->hasMoreData()) {
PathSegmentData toSeg = m_toSource->parseSegment();
if (toSeg.command == PathSegUnknown)
@@ -309,24 +293,13 @@ bool SVGPathBlender::blendAnimatedPath(float progress)
return false;
}
- m_typesAreEqual = fromSeg.command == toSeg.command;
-
- // If the types are equal, they'll blend regardless of parameters.
- if (!m_typesAreEqual) {
- // Addition require segments with the same type.
- if (m_addTypesCount)
- return false;
- // Allow the segments to differ in "relativeness".
- if (toAbsolutePathSegType(fromSeg.command) != toAbsolutePathSegType(toSeg.command))
- return false;
- }
-
- m_fromIsAbsolute = isAbsolutePathSegType(fromSeg.command);
- m_toIsAbsolute = isAbsolutePathSegType(toSeg.command);
+ PathSegmentData blendedSeg;
+ if (!blendState.blendSegments(fromSeg, toSeg, blendedSeg))
+ return false;
- blendSegments(fromSeg, toSeg);
+ m_consumer->emitSegment(blendedSeg);
- if (!fromSourceHadData)
+ if (fromSourceIsEmpty)
continue;
if (m_fromSource->hasMoreData() != m_toSource->hasMoreData())
return false;
« no previous file with comments | « Source/core/svg/SVGPathBlender.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698