blob: 187fc290bbd9ae6834da15cec5185c027adf09f3 [file] [log] [blame]
/*
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann
* <zimmermann@kde.org>
* Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
* 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 "core/svg/SVGPath.h"
#include "core/SVGNames.h"
#include "core/svg/SVGAnimationElement.h"
#include "core/svg/SVGPathBlender.h"
#include "core/svg/SVGPathByteStream.h"
#include "core/svg/SVGPathByteStreamBuilder.h"
#include "core/svg/SVGPathByteStreamSource.h"
#include "core/svg/SVGPathUtilities.h"
#include "platform/graphics/Path.h"
#include <memory>
namespace blink {
namespace {
std::unique_ptr<SVGPathByteStream> blendPathByteStreams(
const SVGPathByteStream& fromStream,
const SVGPathByteStream& toStream,
float progress) {
std::unique_ptr<SVGPathByteStream> resultStream = SVGPathByteStream::create();
SVGPathByteStreamBuilder builder(*resultStream);
SVGPathByteStreamSource fromSource(fromStream);
SVGPathByteStreamSource toSource(toStream);
SVGPathBlender blender(&fromSource, &toSource, &builder);
blender.blendAnimatedPath(progress);
return resultStream;
}
std::unique_ptr<SVGPathByteStream> addPathByteStreams(
const SVGPathByteStream& fromStream,
const SVGPathByteStream& byStream,
unsigned repeatCount = 1) {
std::unique_ptr<SVGPathByteStream> resultStream = SVGPathByteStream::create();
SVGPathByteStreamBuilder builder(*resultStream);
SVGPathByteStreamSource fromSource(fromStream);
SVGPathByteStreamSource bySource(byStream);
SVGPathBlender blender(&fromSource, &bySource, &builder);
blender.addAnimatedPath(repeatCount);
return resultStream;
}
std::unique_ptr<SVGPathByteStream> conditionallyAddPathByteStreams(
std::unique_ptr<SVGPathByteStream> fromStream,
const SVGPathByteStream& byStream,
unsigned repeatCount = 1) {
if (fromStream->isEmpty() || byStream.isEmpty())
return fromStream;
return addPathByteStreams(*fromStream, byStream, repeatCount);
}
} // namespace
SVGPath::SVGPath() : m_pathValue(CSSPathValue::emptyPathValue()) {}
SVGPath::SVGPath(CSSPathValue* pathValue) : m_pathValue(pathValue) {
ASSERT(m_pathValue);
}
SVGPath::~SVGPath() {}
String SVGPath::valueAsString() const {
return buildStringFromByteStream(byteStream());
}
SVGPath* SVGPath::clone() const {
return SVGPath::create(m_pathValue);
}
SVGParsingError SVGPath::setValueAsString(const String& string) {
std::unique_ptr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
SVGParsingError parseStatus = buildByteStreamFromString(string, *byteStream);
m_pathValue = CSSPathValue::create(std::move(byteStream));
return parseStatus;
}
SVGPropertyBase* SVGPath::cloneForAnimation(const String& value) const {
std::unique_ptr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
buildByteStreamFromString(value, *byteStream);
return SVGPath::create(CSSPathValue::create(std::move(byteStream)));
}
void SVGPath::add(SVGPropertyBase* other, SVGElement*) {
const SVGPathByteStream& otherPathByteStream = toSVGPath(other)->byteStream();
if (byteStream().size() != otherPathByteStream.size() ||
byteStream().isEmpty() || otherPathByteStream.isEmpty())
return;
m_pathValue = CSSPathValue::create(
addPathByteStreams(byteStream(), otherPathByteStream));
}
void SVGPath::calculateAnimatedValue(SVGAnimationElement* animationElement,
float percentage,
unsigned repeatCount,
SVGPropertyBase* fromValue,
SVGPropertyBase* toValue,
SVGPropertyBase* toAtEndOfDurationValue,
SVGElement*) {
ASSERT(animationElement);
bool isToAnimation = animationElement->getAnimationMode() == ToAnimation;
const SVGPath& to = toSVGPath(*toValue);
const SVGPathByteStream& toStream = to.byteStream();
// If no 'to' value is given, nothing to animate.
if (!toStream.size())
return;
const SVGPath& from = toSVGPath(*fromValue);
const SVGPathByteStream* fromStream = &from.byteStream();
std::unique_ptr<SVGPathByteStream> copy;
if (isToAnimation) {
copy = byteStream().clone();
fromStream = copy.get();
}
// If the 'from' value is given and it's length doesn't match the 'to' value
// list length, fallback to a discrete animation.
if (fromStream->size() != toStream.size() && fromStream->size()) {
if (percentage < 0.5) {
if (!isToAnimation) {
m_pathValue = from.pathValue();
return;
}
} else {
m_pathValue = to.pathValue();
return;
}
}
std::unique_ptr<SVGPathByteStream> newStream =
blendPathByteStreams(*fromStream, toStream, percentage);
// Handle additive='sum'.
if (animationElement->isAdditive() && !isToAnimation)
newStream =
conditionallyAddPathByteStreams(std::move(newStream), byteStream());
// Handle accumulate='sum'.
if (animationElement->isAccumulated() && repeatCount)
newStream = conditionallyAddPathByteStreams(
std::move(newStream), toSVGPath(toAtEndOfDurationValue)->byteStream(),
repeatCount);
m_pathValue = CSSPathValue::create(std::move(newStream));
}
float SVGPath::calculateDistance(SVGPropertyBase* to, SVGElement*) {
// FIXME: Support paced animations.
return -1;
}
DEFINE_TRACE(SVGPath) {
visitor->trace(m_pathValue);
SVGPropertyBase::trace(visitor);
}
} // namespace blink