Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
      3  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  */
     20 
     21 #include "config.h"
     22 #include "core/svg/SVGAnimatedTypeAnimator.h"
     23 
     24 #include "core/css/parser/CSSParser.h"
     25 #include "core/svg/SVGAnimateTransformElement.h"
     26 #include "core/svg/SVGAnimatedColor.h"
     27 #include "core/svg/SVGAnimationElement.h"
     28 #include "core/svg/SVGElement.h"
     29 #include "core/svg/SVGLength.h"
     30 #include "core/svg/SVGLengthList.h"
     31 #include "core/svg/SVGNumber.h"
     32 #include "core/svg/SVGPointList.h"
     33 #include "core/svg/SVGString.h"
     34 #include "core/svg/SVGTransformList.h"
     35 
     36 namespace blink {
     37 
     38 SVGAnimatedTypeAnimator::SVGAnimatedTypeAnimator(SVGAnimationElement* animationElement, SVGElement* contextElement)
     39     : m_animationElement(animationElement)
     40     , m_contextElement(contextElement)
     41 {
     42     ASSERT(m_animationElement);
     43     ASSERT(m_contextElement);
     44 
     45     const QualifiedName& attributeName = m_animationElement->attributeName();
     46     m_animatedProperty = m_contextElement->propertyFromAttribute(attributeName);
     47     m_type = m_animatedProperty ? m_animatedProperty->type()
     48         : SVGElement::animatedPropertyTypeForCSSAttribute(attributeName);
     49 
     50     // Only <animateTransform> is allowed to animate AnimatedTransformList.
     51     // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties
     52     if (m_type == AnimatedTransformList && !isSVGAnimateTransformElement(*animationElement))
     53         m_type = AnimatedUnknown;
     54 
     55     ASSERT(m_type != AnimatedPoint
     56         && m_type != AnimatedStringList
     57         && m_type != AnimatedTransform);
     58 }
     59 
     60 SVGAnimatedTypeAnimator::~SVGAnimatedTypeAnimator()
     61 {
     62 }
     63 
     64 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::createPropertyForAnimation(const String& value)
     65 {
     66     if (isAnimatingSVGDom()) {
     67         // SVG DOM animVal animation code-path.
     68 
     69         if (m_type == AnimatedTransformList) {
     70             // TransformList must be animated via <animateTransform>,
     71             // and its {from,by,to} attribute values needs to be parsed w.r.t. its "type" attribute.
     72             // Spec: http://www.w3.org/TR/SVG/single-page.html#animate-AnimateTransformElement
     73             ASSERT(m_animationElement);
     74             SVGTransformType transformType = toSVGAnimateTransformElement(m_animationElement)->transformType();
     75             return SVGTransformList::create(transformType, value);
     76         }
     77 
     78         ASSERT(m_animatedProperty);
     79         return m_animatedProperty->currentValueBase()->cloneForAnimation(value);
     80     }
     81 
     82     ASSERT(isAnimatingCSSProperty());
     83 
     84     // CSS properties animation code-path.
     85     // Create a basic instance of the corresponding SVG property.
     86     // The instance will not have full context info. (e.g. SVGLengthMode)
     87 
     88     switch (m_type) {
     89     case AnimatedColor:
     90         return SVGColorProperty::create(value.isEmpty() ? StyleColor::currentColor() : CSSParser::colorFromRGBColorString(value));
     91     case AnimatedNumber: {
     92         RefPtr<SVGNumber> property = SVGNumber::create();
     93         property->setValueAsString(value, IGNORE_EXCEPTION);
     94         return property.release();
     95     }
     96     case AnimatedLength: {
     97         RefPtr<SVGLength> property = SVGLength::create(LengthModeOther);
     98         property->setValueAsString(value, IGNORE_EXCEPTION);
     99         return property.release();
    100     }
    101     case AnimatedLengthList: {
    102         RefPtr<SVGLengthList> property = SVGLengthList::create(LengthModeOther);
    103         property->setValueAsString(value, IGNORE_EXCEPTION);
    104         return property.release();
    105     }
    106     case AnimatedString: {
    107         RefPtr<SVGString> property = SVGString::create();
    108         property->setValueAsString(value, IGNORE_EXCEPTION);
    109         return property.release();
    110     }
    111 
    112     // These types don't appear in the table in SVGElement::animatedPropertyTypeForCSSAttribute() and thus don't need support.
    113     case AnimatedAngle:
    114     case AnimatedBoolean:
    115     case AnimatedEnumeration:
    116     case AnimatedInteger:
    117     case AnimatedIntegerOptionalInteger:
    118     case AnimatedNumberList:
    119     case AnimatedNumberOptionalNumber:
    120     case AnimatedPath:
    121     case AnimatedPoint:
    122     case AnimatedPoints:
    123     case AnimatedPreserveAspectRatio:
    124     case AnimatedRect:
    125     case AnimatedStringList:
    126     case AnimatedTransform:
    127     case AnimatedTransformList:
    128         ASSERT_NOT_REACHED();
    129 
    130     case AnimatedUnknown:
    131         ASSERT_NOT_REACHED();
    132     };
    133 
    134     ASSERT_NOT_REACHED();
    135     return nullptr;
    136 }
    137 
    138 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::constructFromString(const String& value)
    139 {
    140     return createPropertyForAnimation(value);
    141 }
    142 
    143 void SVGAnimatedTypeAnimator::calculateFromAndToValues(RefPtr<SVGPropertyBase>& from, RefPtr<SVGPropertyBase>& to, const String& fromString, const String& toString)
    144 {
    145     from = constructFromString(fromString);
    146     to = constructFromString(toString);
    147 }
    148 
    149 void SVGAnimatedTypeAnimator::calculateFromAndByValues(RefPtr<SVGPropertyBase>& from, RefPtr<SVGPropertyBase>& to, const String& fromString, const String& byString)
    150 {
    151     from = constructFromString(fromString);
    152     to = constructFromString(byString);
    153     // FIXME(oilpan): Below .get() should be removed after transition types are gone.
    154     to->add(from.get(), m_contextElement);
    155 }
    156 
    157 namespace {
    158 
    159 void setAnimatedValueOnAllTargetProperties(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list, const QualifiedName& attributeName, PassRefPtr<SVGPropertyBase> passValue)
    160 {
    161     RefPtr<SVGPropertyBase> value = passValue;
    162 
    163     WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator it = list.begin();
    164     WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator itEnd = list.end();
    165     for (; it != itEnd; ++it) {
    166         RefPtr<SVGAnimatedPropertyBase> animatedProperty = (*it)->propertyFromAttribute(attributeName);
    167         if (animatedProperty)
    168             animatedProperty->setAnimatedValue(value);
    169     }
    170 }
    171 
    172 }
    173 
    174 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::resetAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
    175 {
    176     ASSERT(isAnimatingSVGDom());
    177     RefPtr<SVGPropertyBase> animatedValue = m_animatedProperty->createAnimatedValue();
    178     ASSERT(animatedValue->type() == m_type);
    179     setAnimatedValueOnAllTargetProperties(list, m_animatedProperty->attributeName(), animatedValue);
    180 
    181     return animatedValue.release();
    182 }
    183 
    184 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::startAnimValAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
    185 {
    186     ASSERT(isAnimatingSVGDom());
    187     SVGElement::InstanceUpdateBlocker blocker(m_contextElement);
    188 
    189     return resetAnimation(list);
    190 }
    191 
    192 void SVGAnimatedTypeAnimator::stopAnimValAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
    193 {
    194     ASSERT(isAnimatingSVGDom());
    195     SVGElement::InstanceUpdateBlocker blocker(m_contextElement);
    196 
    197     WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator it = list.begin();
    198     WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator itEnd = list.end();
    199     for (; it != itEnd; ++it) {
    200         RefPtr<SVGAnimatedPropertyBase> animatedProperty = (*it)->propertyFromAttribute(m_animatedProperty->attributeName());
    201         if (animatedProperty)
    202             animatedProperty->animationEnded();
    203     }
    204 }
    205 
    206 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::resetAnimValToBaseVal(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
    207 {
    208     SVGElement::InstanceUpdateBlocker blocker(m_contextElement);
    209 
    210     return resetAnimation(list);
    211 }
    212 
    213 class ParsePropertyFromString {
    214 public:
    215     explicit ParsePropertyFromString(SVGAnimatedTypeAnimator* animator)
    216         : m_animator(animator)
    217     {
    218     }
    219 
    220     PassRefPtr<SVGPropertyBase> operator()(SVGAnimationElement*, const String& value)
    221     {
    222         return m_animator->createPropertyForAnimation(value);
    223     }
    224 
    225 private:
    226     SVGAnimatedTypeAnimator* m_animator;
    227 };
    228 
    229 void SVGAnimatedTypeAnimator::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGPropertyBase* from, SVGPropertyBase* to, SVGPropertyBase* toAtEndOfDuration, SVGPropertyBase* animated)
    230 {
    231     ASSERT(m_animationElement);
    232     ASSERT(m_contextElement);
    233 
    234     RefPtr<SVGPropertyBase> fromValue = m_animationElement->animationMode() == ToAnimation ? animated : from;
    235     RefPtr<SVGPropertyBase> toValue = to;
    236     RefPtr<SVGPropertyBase> toAtEndOfDurationValue = toAtEndOfDuration;
    237     RefPtr<SVGPropertyBase> animatedValue = animated;
    238 
    239     // Apply CSS inheritance rules.
    240     ParsePropertyFromString parsePropertyFromString(this);
    241     m_animationElement->adjustForInheritance<RefPtr<SVGPropertyBase>, ParsePropertyFromString>(parsePropertyFromString, m_animationElement->fromPropertyValueType(), fromValue, m_contextElement);
    242     m_animationElement->adjustForInheritance<RefPtr<SVGPropertyBase>, ParsePropertyFromString>(parsePropertyFromString, m_animationElement->toPropertyValueType(), toValue, m_contextElement);
    243 
    244     animatedValue->calculateAnimatedValue(m_animationElement, percentage, repeatCount, fromValue, toValue, toAtEndOfDurationValue, m_contextElement);
    245 }
    246 
    247 float SVGAnimatedTypeAnimator::calculateDistance(const String& fromString, const String& toString)
    248 {
    249     ASSERT(m_animationElement);
    250     ASSERT(m_contextElement);
    251     RefPtr<SVGPropertyBase> fromValue = createPropertyForAnimation(fromString);
    252     RefPtr<SVGPropertyBase> toValue = createPropertyForAnimation(toString);
    253     return fromValue->calculateDistance(toValue, m_contextElement);
    254 }
    255 
    256 void SVGAnimatedTypeAnimator::trace(Visitor* visitor)
    257 {
    258     visitor->trace(m_animationElement);
    259     visitor->trace(m_contextElement);
    260 }
    261 
    262 }
    263