Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / DatasetDOMStringMap.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "core/dom/DatasetDOMStringMap.h"
28
29 #include "bindings/v8/ExceptionState.h"
30 #include "core/dom/Attribute.h"
31 #include "core/dom/Element.h"
32 #include "core/dom/ExceptionCode.h"
33 #include "wtf/ASCIICType.h"
34 #include "wtf/text/StringBuilder.h"
35
36 namespace WebCore {
37
38 static bool isValidAttributeName(const String& name)
39 {
40     if (!name.startsWith("data-"))
41         return false;
42
43     unsigned length = name.length();
44     for (unsigned i = 5; i < length; ++i) {
45         if (isASCIIUpper(name[i]))
46             return false;
47     }
48
49     return true;
50 }
51
52 static String convertAttributeNameToPropertyName(const String& name)
53 {
54     StringBuilder stringBuilder;
55
56     unsigned length = name.length();
57     for (unsigned i = 5; i < length; ++i) {
58         UChar character = name[i];
59         if (character != '-')
60             stringBuilder.append(character);
61         else {
62             if ((i + 1 < length) && isASCIILower(name[i + 1])) {
63                 stringBuilder.append(toASCIIUpper(name[i + 1]));
64                 ++i;
65             } else
66                 stringBuilder.append(character);
67         }
68     }
69
70     return stringBuilder.toString();
71 }
72
73 template<typename CharType1, typename CharType2>
74 static bool propertyNameMatchesAttributeName(const CharType1* propertyName, const CharType2* attributeName, unsigned propertyLength, unsigned attributeLength)
75 {
76     unsigned a = 5;
77     unsigned p = 0;
78     bool wordBoundary = false;
79     while (a < attributeLength && p < propertyLength) {
80         if (attributeName[a] == '-' && a + 1 < attributeLength && isASCIILower(attributeName[a + 1]))
81             wordBoundary = true;
82         else {
83             if ((wordBoundary ? toASCIIUpper(attributeName[a]) : attributeName[a]) != propertyName[p])
84                 return false;
85             p++;
86             wordBoundary = false;
87         }
88         a++;
89     }
90
91     return (a == attributeLength && p == propertyLength);
92 }
93
94 static bool propertyNameMatchesAttributeName(const String& propertyName, const String& attributeName)
95 {
96     if (!attributeName.startsWith("data-"))
97         return false;
98
99     unsigned propertyLength = propertyName.length();
100     unsigned attributeLength = attributeName.length();
101
102     if (propertyName.is8Bit()) {
103         if (attributeName.is8Bit())
104             return propertyNameMatchesAttributeName(propertyName.characters8(), attributeName.characters8(), propertyLength, attributeLength);
105         return propertyNameMatchesAttributeName(propertyName.characters8(), attributeName.characters16(), propertyLength, attributeLength);
106     }
107
108     if (attributeName.is8Bit())
109         return propertyNameMatchesAttributeName(propertyName.characters16(), attributeName.characters8(), propertyLength, attributeLength);
110     return propertyNameMatchesAttributeName(propertyName.characters16(), attributeName.characters16(), propertyLength, attributeLength);
111 }
112
113 static bool isValidPropertyName(const String& name)
114 {
115     unsigned length = name.length();
116     for (unsigned i = 0; i < length; ++i) {
117         if (name[i] == '-' && (i + 1 < length) && isASCIILower(name[i + 1]))
118             return false;
119     }
120     return true;
121 }
122
123 // This returns an AtomicString because attribute names are always stored
124 // as AtomicString types in Element (see setAttribute()).
125 static AtomicString convertPropertyNameToAttributeName(const String& name)
126 {
127     StringBuilder builder;
128     builder.append("data-");
129
130     unsigned length = name.length();
131     for (unsigned i = 0; i < length; ++i) {
132         UChar character = name[i];
133         if (isASCIIUpper(character)) {
134             builder.append('-');
135             builder.append(toASCIILower(character));
136         } else
137             builder.append(character);
138     }
139
140     return builder.toAtomicString();
141 }
142
143 #if !ENABLE(OILPAN)
144 void DatasetDOMStringMap::ref()
145 {
146     m_element->ref();
147 }
148
149 void DatasetDOMStringMap::deref()
150 {
151     m_element->deref();
152 }
153 #endif
154
155 void DatasetDOMStringMap::getNames(Vector<String>& names)
156 {
157     if (!m_element->hasAttributes())
158         return;
159
160     unsigned length = m_element->attributeCount();
161     for (unsigned i = 0; i < length; i++) {
162         const Attribute& attribute = m_element->attributeItem(i);
163         if (isValidAttributeName(attribute.localName()))
164             names.append(convertAttributeNameToPropertyName(attribute.localName()));
165     }
166 }
167
168 String DatasetDOMStringMap::item(const String& name)
169 {
170     if (!m_element->hasAttributes())
171         return String();
172
173     unsigned length = m_element->attributeCount();
174     for (unsigned i = 0; i < length; i++) {
175         const Attribute& attribute = m_element->attributeItem(i);
176         if (propertyNameMatchesAttributeName(name, attribute.localName()))
177             return attribute.value();
178     }
179
180     return String();
181 }
182
183 bool DatasetDOMStringMap::contains(const String& name)
184 {
185     if (!m_element->hasAttributes())
186         return false;
187
188     unsigned length = m_element->attributeCount();
189     for (unsigned i = 0; i < length; i++) {
190         const Attribute& attribute = m_element->attributeItem(i);
191         if (propertyNameMatchesAttributeName(name, attribute.localName()))
192             return true;
193     }
194
195     return false;
196 }
197
198 void DatasetDOMStringMap::setItem(const String& name, const String& value, ExceptionState& exceptionState)
199 {
200     if (!isValidPropertyName(name)) {
201         exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a valid property name.");
202         return;
203     }
204
205     m_element->setAttribute(convertPropertyNameToAttributeName(name), AtomicString(value), exceptionState);
206 }
207
208 bool DatasetDOMStringMap::deleteItem(const String& name)
209 {
210     if (isValidPropertyName(name)) {
211         AtomicString attributeName = convertPropertyNameToAttributeName(name);
212         if (m_element->hasAttribute(attributeName)) {
213             m_element->removeAttribute(attributeName);
214             return true;
215         }
216     }
217     return false;
218 }
219
220 void DatasetDOMStringMap::trace(Visitor* visitor)
221 {
222     visitor->trace(m_element);
223     DOMStringMap::trace(visitor);
224 }
225
226 } // namespace WebCore