Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis (at) kde.org>
      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/SVGLengthList.h"
     23 
     24 #include "bindings/v8/ExceptionStatePlaceholder.h"
     25 #include "core/svg/SVGAnimationElement.h"
     26 #include "core/svg/SVGParserUtilities.h"
     27 #include "wtf/text/StringBuilder.h"
     28 
     29 namespace WebCore {
     30 
     31 inline PassRefPtr<SVGLengthList> toSVGLengthList(PassRefPtr<SVGPropertyBase> passBase)
     32 {
     33     RefPtr<SVGPropertyBase> base = passBase;
     34     ASSERT(base->type() == SVGLengthList::classType());
     35     return static_pointer_cast<SVGLengthList>(base.release());
     36 }
     37 
     38 SVGLengthList::SVGLengthList(SVGLengthMode mode)
     39     : m_mode(mode)
     40 {
     41 }
     42 
     43 SVGLengthList::~SVGLengthList()
     44 {
     45 }
     46 
     47 PassRefPtr<SVGLengthList> SVGLengthList::clone()
     48 {
     49     RefPtr<SVGLengthList> ret = SVGLengthList::create(m_mode);
     50     ret->deepCopy(this);
     51     return ret.release();
     52 }
     53 
     54 PassRefPtr<SVGPropertyBase> SVGLengthList::cloneForAnimation(const String& value) const
     55 {
     56     RefPtr<SVGLengthList> ret = SVGLengthList::create(m_mode);
     57     ret->setValueAsString(value, IGNORE_EXCEPTION);
     58     return ret.release();
     59 }
     60 
     61 String SVGLengthList::valueAsString() const
     62 {
     63     StringBuilder builder;
     64 
     65     ConstIterator it = begin();
     66     ConstIterator itEnd = end();
     67     if (it != itEnd) {
     68         builder.append(it->valueAsString());
     69         ++it;
     70 
     71         for (; it != itEnd; ++it) {
     72             builder.append(' ');
     73             builder.append(it->valueAsString());
     74         }
     75     }
     76 
     77     return builder.toString();
     78 }
     79 
     80 template <typename CharType>
     81 void SVGLengthList::parseInternal(const CharType*& ptr, const CharType* end, ExceptionState& exceptionState)
     82 {
     83     clear();
     84     while (ptr < end) {
     85         const CharType* start = ptr;
     86         while (ptr < end && *ptr != ',' && !isHTMLSpace<CharType>(*ptr))
     87             ptr++;
     88         if (ptr == start)
     89             break;
     90 
     91         RefPtr<SVGLength> length = SVGLength::create(m_mode);
     92         String valueString(start, ptr - start);
     93         if (valueString.isEmpty())
     94             return;
     95         length->setValueAsString(valueString, exceptionState);
     96         if (exceptionState.hadException())
     97             return;
     98         append(length);
     99         skipOptionalSVGSpacesOrDelimiter(ptr, end);
    100     }
    101 }
    102 
    103 void SVGLengthList::setValueAsString(const String& value, ExceptionState& exceptionState)
    104 {
    105     if (value.isEmpty()) {
    106         clear();
    107         return;
    108     }
    109     if (value.is8Bit()) {
    110         const LChar* ptr = value.characters8();
    111         const LChar* end = ptr + value.length();
    112         parseInternal(ptr, end, exceptionState);
    113     } else {
    114         const UChar* ptr = value.characters16();
    115         const UChar* end = ptr + value.length();
    116         parseInternal(ptr, end, exceptionState);
    117     }
    118 }
    119 
    120 void SVGLengthList::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement* contextElement)
    121 {
    122     RefPtr<SVGLengthList> otherList = toSVGLengthList(other);
    123 
    124     if (length() != otherList->length())
    125         return;
    126 
    127     SVGLengthContext lengthContext(contextElement);
    128     for (size_t i = 0; i < length(); ++i)
    129         at(i)->setValue(at(i)->value(lengthContext) + otherList->at(i)->value(lengthContext), lengthContext, ASSERT_NO_EXCEPTION);
    130 }
    131 
    132 bool SVGLengthList::adjustFromToListValues(PassRefPtr<SVGLengthList> passFromList, PassRefPtr<SVGLengthList> passToList, float percentage, bool isToAnimation, bool resizeAnimatedListIfNeeded)
    133 {
    134     RefPtr<SVGLengthList> fromList = passFromList;
    135     RefPtr<SVGLengthList> toList = passToList;
    136 
    137     // If no 'to' value is given, nothing to animate.
    138     size_t toListSize = toList->length();
    139     if (!toListSize)
    140         return false;
    141 
    142     // If the 'from' value is given and it's length doesn't match the 'to' value list length, fallback to a discrete animation.
    143     size_t fromListSize = fromList->length();
    144     if (fromListSize != toListSize && fromListSize) {
    145         if (percentage < 0.5) {
    146             if (!isToAnimation)
    147                 deepCopy(fromList);
    148         } else {
    149             deepCopy(toList);
    150         }
    151 
    152         return false;
    153     }
    154 
    155     ASSERT(!fromListSize || fromListSize == toListSize);
    156     if (resizeAnimatedListIfNeeded && length() < toListSize) {
    157         size_t paddingCount = toListSize - length();
    158         for (size_t i = 0; i < paddingCount; ++i)
    159             append(SVGLength::create(m_mode));
    160     }
    161 
    162     return true;
    163 }
    164 
    165 void SVGLengthList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtr<SVGPropertyBase> fromValue, PassRefPtr<SVGPropertyBase> toValue, PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement)
    166 {
    167     RefPtr<SVGLengthList> fromList = toSVGLengthList(fromValue);
    168     RefPtr<SVGLengthList> toList = toSVGLengthList(toValue);
    169     RefPtr<SVGLengthList> toAtEndOfDurationList = toSVGLengthList(toAtEndOfDurationValue);
    170 
    171     SVGLengthContext lengthContext(contextElement);
    172     ASSERT(m_mode == SVGLength::lengthModeForAnimatedLengthAttribute(animationElement->attributeName()));
    173 
    174     size_t fromLengthListSize = fromList->length();
    175     size_t toLengthListSize = toList->length();
    176     size_t toAtEndOfDurationListSize = toAtEndOfDurationList->length();
    177 
    178     if (!adjustFromToListValues(fromList, toList, percentage, animationElement->animationMode() == ToAnimation, true))
    179         return;
    180 
    181     for (size_t i = 0; i < toLengthListSize; ++i) {
    182         float animatedNumber = at(i)->value(lengthContext);
    183         SVGLengthType unitType = toList->at(i)->unitType();
    184         float effectiveFrom = 0;
    185         if (fromLengthListSize) {
    186             if (percentage < 0.5)
    187                 unitType = fromList->at(i)->unitType();
    188             effectiveFrom = fromList->at(i)->value(lengthContext);
    189         }
    190         float effectiveTo = toList->at(i)->value(lengthContext);
    191         float effectiveToAtEnd = i < toAtEndOfDurationListSize ? toAtEndOfDurationList->at(i)->value(lengthContext) : 0;
    192 
    193         animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom, effectiveTo, effectiveToAtEnd, animatedNumber);
    194         at(i)->setUnitType(unitType);
    195         at(i)->setValue(animatedNumber, lengthContext, ASSERT_NO_EXCEPTION);
    196     }
    197 }
    198 
    199 float SVGLengthList::calculateDistance(PassRefPtr<SVGPropertyBase> to, SVGElement*)
    200 {
    201     // FIXME: Distance calculation is not possible for SVGLengthList right now. We need the distance for every single value.
    202     return -1;
    203 }
    204 }
    205