15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2010 Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1.  Redistributions of source code must retain the above copyright
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer in the
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     documentation and/or other materials provided with the distribution.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
268abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)#include "core/dom/DOMTokenList.h"
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
28197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "bindings/core/v8/ExceptionState.h"
2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/ExceptionCode.h"
3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/parser/HTMLParserIdioms.h"
31e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "wtf/text/StringBuilder.h"
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
33c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool DOMTokenList::validateToken(const String& token, ExceptionState& exceptionState)
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (token.isEmpty()) {
38a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        exceptionState.throwDOMException(SyntaxError, "The token provided must not be empty.");
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
429e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)    if (token.find(isHTMLSpace) != kNotFound) {
439e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)        exceptionState.throwDOMException(InvalidCharacterError, "The token provided ('" + token + "') contains HTML space characters, which are not valid in tokens.");
449e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)        return false;
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
50a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)bool DOMTokenList::validateTokens(const Vector<String>& tokens, ExceptionState& exceptionState)
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < tokens.size(); ++i) {
53a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        if (!validateToken(tokens[i], exceptionState))
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DOMTokenList::contains(const AtomicString& token, ExceptionState& exceptionState) const
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
62a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    if (!validateToken(token, exceptionState))
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return containsInternal(token);
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void DOMTokenList::add(const AtomicString& token, ExceptionState& exceptionState)
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<String> tokens;
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tokens.append(token.string());
7151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    add(tokens, exceptionState);
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Optimally, this should take a Vector<AtomicString> const ref in argument but the
7509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// bindings generator does not handle that.
7651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void DOMTokenList::add(const Vector<String>& tokens, ExceptionState& exceptionState)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<String> filteredTokens;
791e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    filteredTokens.reserveCapacity(tokens.size());
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < tokens.size(); ++i) {
81a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        if (!validateToken(tokens[i], exceptionState))
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
8309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (containsInternal(AtomicString(tokens[i])))
841e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            continue;
851e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (filteredTokens.contains(tokens[i]))
861e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            continue;
871e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        filteredTokens.append(tokens[i]);
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (filteredTokens.isEmpty())
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    setValue(addTokens(value(), filteredTokens));
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void DOMTokenList::remove(const AtomicString& token, ExceptionState& exceptionState)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<String> tokens;
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tokens.append(token.string());
10051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    remove(tokens, exceptionState);
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Optimally, this should take a Vector<AtomicString> const ref in argument but the
10409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// bindings generator does not handle that.
10551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void DOMTokenList::remove(const Vector<String>& tokens, ExceptionState& exceptionState)
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
107a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    if (!validateTokens(tokens, exceptionState))
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Check using containsInternal first since it is a lot faster than going
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // through the string character by character.
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool found = false;
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < tokens.size(); ++i) {
11409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (containsInternal(AtomicString(tokens[i]))) {
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            found = true;
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (found)
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        setValue(removeTokens(value(), tokens));
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DOMTokenList::toggle(const AtomicString& token, ExceptionState& exceptionState)
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
126a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    if (!validateToken(token, exceptionState))
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (containsInternal(token)) {
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        removeInternal(token);
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    addInternal(token);
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DOMTokenList::toggle(const AtomicString& token, bool force, ExceptionState& exceptionState)
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
139a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    if (!validateToken(token, exceptionState))
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (force)
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        addInternal(token);
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        removeInternal(token);
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return force;
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DOMTokenList::addInternal(const AtomicString& token)
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!containsInternal(token))
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        setValue(addToken(value(), token));
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DOMTokenList::removeInternal(const AtomicString& token)
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Check using contains first since it uses AtomicString comparisons instead
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // of character by character testing.
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!containsInternal(token))
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    setValue(removeToken(value(), token));
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)AtomicString DOMTokenList::addToken(const AtomicString& input, const AtomicString& token)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<String> tokens;
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tokens.append(token.string());
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return addTokens(input, tokens);
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
17209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// This returns an AtomicString because it is always passed as argument to setValue() and setValue()
17309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// takes an AtomicString in argument.
17409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)AtomicString DOMTokenList::addTokens(const AtomicString& input, const Vector<String>& tokens)
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool needsSpace = false;
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    StringBuilder builder;
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!input.isEmpty()) {
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        builder.append(input);
18106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        needsSpace = !isHTMLSpace<UChar>(input[input.length() - 1]);
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < tokens.size(); ++i) {
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (needsSpace)
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            builder.append(' ');
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        builder.append(tokens[i]);
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        needsSpace = true;
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
19109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return builder.toAtomicString();
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
19409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)AtomicString DOMTokenList::removeToken(const AtomicString& input, const AtomicString& token)
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<String> tokens;
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    tokens.append(token.string());
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return removeTokens(input, tokens);
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
20109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// This returns an AtomicString because it is always passed as argument to setValue() and setValue()
20209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// takes an AtomicString in argument.
20309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)AtomicString DOMTokenList::removeTokens(const AtomicString& input, const Vector<String>& tokens)
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Algorithm defined at http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#remove-a-token-from-a-string
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // New spec is at http://dom.spec.whatwg.org/#remove-a-token-from-a-string
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned inputLength = input.length();
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    StringBuilder output; // 3
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    output.reserveCapacity(inputLength);
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned position = 0; // 4
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Step 5
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (position < inputLength) {
21506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        if (isHTMLSpace<UChar>(input[position])) { // 6
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            output.append(input[position++]); // 6.1, 6.2
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue; // 6.3
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Step 7
2217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        StringBuilder tokenBuilder;
22206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        while (position < inputLength && isNotHTMLSpace<UChar>(input[position]))
2237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            tokenBuilder.append(input[position++]);
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Step 8
2267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        String token = tokenBuilder.toString();
2277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (tokens.contains(token)) {
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Step 8.1
22906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)            while (position < inputLength && isHTMLSpace<UChar>(input[position]))
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ++position;
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Step 8.2
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            size_t j = output.length();
23406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)            while (j > 0 && isHTMLSpace<UChar>(output[j - 1]))
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                --j;
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            output.resize(j);
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Step 8.3
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (position < inputLength && !output.isEmpty())
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                output.append(' ');
2417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        } else {
2427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            output.append(token); // Step 9
2437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
24609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return output.toAtomicString();
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
249c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
250