bool addToSVGPathByteStream(SVGPathByteStream& fromStream, const SVGPathByteStream& byStream, unsigned repeatCount)
{
    if (fromStream.isEmpty() || byStream.isEmpty())
        return true;

    OwnPtr<SVGPathByteStream> fromStreamCopy = fromStream.copy();
    fromStream.clear();

    SVGPathByteStreamBuilder builder(fromStream);
    SVGPathByteStreamSource fromSource(*fromStreamCopy);
    SVGPathByteStreamSource bySource(byStream);
    SVGPathBlender blender(&fromSource, &bySource, &builder);
    return blender.addAnimatedPath(repeatCount);
}
bool addToSVGPathByteStream(SVGPathByteStream& streamToAppendTo, const SVGPathByteStream& byStream, unsigned repeatCount)
{
    // Why return when streamToAppendTo is empty? Don't we still need to append?
    if (streamToAppendTo.isEmpty() || byStream.isEmpty())
        return true;

    // Is it OK to make the SVGPathByteStreamBuilder from a stream, and then clear that stream?
    SVGPathByteStreamBuilder builder(streamToAppendTo);

    SVGPathByteStream fromStreamCopy = streamToAppendTo;
    streamToAppendTo.clear();

    SVGPathByteStreamSource fromSource(fromStreamCopy);
    SVGPathByteStreamSource bySource(byStream);
    return SVGPathBlender::addAnimatedPath(fromSource, bySource, builder, repeatCount);
}
bool buildStringFromByteStream(const SVGPathByteStream& stream, String& result, PathParsingMode parsingMode)
{
    if (stream.isEmpty())
        return true;

    SVGPathByteStreamSource source(stream);
    return SVGPathParser::parseToString(source, result, parsingMode);
}
bool buildSVGPathSegListFromByteStream(const SVGPathByteStream& stream, SVGPathElement& element, SVGPathSegList& result, PathParsingMode parsingMode)
{
    if (stream.isEmpty())
        return true;

    SVGPathSegListBuilder builder(element, result, parsingMode == NormalizedParsing ? PathSegNormalizedRole : PathSegUnalteredRole);
    SVGPathByteStreamSource source(stream);
    return SVGPathParser::parse(source, builder, parsingMode);
}
bool buildPathFromByteStream(const SVGPathByteStream& stream, Path& result)
{
    if (stream.isEmpty())
        return true;

    SVGPathBuilder builder(result);
    SVGPathByteStreamSource source(stream);
    return SVGPathParser::parse(source, builder);
}
bool buildPathFromByteStream(const SVGPathByteStream& stream, Path& result)
{
    if (stream.isEmpty())
        return true;

    SVGPathBuilder builder(result);
    SVGPathByteStreamSource source(stream);
    SVGPathParser parser(&source, &builder);
    return parser.parsePathDataFromSource(NormalizedParsing);
}
FloatPoint getPointAtLengthOfSVGPathByteStream(const SVGPathByteStream& stream, float length)
{
    if (stream.isEmpty())
        return FloatPoint();

    SVGPathTraversalStateBuilder builder(PathTraversalState::TraversalPointAtLength, length);
    SVGPathByteStreamSource source(stream);
    SVGPathParser parser(&source, &builder);
    parser.parsePathDataFromSource(NormalizedParsing);
    return builder.currentPoint();
}
float getTotalLengthOfSVGPathByteStream(const SVGPathByteStream& stream)
{
    if (stream.isEmpty())
        return 0;

    SVGPathTraversalStateBuilder builder(PathTraversalState::TraversalTotalLength);
    SVGPathByteStreamSource source(stream);
    SVGPathParser parser(&source, &builder);
    parser.parsePathDataFromSource(NormalizedParsing);
    return builder.totalLength();
}
unsigned getSVGPathSegAtLengthFromSVGPathByteStream(const SVGPathByteStream& stream, float length)
{
    if (stream.isEmpty())
        return 0;

    SVGPathTraversalStateBuilder builder(PathTraversalState::TraversalSegmentAtLength, length);
    SVGPathByteStreamSource source(stream);
    SVGPathParser parser(&source, &builder);
    parser.parsePathDataFromSource(NormalizedParsing);
    return builder.pathSegmentIndex();
}
bool buildStringFromByteStream(const SVGPathByteStream& stream, String& result, PathParsingMode parsingMode)
{
    if (stream.isEmpty())
        return true;

    SVGPathStringBuilder builder;
    SVGPathByteStreamSource source(stream);
    SVGPathParser parser(&source, &builder);
    bool ok = parser.parsePathDataFromSource(parsingMode);
    result = builder.result();
    return ok;
}
bool getSVGPathSegAtLengthFromSVGPathByteStream(const SVGPathByteStream& stream, float length, unsigned& pathSeg)
{
    if (stream.isEmpty())
        return false;

    PathTraversalState traversalState(PathTraversalState::Action::SegmentAtLength);
    SVGPathTraversalStateBuilder builder(traversalState, length);

    SVGPathByteStreamSource source(stream);
    bool ok = SVGPathParser::parse(source, builder);
    pathSeg = builder.pathSegmentIndex();
    return ok;
}
bool buildAnimatedSVGPathByteStream(const SVGPathByteStream& fromStream, const SVGPathByteStream& toStream, SVGPathByteStream& result, float progress)
{
    ASSERT(&toStream != &result);
    result.clear();
    if (toStream.isEmpty())
        return true;

    SVGPathByteStreamBuilder builder(result);

    SVGPathByteStreamSource fromSource(fromStream);
    SVGPathByteStreamSource toSource(toStream);
    return SVGPathBlender::blendAnimatedPath(fromSource, toSource, builder, progress);
}
bool getPointAtLengthOfSVGPathByteStream(const SVGPathByteStream& stream, float length, SVGPoint& point)
{
    if (stream.isEmpty())
        return false;

    PathTraversalState traversalState(PathTraversalState::Action::VectorAtLength);

    SVGPathTraversalStateBuilder builder(traversalState, length);

    SVGPathByteStreamSource source(stream);
    bool ok = SVGPathParser::parse(source, builder);
    point = builder.currentPoint();
    return ok;
}
bool getTotalLengthOfSVGPathByteStream(const SVGPathByteStream& stream, float& totalLength)
{
    if (stream.isEmpty())
        return false;

    PathTraversalState traversalState(PathTraversalState::Action::TotalLength);

    SVGPathTraversalStateBuilder builder(traversalState);

    SVGPathByteStreamSource source(stream);
    bool ok = SVGPathParser::parse(source, builder);
    totalLength = builder.totalLength();
    return ok;
}