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/SVGNumberList.h"
     23 
     24 #include "core/svg/SVGAnimationElement.h"
     25 #include "core/svg/SVGParserUtilities.h"
     26 #include "wtf/text/StringBuilder.h"
     27 #include "wtf/text/WTFString.h"
     28 
     29 namespace WebCore {
     30 
     31 inline PassRefPtr<SVGNumberList> toSVGNumberList(PassRefPtr<SVGPropertyBase> passBase)
     32 {
     33     RefPtr<SVGPropertyBase> base = passBase;
     34     ASSERT(base->type() == SVGNumberList::classType());
     35     return static_pointer_cast<SVGNumberList>(base.release());
     36 }
     37 
     38 SVGNumberList::SVGNumberList()
     39 {
     40 }
     41 
     42 SVGNumberList::~SVGNumberList()
     43 {
     44 }
     45 
     46 PassRefPtr<SVGNumberList> SVGNumberList::clone()
     47 {
     48     RefPtr<SVGNumberList> svgNumberList = SVGNumberList::create();
     49     svgNumberList->deepCopy(this);
     50     return svgNumberList.release();
     51 }
     52 
     53 PassRefPtr<SVGPropertyBase> SVGNumberList::cloneForAnimation(const String& value) const
     54 {
     55     RefPtr<SVGNumberList> svgNumberList = SVGNumberList::create();
     56     svgNumberList->setValueAsString(value, IGNORE_EXCEPTION);
     57     return svgNumberList.release();
     58 }
     59 
     60 String SVGNumberList::valueAsString() const
     61 {
     62     StringBuilder builder;
     63 
     64     ConstIterator it = begin();
     65     ConstIterator itEnd = end();
     66     if (it != itEnd) {
     67         builder.append(it->valueAsString());
     68         ++it;
     69 
     70         for (; it != itEnd; ++it) {
     71             builder.append(' ');
     72             builder.append(it->valueAsString());
     73         }
     74     }
     75 
     76     return builder.toString();
     77 }
     78 
     79 template <typename CharType>
     80 bool SVGNumberList::parse(const CharType*& ptr, const CharType* end)
     81 {
     82     clear();
     83 
     84     while (ptr < end) {
     85         float number = 0;
     86         if (!parseNumber(ptr, end, number))
     87             return false;
     88         append(SVGNumber::create(number));
     89     }
     90 
     91     return true;
     92 }
     93 
     94 void SVGNumberList::setValueAsString(const String& value, ExceptionState& exceptionState)
     95 {
     96     if (value.isEmpty()) {
     97         clear();
     98         return;
     99     }
    100 
    101     bool valid = false;
    102     if (value.is8Bit()) {
    103         const LChar* ptr = value.characters8();
    104         const LChar* end = ptr + value.length();
    105         valid = parse(ptr, end);
    106     } else {
    107         const UChar* ptr = value.characters16();
    108         const UChar* end = ptr + value.length();
    109         valid = parse(ptr, end);
    110     }
    111 
    112     if (!valid) {
    113         exceptionState.throwDOMException(SyntaxError, "Problem parsing number list \""+value+"\"");
    114         // No call to |clear()| here. SVG policy is to use valid items before error.
    115         // Spec: http://www.w3.org/TR/SVG/single-page.html#implnote-ErrorProcessing
    116     }
    117 }
    118 
    119 void SVGNumberList::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement* contextElement)
    120 {
    121     RefPtr<SVGNumberList> otherList = toSVGNumberList(other);
    122 
    123     if (length() != otherList->length())
    124         return;
    125 
    126     for (size_t i = 0; i < length(); ++i)
    127         at(i)->setValue(at(i)->value() + otherList->at(i)->value());
    128 }
    129 
    130 bool SVGNumberList::adjustFromToListValues(PassRefPtr<SVGNumberList> passFromList, PassRefPtr<SVGNumberList> passToList, float percentage, bool isToAnimation, bool resizeAnimatedListIfNeeded)
    131 {
    132     RefPtr<SVGNumberList> fromList = passFromList;
    133     RefPtr<SVGNumberList> toList = passToList;
    134 
    135     // If no 'to' value is given, nothing to animate.
    136     size_t toListSize = toList->length();
    137     if (!toListSize)
    138         return false;
    139 
    140     // If the 'from' value is given and it's length doesn't match the 'to' value list length, fallback to a discrete animation.
    141     size_t fromListSize = fromList->length();
    142     if (fromListSize != toListSize && fromListSize) {
    143         if (percentage < 0.5) {
    144             if (!isToAnimation)
    145                 deepCopy(fromList);
    146         } else {
    147             deepCopy(toList);
    148         }
    149 
    150         return false;
    151     }
    152 
    153     ASSERT(!fromListSize || fromListSize == toListSize);
    154     if (resizeAnimatedListIfNeeded && length() < toListSize) {
    155         size_t paddingCount = toListSize - length();
    156         for (size_t i = 0; i < paddingCount; ++i)
    157             append(SVGNumber::create());
    158     }
    159 
    160     return true;
    161 }
    162 
    163 void SVGNumberList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtr<SVGPropertyBase> fromValue, PassRefPtr<SVGPropertyBase> toValue, PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement)
    164 {
    165     RefPtr<SVGNumberList> fromList = toSVGNumberList(fromValue);
    166     RefPtr<SVGNumberList> toList = toSVGNumberList(toValue);
    167     RefPtr<SVGNumberList> toAtEndOfDurationList = toSVGNumberList(toAtEndOfDurationValue);
    168 
    169     size_t fromListSize = fromList->length();
    170     size_t toListSize = toList->length();
    171     size_t toAtEndOfDurationListSize = toAtEndOfDurationList->length();
    172 
    173     if (!adjustFromToListValues(fromList, toList, percentage, animationElement->animationMode() == ToAnimation, true))
    174         return;
    175 
    176     for (size_t i = 0; i < toListSize; ++i) {
    177         float effectiveFrom = fromListSize ? fromList->at(i)->value() : 0;
    178         float effectiveTo = toListSize ? toList->at(i)->value() : 0;
    179         float effectiveToAtEnd = i < toAtEndOfDurationListSize ? toAtEndOfDurationList->at(i)->value() : 0;
    180 
    181         float animated = at(i)->value();
    182         animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom, effectiveTo, effectiveToAtEnd, animated);
    183         at(i)->setValue(animated);
    184     }
    185 }
    186 
    187 float SVGNumberList::calculateDistance(PassRefPtr<SVGPropertyBase> to, SVGElement*)
    188 {
    189     // FIXME: Distance calculation is not possible for SVGNumberList right now. We need the distance for every single value.
    190     return -1;
    191 }
    192 
    193 Vector<float> SVGNumberList::toFloatVector() const
    194 {
    195     Vector<float> vec;
    196     vec.reserveInitialCapacity(length());
    197     for (size_t i = 0; i < length(); ++i)
    198         vec.uncheckedAppend(at(i)->value());
    199     return vec;
    200 }
    201 
    202 }
    203