1/*
2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 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/SVGLengthList.h"
23
24#include "bindings/core/v8/ExceptionStatePlaceholder.h"
25#include "core/svg/SVGAnimationElement.h"
26#include "core/svg/SVGParserUtilities.h"
27#include "wtf/text/StringBuilder.h"
28
29namespace blink {
30
31inline 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
38SVGLengthList::SVGLengthList(SVGLengthMode mode)
39    : m_mode(mode)
40{
41}
42
43SVGLengthList::~SVGLengthList()
44{
45}
46
47PassRefPtr<SVGLengthList> SVGLengthList::clone()
48{
49    RefPtr<SVGLengthList> ret = SVGLengthList::create(m_mode);
50    ret->deepCopy(this);
51    return ret.release();
52}
53
54PassRefPtr<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
61String 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
80template <typename CharType>
81void 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
103void 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
120void 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
132PassRefPtr<SVGLength> SVGLengthList::createPaddingItem() const
133{
134    return SVGLength::create(m_mode);
135}
136
137void SVGLengthList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtr<SVGPropertyBase> fromValue, PassRefPtr<SVGPropertyBase> toValue, PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement)
138{
139    RefPtr<SVGLengthList> fromList = toSVGLengthList(fromValue);
140    RefPtr<SVGLengthList> toList = toSVGLengthList(toValue);
141    RefPtr<SVGLengthList> toAtEndOfDurationList = toSVGLengthList(toAtEndOfDurationValue);
142
143    SVGLengthContext lengthContext(contextElement);
144    ASSERT(m_mode == SVGLength::lengthModeForAnimatedLengthAttribute(animationElement->attributeName()));
145
146    size_t fromLengthListSize = fromList->length();
147    size_t toLengthListSize = toList->length();
148    size_t toAtEndOfDurationListSize = toAtEndOfDurationList->length();
149
150    if (!adjustFromToListValues(fromList, toList, percentage, animationElement->animationMode()))
151        return;
152
153    for (size_t i = 0; i < toLengthListSize; ++i) {
154        float animatedNumber = at(i)->value(lengthContext);
155        SVGLengthType unitType = toList->at(i)->unitType();
156        float effectiveFrom = 0;
157        if (fromLengthListSize) {
158            if (percentage < 0.5)
159                unitType = fromList->at(i)->unitType();
160            effectiveFrom = fromList->at(i)->value(lengthContext);
161        }
162        float effectiveTo = toList->at(i)->value(lengthContext);
163        float effectiveToAtEnd = i < toAtEndOfDurationListSize ? toAtEndOfDurationList->at(i)->value(lengthContext) : 0;
164
165        animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom, effectiveTo, effectiveToAtEnd, animatedNumber);
166        at(i)->setUnitType(unitType);
167        at(i)->setValue(animatedNumber, lengthContext, ASSERT_NO_EXCEPTION);
168    }
169}
170
171float SVGLengthList::calculateDistance(PassRefPtr<SVGPropertyBase> to, SVGElement*)
172{
173    // FIXME: Distance calculation is not possible for SVGLengthList right now. We need the distance for every single value.
174    return -1;
175}
176}
177