Update To 11.40.268.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/core/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 blink {
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.appendLiteral("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     AttributeCollection attributes = m_element->attributes();
158     for (const Attribute& attr : attributes) {
159         if (isValidAttributeName(attr.localName()))
160             names.append(convertAttributeNameToPropertyName(attr.localName()));
161     }
162 }
163
164 String DatasetDOMStringMap::item(const String& name)
165 {
166     AttributeCollection attributes = m_element->attributes();
167     for (const Attribute& attr : attributes) {
168         if (propertyNameMatchesAttributeName(name, attr.localName()))
169             return attr.value();
170     }
171
172     return String();
173 }
174
175 bool DatasetDOMStringMap::contains(const String& name)
176 {
177     AttributeCollection attributes = m_element->attributes();
178     for (const Attribute& attr : attributes) {
179         if (propertyNameMatchesAttributeName(name, attr.localName()))
180             return true;
181     }
182     return false;
183 }
184
185 void DatasetDOMStringMap::setItem(const String& name, const String& value, ExceptionState& exceptionState)
186 {
187     if (!isValidPropertyName(name)) {
188         exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a valid property name.");
189         return;
190     }
191
192     m_element->setAttribute(convertPropertyNameToAttributeName(name), AtomicString(value), exceptionState);
193 }
194
195 bool DatasetDOMStringMap::deleteItem(const String& name)
196 {
197     if (isValidPropertyName(name)) {
198         AtomicString attributeName = convertPropertyNameToAttributeName(name);
199         if (m_element->hasAttribute(attributeName)) {
200             m_element->removeAttribute(attributeName);
201             return true;
202         }
203     }
204     return false;
205 }
206
207 void DatasetDOMStringMap::trace(Visitor* visitor)
208 {
209     visitor->trace(m_element);
210     DOMStringMap::trace(visitor);
211 }
212
213 } // namespace blink