2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "core/dom/DatasetDOMStringMap.h"
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"
38 static bool isValidAttributeName(const String& name)
40 if (!name.startsWith("data-"))
43 unsigned length = name.length();
44 for (unsigned i = 5; i < length; ++i) {
45 if (isASCIIUpper(name[i]))
52 static String convertAttributeNameToPropertyName(const String& name)
54 StringBuilder stringBuilder;
56 unsigned length = name.length();
57 for (unsigned i = 5; i < length; ++i) {
58 UChar character = name[i];
60 stringBuilder.append(character);
62 if ((i + 1 < length) && isASCIILower(name[i + 1])) {
63 stringBuilder.append(toASCIIUpper(name[i + 1]));
66 stringBuilder.append(character);
70 return stringBuilder.toString();
73 template<typename CharType1, typename CharType2>
74 static bool propertyNameMatchesAttributeName(const CharType1* propertyName, const CharType2* attributeName, unsigned propertyLength, unsigned attributeLength)
78 bool wordBoundary = false;
79 while (a < attributeLength && p < propertyLength) {
80 if (attributeName[a] == '-' && a + 1 < attributeLength && isASCIILower(attributeName[a + 1]))
83 if ((wordBoundary ? toASCIIUpper(attributeName[a]) : attributeName[a]) != propertyName[p])
91 return (a == attributeLength && p == propertyLength);
94 static bool propertyNameMatchesAttributeName(const String& propertyName, const String& attributeName)
96 if (!attributeName.startsWith("data-"))
99 unsigned propertyLength = propertyName.length();
100 unsigned attributeLength = attributeName.length();
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);
108 if (attributeName.is8Bit())
109 return propertyNameMatchesAttributeName(propertyName.characters16(), attributeName.characters8(), propertyLength, attributeLength);
110 return propertyNameMatchesAttributeName(propertyName.characters16(), attributeName.characters16(), propertyLength, attributeLength);
113 static bool isValidPropertyName(const String& name)
115 unsigned length = name.length();
116 for (unsigned i = 0; i < length; ++i) {
117 if (name[i] == '-' && (i + 1 < length) && isASCIILower(name[i + 1]))
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)
127 StringBuilder builder;
128 builder.append("data-");
130 unsigned length = name.length();
131 for (unsigned i = 0; i < length; ++i) {
132 UChar character = name[i];
133 if (isASCIIUpper(character)) {
135 builder.append(toASCIILower(character));
137 builder.append(character);
140 return builder.toAtomicString();
144 void DatasetDOMStringMap::ref()
149 void DatasetDOMStringMap::deref()
155 void DatasetDOMStringMap::getNames(Vector<String>& names)
157 if (!m_element->hasAttributes())
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()));
168 String DatasetDOMStringMap::item(const String& name)
170 if (!m_element->hasAttributes())
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();
183 bool DatasetDOMStringMap::contains(const String& name)
185 if (!m_element->hasAttributes())
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()))
198 void DatasetDOMStringMap::setItem(const String& name, const String& value, ExceptionState& exceptionState)
200 if (!isValidPropertyName(name)) {
201 exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a valid property name.");
205 m_element->setAttribute(convertPropertyNameToAttributeName(name), AtomicString(value), exceptionState);
208 bool DatasetDOMStringMap::deleteItem(const String& name)
210 if (isValidPropertyName(name)) {
211 AtomicString attributeName = convertPropertyNameToAttributeName(name);
212 if (m_element->hasAttribute(attributeName)) {
213 m_element->removeAttribute(attributeName);
220 void DatasetDOMStringMap::trace(Visitor* visitor)
222 visitor->trace(m_element);
223 DOMStringMap::trace(visitor);
226 } // namespace WebCore