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/SVGStringList.h"
23
24#include "bindings/core/v8/ExceptionMessages.h"
25#include "core/svg/SVGElement.h"
26#include "core/svg/SVGParserUtilities.h"
27#include "wtf/text/StringBuilder.h"
28
29namespace blink {
30
31SVGStringList::SVGStringList()
32{
33}
34
35SVGStringList::~SVGStringList()
36{
37}
38
39void SVGStringList::initialize(const String& item)
40{
41    m_values.clear();
42    m_values.append(item);
43}
44
45String SVGStringList::getItem(size_t index, ExceptionState& exceptionState)
46{
47    if (!checkIndexBound(index, exceptionState))
48        return String();
49
50    return m_values.at(index);
51}
52
53void SVGStringList::insertItemBefore(const String& newItem, size_t index)
54{
55    // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
56    if (index > m_values.size())
57        index = m_values.size();
58
59    // Spec: Inserts a new item into the list at the specified position. The index of the item before which the new item is to be
60    // inserted. The first item is number 0. If the index is equal to 0, then the new item is inserted at the front of the list.
61    m_values.insert(index, newItem);
62}
63
64String SVGStringList::removeItem(size_t index, ExceptionState& exceptionState)
65{
66    if (!checkIndexBound(index, exceptionState))
67        return String();
68
69    String oldItem = m_values.at(index);
70    m_values.remove(index);
71    return oldItem;
72}
73
74void SVGStringList::appendItem(const String& newItem)
75{
76    m_values.append(newItem);
77}
78
79void SVGStringList::replaceItem(const String& newItem, size_t index, ExceptionState& exceptionState)
80{
81    if (!checkIndexBound(index, exceptionState))
82        return;
83
84    // Update the value at the desired position 'index'.
85    m_values[index] = newItem;
86}
87
88template<typename CharType>
89void SVGStringList::parseInternal(const CharType*& ptr, const CharType* end)
90{
91    const UChar delimiter = ' ';
92
93    while (ptr < end) {
94        const CharType* start = ptr;
95        while (ptr < end && *ptr != delimiter && !isHTMLSpace<CharType>(*ptr))
96            ptr++;
97        if (ptr == start)
98            break;
99        m_values.append(String(start, ptr - start));
100        skipOptionalSVGSpacesOrDelimiter(ptr, end, delimiter);
101    }
102}
103
104void SVGStringList::setValueAsString(const String& data, ExceptionState&)
105{
106    // FIXME: Add more error checking and reporting.
107    m_values.clear();
108    if (data.isEmpty())
109        return;
110    if (data.is8Bit()) {
111        const LChar* ptr = data.characters8();
112        const LChar* end = ptr + data.length();
113        parseInternal(ptr, end);
114    } else {
115        const UChar* ptr = data.characters16();
116        const UChar* end = ptr + data.length();
117        parseInternal(ptr, end);
118    }
119}
120
121String SVGStringList::valueAsString() const
122{
123    StringBuilder builder;
124
125    Vector<String>::const_iterator it = m_values.begin();
126    Vector<String>::const_iterator itEnd = m_values.end();
127    if (it != itEnd) {
128        builder.append(*it);
129        ++it;
130
131        for (; it != itEnd; ++it) {
132            builder.append(' ');
133            builder.append(*it);
134        }
135    }
136
137    return builder.toString();
138}
139
140bool SVGStringList::checkIndexBound(size_t index, ExceptionState& exceptionState)
141{
142    if (index >= m_values.size()) {
143        exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("index", index, m_values.size()));
144        return false;
145    }
146
147    return true;
148}
149
150void SVGStringList::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement* contextElement)
151{
152    // SVGStringList is never animated.
153    ASSERT_NOT_REACHED();
154}
155
156void SVGStringList::calculateAnimatedValue(SVGAnimationElement*, float, unsigned, PassRefPtr<SVGPropertyBase>, PassRefPtr<SVGPropertyBase>, PassRefPtr<SVGPropertyBase>, SVGElement*)
157{
158    // SVGStringList is never animated.
159    ASSERT_NOT_REACHED();
160}
161
162float SVGStringList::calculateDistance(PassRefPtr<SVGPropertyBase>, SVGElement*)
163{
164    // SVGStringList is never animated.
165    ASSERT_NOT_REACHED();
166
167    return -1.0f;
168}
169
170}
171