| 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;
|
|
|