summaryrefslogtreecommitdiffstats
path: root/WebCore/html/DOMTokenList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/DOMTokenList.cpp')
-rw-r--r--WebCore/html/DOMTokenList.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/WebCore/html/DOMTokenList.cpp b/WebCore/html/DOMTokenList.cpp
new file mode 100644
index 0000000..8ee45a2
--- /dev/null
+++ b/WebCore/html/DOMTokenList.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2010, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DOMTokenList.h"
+
+#include "Element.h"
+#include "HTMLNames.h"
+#include "SpaceSplitString.h"
+#include "StringBuilder.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static bool validateToken(const AtomicString& token, ExceptionCode& ec)
+{
+ if (token.isEmpty()) {
+ ec = SYNTAX_ERR;
+ return false;
+ }
+
+ unsigned length = token.length();
+ for (unsigned i = 0; i < length; ++i) {
+ if (isClassWhitespace(token[i])) {
+ ec = INVALID_CHARACTER_ERR;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+DOMTokenList::DOMTokenList(Element* element)
+ : m_element(element)
+{
+ if (m_element->document()->inQuirksMode())
+ m_classNamesForQuirksMode.set(m_element->fastGetAttribute(classAttr), false);
+}
+
+void DOMTokenList::ref()
+{
+ m_element->ref();
+}
+
+void DOMTokenList::deref()
+{
+ m_element->deref();
+}
+
+unsigned DOMTokenList::length() const
+{
+ return classNames().size();
+}
+
+const AtomicString DOMTokenList::item(unsigned index) const
+{
+ if (index >= length())
+ return AtomicString();
+ return classNames()[index];
+}
+
+bool DOMTokenList::contains(const AtomicString& token, ExceptionCode& ec) const
+{
+ if (!validateToken(token, ec))
+ return false;
+ return containsInternal(token);
+}
+
+bool DOMTokenList::containsInternal(const AtomicString& token) const
+{
+ return classNames().contains(token);
+}
+
+void DOMTokenList::add(const AtomicString& token, ExceptionCode& ec)
+{
+ if (!validateToken(token, ec))
+ return;
+ addInternal(token);
+}
+
+void DOMTokenList::addInternal(const AtomicString& token) const
+{
+ const AtomicString& oldClassName(m_element->fastGetAttribute(classAttr));
+ if (oldClassName.isEmpty())
+ m_element->setAttribute(classAttr, token);
+ else if (!containsInternal(token)) {
+ StringBuilder builder;
+ builder.append(oldClassName);
+ if (oldClassName[oldClassName.length() - 1] != ' ')
+ builder.append(' ');
+ builder.append(token);
+ m_element->setAttribute(classAttr, builder.toString());
+ }
+}
+
+void DOMTokenList::remove(const AtomicString& token, ExceptionCode& ec)
+{
+ if (!validateToken(token, ec))
+ return;
+ removeInternal(token);
+}
+
+void DOMTokenList::removeInternal(const AtomicString& token) const
+{
+ // Check using contains first since it uses AtomicString comparisons instead
+ // of character by character testing.
+ if (!containsInternal(token))
+ return;
+
+ // Algorithm defined at http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#remove-a-token-from-a-string
+
+ const AtomicString& input = m_element->fastGetAttribute(classAttr);
+ unsigned inputLength = input.length();
+ Vector<UChar> output; // 3
+ output.reserveCapacity(inputLength);
+ unsigned position = 0; // 4
+
+ // Step 5
+ while (position < inputLength) {
+ if (isClassWhitespace(input[position])) { // 6
+ output.append(input[position++]); // 6.1, 6.2
+ continue; // 6.3
+ }
+
+ // Step 7
+ Vector<UChar> s;
+ while (position < inputLength && !isClassWhitespace(input[position]))
+ s.append(input[position++]);
+
+ // Step 8
+ if (s == token) {
+ // Step 8.1
+ while (position < inputLength && isClassWhitespace(input[position]))
+ ++position;
+
+ // Step 8.2
+ size_t j = output.size();
+ while (j > 0 && isClassWhitespace(output[j - 1]))
+ --j;
+ output.resize(j);
+
+ // Step 8.3
+ if (position < inputLength && !output.isEmpty())
+ output.append(' ');
+ } else
+ output.append(s); // Step 9
+ }
+
+ output.shrinkToFit();
+ m_element->setAttribute(classAttr, String::adopt(output));
+}
+
+bool DOMTokenList::toggle(const AtomicString& token, ExceptionCode& ec)
+{
+ if (!validateToken(token, ec))
+ return false;
+
+ if (containsInternal(token)) {
+ removeInternal(token);
+ return false;
+ }
+ addInternal(token);
+ return true;
+}
+
+String DOMTokenList::toString() const
+{
+ return m_element->fastGetAttribute(classAttr);
+}
+
+void DOMTokenList::reset(const String& newClassName)
+{
+ if (!m_classNamesForQuirksMode.isNull())
+ m_classNamesForQuirksMode.set(newClassName, false);
+}
+
+const SpaceSplitString& DOMTokenList::classNames() const
+{
+ if (!m_classNamesForQuirksMode.isNull())
+ return m_classNamesForQuirksMode;
+ return m_element->attributeMap()->classNames();
+}
+
+} // namespace WebCore