blob: 328f82262c385129629adf617e16e0b2df08598a [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "core/svg/SVGAnimatedNewPropertyAnimator.h"
#include "core/svg/SVGAnimatedColor.h"
#include "core/svg/SVGAnimationElement.h"
#include "core/svg/SVGElementInstance.h"
#include "core/svg/SVGLength.h"
#include "core/svg/SVGLengthList.h"
#include "core/svg/SVGNumber.h"
#include "core/svg/SVGPointList.h"
#include "core/svg/SVGString.h"
namespace WebCore {
SVGAnimatedNewPropertyAnimator::SVGAnimatedNewPropertyAnimator(AnimatedPropertyType type, SVGAnimationElement* animationElement, SVGElement* contextElement)
: SVGAnimatedTypeAnimator(type, animationElement, contextElement)
{
ASSERT(m_animationElement);
ASSERT(m_contextElement);
const QualifiedName& attributeName = m_animationElement->attributeName();
m_animatedProperty = m_contextElement->propertyFromAttribute(attributeName);
if (m_animatedProperty)
ASSERT(m_animatedProperty->type() == m_type);
}
SVGAnimatedNewPropertyAnimator::~SVGAnimatedNewPropertyAnimator()
{
}
PassRefPtr<NewSVGPropertyBase> SVGAnimatedNewPropertyAnimator::createPropertyForAnimation(const String& value)
{
if (isAnimatingSVGDom()) {
ASSERT(m_animatedProperty);
// SVG DOM animVal animation code-path.
return m_animatedProperty->currentValueBase()->cloneForAnimation(value);
}
ASSERT(isAnimatingCSSProperty());
// CSS properties animation code-path.
// Create a basic instance of the corresponding SVG property.
// The instance will not have full context info. (e.g. SVGLengthMode)
switch (m_type) {
case AnimatedColor:
return SVGColorProperty::create(value.isEmpty() ? StyleColor::currentColor() : SVGColor::colorFromRGBColorString(value));
case AnimatedNumber: {
RefPtr<SVGNumber> property = SVGNumber::create();
property->setValueAsString(value, IGNORE_EXCEPTION);
return property.release();
}
case AnimatedLength: {
RefPtr<SVGLength> property = SVGLength::create(LengthModeOther);
property->setValueAsString(value, IGNORE_EXCEPTION);
return property.release();
}
case AnimatedLengthList: {
RefPtr<SVGLengthList> property = SVGLengthList::create(LengthModeOther);
property->setValueAsString(value, IGNORE_EXCEPTION);
return property.release();
}
case AnimatedString: {
RefPtr<SVGString> property = SVGString::create();
property->setValueAsString(value, IGNORE_EXCEPTION);
return property.release();
}
// These types don't appear in the table in SVGElement::cssPropertyToTypeMap() and thus don't need support.
case AnimatedBoolean:
case AnimatedNumberList:
case AnimatedNumberOptionalNumber:
case AnimatedPoint:
case AnimatedPoints:
case AnimatedRect:
ASSERT_NOT_REACHED();
// These properties are not yet migrated to NewProperty implementation. see http://crbug.com/308818
case AnimatedAngle:
case AnimatedEnumeration:
case AnimatedInteger:
case AnimatedIntegerOptionalInteger:
case AnimatedPath:
case AnimatedPreserveAspectRatio:
case AnimatedStringList:
case AnimatedTransformList:
ASSERT_NOT_REACHED();
case AnimatedUnknown:
ASSERT_NOT_REACHED();
};
ASSERT_NOT_REACHED();
return 0;
}
PassOwnPtr<SVGAnimatedType> SVGAnimatedNewPropertyAnimator::constructFromString(const String& value)
{
return SVGAnimatedType::createNewProperty(createPropertyForAnimation(value));
}
namespace {
typedef void (NewSVGAnimatedPropertyBase::*NewSVGAnimatedPropertyMethod)();
void invokeMethodOnAllTargetProperties(const SVGElementAnimatedPropertyList& list, const QualifiedName& attributeName, NewSVGAnimatedPropertyMethod method)
{
SVGElementAnimatedPropertyList::const_iterator it = list.begin();
SVGElementAnimatedPropertyList::const_iterator itEnd = list.end();
for (; it != itEnd; ++it) {
RefPtr<NewSVGAnimatedPropertyBase> animatedProperty = it->element->propertyFromAttribute(attributeName);
if (animatedProperty)
(animatedProperty.get()->*method)();
}
}
void setAnimatedValueOnAllTargetProperties(const SVGElementAnimatedPropertyList& list, const QualifiedName& attributeName, PassRefPtr<NewSVGPropertyBase> passValue)
{
RefPtr<NewSVGPropertyBase> value = passValue;
SVGElementAnimatedPropertyList::const_iterator it = list.begin();
SVGElementAnimatedPropertyList::const_iterator itEnd = list.end();
for (; it != itEnd; ++it) {
RefPtr<NewSVGAnimatedPropertyBase> animatedProperty = it->element->propertyFromAttribute(attributeName);
if (animatedProperty)
animatedProperty->setAnimatedValue(value);
}
}
}
PassRefPtr<NewSVGPropertyBase> SVGAnimatedNewPropertyAnimator::resetAnimation(const SVGElementAnimatedPropertyList& list)
{
ASSERT(isAnimatingSVGDom());
RefPtr<NewSVGPropertyBase> animatedValue = m_animatedProperty->createAnimatedValue();
ASSERT(animatedValue->type() == m_type);
setAnimatedValueOnAllTargetProperties(list, m_animatedProperty->attributeName(), animatedValue);
return animatedValue.release();
}
PassOwnPtr<SVGAnimatedType> SVGAnimatedNewPropertyAnimator::startAnimValAnimation(const SVGElementAnimatedPropertyList& list)
{
ASSERT(isAnimatingSVGDom());
SVGElementInstance::InstanceUpdateBlocker blocker(m_contextElement);
invokeMethodOnAllTargetProperties(list, m_animatedProperty->attributeName(), &NewSVGAnimatedPropertyBase::animationStarted);
return SVGAnimatedType::createNewProperty(resetAnimation(list));
}
void SVGAnimatedNewPropertyAnimator::stopAnimValAnimation(const SVGElementAnimatedPropertyList& list)
{
ASSERT(isAnimatingSVGDom());
SVGElementInstance::InstanceUpdateBlocker blocker(m_contextElement);
invokeMethodOnAllTargetProperties(list, m_animatedProperty->attributeName(), &NewSVGAnimatedPropertyBase::animationEnded);
}
void SVGAnimatedNewPropertyAnimator::resetAnimValToBaseVal(const SVGElementAnimatedPropertyList& list, SVGAnimatedType* animated)
{
SVGElementInstance::InstanceUpdateBlocker blocker(m_contextElement);
animated->newProperty() = resetAnimation(list);
}
void SVGAnimatedNewPropertyAnimator::animValWillChange(const SVGElementAnimatedPropertyList& list)
{
ASSERT(isAnimatingSVGDom());
SVGElementInstance::InstanceUpdateBlocker blocker(m_contextElement);
invokeMethodOnAllTargetProperties(list, m_animatedProperty->attributeName(), &NewSVGAnimatedPropertyBase::animValWillChange);
}
void SVGAnimatedNewPropertyAnimator::animValDidChange(const SVGElementAnimatedPropertyList& list)
{
ASSERT(isAnimatingSVGDom());
SVGElementInstance::InstanceUpdateBlocker blocker(m_contextElement);
invokeMethodOnAllTargetProperties(list, m_animatedProperty->attributeName(), &NewSVGAnimatedPropertyBase::animValDidChange);
}
void SVGAnimatedNewPropertyAnimator::addAnimatedTypes(SVGAnimatedType* from, SVGAnimatedType* to)
{
to->newProperty()->add(from->newProperty(), m_contextElement);
}
class ParsePropertyFromString {
public:
explicit ParsePropertyFromString(SVGAnimatedNewPropertyAnimator* animator)
: m_animator(animator)
{
}
PassRefPtr<NewSVGPropertyBase> operator()(SVGAnimationElement*, const String& value)
{
return m_animator->createPropertyForAnimation(value);
}
private:
SVGAnimatedNewPropertyAnimator* m_animator;
};
void SVGAnimatedNewPropertyAnimator::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGAnimatedType* from, SVGAnimatedType* to, SVGAnimatedType* toAtEndOfDuration, SVGAnimatedType* animated)
{
ASSERT(m_animationElement);
ASSERT(m_contextElement);
RefPtr<NewSVGPropertyBase> fromValue = m_animationElement->animationMode() == ToAnimation ? animated->newProperty() : from->newProperty();
RefPtr<NewSVGPropertyBase> toValue = to->newProperty();
RefPtr<NewSVGPropertyBase> toAtEndOfDurationValue = toAtEndOfDuration->newProperty();
RefPtr<NewSVGPropertyBase> animatedValue = animated->newProperty();
// Apply CSS inheritance rules.
ParsePropertyFromString parsePropertyFromString(this);
m_animationElement->adjustForInheritance<RefPtr<NewSVGPropertyBase>, ParsePropertyFromString>(parsePropertyFromString, m_animationElement->fromPropertyValueType(), fromValue, m_contextElement);
m_animationElement->adjustForInheritance<RefPtr<NewSVGPropertyBase>, ParsePropertyFromString>(parsePropertyFromString, m_animationElement->toPropertyValueType(), toValue, m_contextElement);
animatedValue->calculateAnimatedValue(m_animationElement, percentage, repeatCount, fromValue, toValue, toAtEndOfDurationValue, m_contextElement);
}
float SVGAnimatedNewPropertyAnimator::calculateDistance(const String& fromString, const String& toString)
{
ASSERT(m_animationElement);
ASSERT(m_contextElement);
RefPtr<NewSVGPropertyBase> fromValue = createPropertyForAnimation(fromString);
RefPtr<NewSVGPropertyBase> toValue = createPropertyForAnimation(toString);
return fromValue->calculateDistance(toValue, m_contextElement);
}
} // namespace WebCore