1/*
2 * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005 Rob Buis <buis@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
30namespace blink {
31
32inline 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
39SVGPointList::SVGPointList()
40{
41}
42
43SVGPointList::~SVGPointList()
44{
45}
46
47String SVGPointList::valueAsString() const
48{
49    StringBuilder builder;
50
51    ConstIterator it = begin();
52    ConstIterator itEnd = end();
53    if (it != itEnd) {
54        builder.append(it->valueAsString());
55        ++it;
56
57        for (; it != itEnd; ++it) {
58            builder.append(' ');
59            builder.append(it->valueAsString());
60        }
61    }
62
63    return builder.toString();
64}
65
66template <typename CharType>
67bool SVGPointList::parse(const CharType*& ptr, const CharType* end)
68{
69    clear();
70
71    skipOptionalSVGSpaces(ptr, end);
72    if (ptr >= end)
73        return true;
74
75    for (;;) {
76        float x = 0.0f;
77        float y = 0.0f;
78        bool valid = parseNumber(ptr, end, x) && parseNumber(ptr, end, y, DisallowWhitespace);
79        if (!valid) {
80            return false;
81        }
82        append(SVGPoint::create(FloatPoint(x, y)));
83
84        skipOptionalSVGSpaces(ptr, end);
85        if (ptr < end && *ptr == ',') {
86            ++ptr;
87            skipOptionalSVGSpaces(ptr, end);
88
89            // ',' requires the list to be continued
90            continue;
91        }
92
93        // check end of list
94        if (ptr >= end)
95            return true;
96    }
97}
98
99void SVGPointList::setValueAsString(const String& value, ExceptionState& exceptionState)
100{
101    if (value.isEmpty()) {
102        clear();
103        return;
104    }
105
106    bool valid = false;
107    if (value.is8Bit()) {
108        const LChar* ptr = value.characters8();
109        const LChar* end = ptr + value.length();
110        valid = parse(ptr, end);
111    } else {
112        const UChar* ptr = value.characters16();
113        const UChar* end = ptr + value.length();
114        valid = parse(ptr, end);
115    }
116
117    if (!valid)
118        exceptionState.throwDOMException(SyntaxError, "Problem parsing points=\""+value+"\"");
119}
120
121void SVGPointList::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement* contextElement)
122{
123    RefPtr<SVGPointList> otherList = toSVGPointList(other);
124
125    if (length() != otherList->length())
126        return;
127
128    for (size_t i = 0; i < length(); ++i)
129        at(i)->setValue(at(i)->value() + otherList->at(i)->value());
130}
131
132void SVGPointList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtr<SVGPropertyBase> fromValue, PassRefPtr<SVGPropertyBase> toValue, PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement)
133{
134    RefPtr<SVGPointList> fromList = toSVGPointList(fromValue);
135    RefPtr<SVGPointList> toList = toSVGPointList(toValue);
136    RefPtr<SVGPointList> toAtEndOfDurationList = toSVGPointList(toAtEndOfDurationValue);
137
138    size_t fromPointListSize = fromList->length();
139    size_t toPointListSize = toList->length();
140    size_t toAtEndOfDurationListSize = toAtEndOfDurationList->length();
141
142    if (!adjustFromToListValues(fromList, toList, percentage, animationElement->animationMode()))
143        return;
144
145    for (size_t i = 0; i < toPointListSize; ++i) {
146        float animatedX = at(i)->x();
147        float animatedY = at(i)->y();
148
149        FloatPoint effectiveFrom;
150        if (fromPointListSize)
151            effectiveFrom = fromList->at(i)->value();
152        FloatPoint effectiveTo = toList->at(i)->value();
153        FloatPoint effectiveToAtEnd;
154        if (i < toAtEndOfDurationListSize)
155            effectiveToAtEnd = toAtEndOfDurationList->at(i)->value();
156
157        animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.x(), effectiveTo.x(), effectiveToAtEnd.x(), animatedX);
158        animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.y(), effectiveTo.y(), effectiveToAtEnd.y(), animatedY);
159        at(i)->setValue(FloatPoint(animatedX, animatedY));
160    }
161}
162
163float SVGPointList::calculateDistance(PassRefPtr<SVGPropertyBase> to, SVGElement*)
164{
165    // FIXME: Distance calculation is not possible for SVGPointList right now. We need the distance for every single value.
166    return -1;
167}
168
169}
170