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/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"
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
];
59 if (character
!= '-') {
60 stringBuilder
.append(character
);
62 if ((i
+ 1 < length
) && isASCIILower(name
[i
+ 1])) {
63 stringBuilder
.append(toASCIIUpper(name
[i
+ 1]));
66 stringBuilder
.append(character
);
71 return stringBuilder
.toString();
74 template<typename CharType1
, typename CharType2
>
75 static bool propertyNameMatchesAttributeName(const CharType1
* propertyName
, const CharType2
* attributeName
, unsigned propertyLength
, unsigned attributeLength
)
79 bool wordBoundary
= false;
80 while (a
< attributeLength
&& p
< propertyLength
) {
81 if (attributeName
[a
] == '-' && a
+ 1 < attributeLength
&& isASCIILower(attributeName
[a
+ 1])) {
84 if ((wordBoundary
? toASCIIUpper(attributeName
[a
]) : attributeName
[a
]) != propertyName
[p
])
92 return (a
== attributeLength
&& p
== propertyLength
);
95 static bool propertyNameMatchesAttributeName(const String
& propertyName
, const String
& attributeName
)
97 if (!attributeName
.startsWith("data-"))
100 unsigned propertyLength
= propertyName
.length();
101 unsigned attributeLength
= attributeName
.length();
103 if (propertyName
.is8Bit()) {
104 if (attributeName
.is8Bit())
105 return propertyNameMatchesAttributeName(propertyName
.characters8(), attributeName
.characters8(), propertyLength
, attributeLength
);
106 return propertyNameMatchesAttributeName(propertyName
.characters8(), attributeName
.characters16(), propertyLength
, attributeLength
);
109 if (attributeName
.is8Bit())
110 return propertyNameMatchesAttributeName(propertyName
.characters16(), attributeName
.characters8(), propertyLength
, attributeLength
);
111 return propertyNameMatchesAttributeName(propertyName
.characters16(), attributeName
.characters16(), propertyLength
, attributeLength
);
114 static bool isValidPropertyName(const String
& name
)
116 unsigned length
= name
.length();
117 for (unsigned i
= 0; i
< length
; ++i
) {
118 if (name
[i
] == '-' && (i
+ 1 < length
) && isASCIILower(name
[i
+ 1]))
124 // This returns an AtomicString because attribute names are always stored
125 // as AtomicString types in Element (see setAttribute()).
126 static AtomicString
convertPropertyNameToAttributeName(const String
& name
)
128 StringBuilder builder
;
129 builder
.appendLiteral("data-");
131 unsigned length
= name
.length();
132 for (unsigned i
= 0; i
< length
; ++i
) {
133 UChar character
= name
[i
];
134 if (isASCIIUpper(character
)) {
136 builder
.append(toASCIILower(character
));
138 builder
.append(character
);
142 return builder
.toAtomicString();
146 void DatasetDOMStringMap::ref()
151 void DatasetDOMStringMap::deref()
157 void DatasetDOMStringMap::getNames(Vector
<String
>& names
)
159 AttributeCollection attributes
= m_element
->attributes();
160 for (const Attribute
& attr
: attributes
) {
161 if (isValidAttributeName(attr
.localName()))
162 names
.append(convertAttributeNameToPropertyName(attr
.localName()));
166 String
DatasetDOMStringMap::item(const String
& name
)
168 AttributeCollection attributes
= m_element
->attributes();
169 for (const Attribute
& attr
: attributes
) {
170 if (propertyNameMatchesAttributeName(name
, attr
.localName()))
177 bool DatasetDOMStringMap::contains(const String
& name
)
179 AttributeCollection attributes
= m_element
->attributes();
180 for (const Attribute
& attr
: attributes
) {
181 if (propertyNameMatchesAttributeName(name
, attr
.localName()))
187 void DatasetDOMStringMap::setItem(const String
& name
, const String
& value
, ExceptionState
& exceptionState
)
189 if (!isValidPropertyName(name
)) {
190 exceptionState
.throwDOMException(SyntaxError
, "'" + name
+ "' is not a valid property name.");
194 m_element
->setAttribute(convertPropertyNameToAttributeName(name
), AtomicString(value
), exceptionState
);
197 bool DatasetDOMStringMap::deleteItem(const String
& name
)
199 if (isValidPropertyName(name
)) {
200 AtomicString attributeName
= convertPropertyNameToAttributeName(name
);
201 if (m_element
->hasAttribute(attributeName
)) {
202 m_element
->removeAttribute(attributeName
);
209 DEFINE_TRACE(DatasetDOMStringMap
)
211 visitor
->trace(m_element
);
212 DOMStringMap::trace(visitor
);