Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005 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/SVGPointList.h"
     23 
     24 #include "core/svg/SVGAnimationElement.h"
     25 #include "core/svg/SVGParserUtilities.h"
     26 #include "platform/geometry/FloatPoint.h"
     27 #include "wtf/text/StringBuilder.h"
     28 #include "wtf/text/WTFString.h"
     29 
     30 namespace WebCore {
     31 
     32 inline PassRefPtr<SVGPointList> toSVGPointList(PassRefPtr<SVGPropertyBase> passBase)
     33 {
     34     RefPtr<SVGPropertyBase> base = passBase;
     35     ASSERT(base->type() == SVGPointList::classType());
     36     return static_pointer_cast<SVGPointList>(base.release());
     37 }
     38 
     39 SVGPointList::SVGPointList()
     40 {
     41 }
     42 
     43 SVGPointList::~SVGPointList()
     44 {
     45 }
     46 
     47 PassRefPtr<SVGPointList> SVGPointList::clone()
     48 {
     49     RefPtr<SVGPointList> svgPointList = SVGPointList::create();
     50     svgPointList->deepCopy(this);
     51     return svgPointList.release();
     52 }
     53 
     54 PassRefPtr<SVGPropertyBase> SVGPointList::cloneForAnimation(const String& value) const
     55 {
     56     RefPtr<SVGPointList> svgPointList = SVGPointList::create();
     57     svgPointList->setValueAsString(value, IGNORE_EXCEPTION);
     58     return svgPointList.release();
     59 }
     60 
     61 String SVGPointList::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 bool SVGPointList::parse(const CharType*& ptr, const CharType* end)
     82 {
     83     clear();
     84 
     85     skipOptionalSVGSpaces(ptr, end);
     86     if (ptr >= end)
     87         return true;
     88 
     89     for (;;) {
     90         float x = 0.0f;
     91         float y = 0.0f;
     92         bool valid = parseNumber(ptr, end, x) && parseNumber(ptr, end, y, DisallowWhitespace);
     93         if (!valid) {
     94             return false;
     95         }
     96         append(SVGPoint::create(FloatPoint(x, y)));
     97 
     98         skipOptionalSVGSpaces(ptr, end);
     99         if (ptr < end && *ptr == ',') {
    100             ++ptr;
    101             skipOptionalSVGSpaces(ptr, end);
    102 
    103             // ',' requires the list to be continued
    104             continue;
    105         }
    106 
    107         // check end of list
    108         if (ptr >= end)
    109             return true;
    110     }
    111 }
    112 
    113 void SVGPointList::setValueAsString(const String& value, ExceptionState& exceptionState)
    114 {
    115     if (value.isEmpty()) {
    116         clear();
    117         return;
    118     }
    119 
    120     bool valid = false;
    121     if (value.is8Bit()) {
    122         const LChar* ptr = value.characters8();
    123         const LChar* end = ptr + value.length();
    124         valid = parse(ptr, end);
    125     } else {
    126         const UChar* ptr = value.characters16();
    127         const UChar* end = ptr + value.length();
    128         valid = parse(ptr, end);
    129     }
    130 
    131     if (!valid)
    132         exceptionState.throwDOMException(SyntaxError, "Problem parsing points=\""+value+"\"");
    133 }
    134 
    135 void SVGPointList::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement* contextElement)
    136 {
    137     RefPtr<SVGPointList> otherList = toSVGPointList(other);
    138 
    139     if (length() != otherList->length())
    140         return;
    141 
    142     for (size_t i = 0; i < length(); ++i)
    143         at(i)->setValue(at(i)->value() + otherList->at(i)->value());
    144 }
    145 
    146 bool SVGPointList::adjustFromToListValues(PassRefPtr<SVGPointList> passFromList, PassRefPtr<SVGPointList> passToList, float percentage, bool isToAnimation, bool resizeAnimatedListIfNeeded)
    147 {
    148     RefPtr<SVGPointList> fromList = passFromList;
    149     RefPtr<SVGPointList> toList = passToList;
    150 
    151     // If no 'to' value is given, nothing to animate.
    152     size_t toListSize = toList->length();
    153     if (!toListSize)
    154         return false;
    155 
    156     // If the 'from' value is given and it's length doesn't match the 'to' value list length, fallback to a discrete animation.
    157     size_t fromListSize = fromList->length();
    158     if (fromListSize != toListSize && fromListSize) {
    159         if (percentage < 0.5) {
    160             if (!isToAnimation)
    161                 deepCopy(fromList);
    162         } else {
    163             deepCopy(toList);
    164         }
    165 
    166         return false;
    167     }
    168 
    169     ASSERT(!fromListSize || fromListSize == toListSize);
    170     if (resizeAnimatedListIfNeeded && length() < toListSize) {
    171         size_t paddingCount = toListSize - length();
    172         for (size_t i = 0; i < paddingCount; ++i)
    173             append(SVGPoint::create());
    174     }
    175 
    176     return true;
    177 }
    178 
    179 void SVGPointList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtr<SVGPropertyBase> fromValue, PassRefPtr<SVGPropertyBase> toValue, PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement)
    180 {
    181     RefPtr<SVGPointList> fromList = toSVGPointList(fromValue);
    182     RefPtr<SVGPointList> toList = toSVGPointList(toValue);
    183     RefPtr<SVGPointList> toAtEndOfDurationList = toSVGPointList(toAtEndOfDurationValue);
    184 
    185     size_t fromPointListSize = fromList->length();
    186     size_t toPointListSize = toList->length();
    187     size_t toAtEndOfDurationListSize = toAtEndOfDurationList->length();
    188 
    189     if (!adjustFromToListValues(fromList, toList, percentage, animationElement->animationMode() == ToAnimation, true))
    190         return;
    191 
    192     for (size_t i = 0; i < toPointListSize; ++i) {
    193         float animatedX = at(i)->x();
    194         float animatedY = at(i)->y();
    195 
    196         FloatPoint effectiveFrom;
    197         if (fromPointListSize)
    198             effectiveFrom = fromList->at(i)->value();
    199         FloatPoint effectiveTo = toList->at(i)->value();
    200         FloatPoint effectiveToAtEnd;
    201         if (i < toAtEndOfDurationListSize)
    202             effectiveToAtEnd = toAtEndOfDurationList->at(i)->value();
    203 
    204         animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.x(), effectiveTo.x(), effectiveToAtEnd.x(), animatedX);
    205         animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.y(), effectiveTo.y(), effectiveToAtEnd.y(), animatedY);
    206         at(i)->setValue(FloatPoint(animatedX, animatedY));
    207     }
    208 }
    209 
    210 float SVGPointList::calculateDistance(PassRefPtr<SVGPropertyBase> to, SVGElement*)
    211 {
    212     // FIXME: Distance calculation is not possible for SVGPointList right now. We need the distance for every single value.
    213     return -1;
    214 }
    215 
    216 }
    217