1 /* 2 * Copyright (C) 2007 David Smith (catfish.man (at) gmail.com) 3 * Copyright (C) 2007, 2008, 2011, 2012 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 * Boston, MA 02111-1307, USA. 19 */ 20 21 #include "config.h" 22 #include "core/dom/SpaceSplitString.h" 23 24 #include "core/html/parser/HTMLParserIdioms.h" 25 #include "wtf/ASCIICType.h" 26 #include "wtf/HashMap.h" 27 #include "wtf/text/AtomicStringHash.h" 28 29 using namespace WTF; 30 31 namespace blink { 32 33 template <typename CharacterType> 34 static inline bool hasNonASCIIOrUpper(const CharacterType* characters, unsigned length) 35 { 36 bool hasUpper = false; 37 CharacterType ored = 0; 38 for (unsigned i = 0; i < length; i++) { 39 CharacterType c = characters[i]; 40 hasUpper |= isASCIIUpper(c); 41 ored |= c; 42 } 43 return hasUpper || (ored & ~0x7F); 44 } 45 46 static inline bool hasNonASCIIOrUpper(const String& string) 47 { 48 unsigned length = string.length(); 49 50 if (string.is8Bit()) 51 return hasNonASCIIOrUpper(string.characters8(), length); 52 return hasNonASCIIOrUpper(string.characters16(), length); 53 } 54 55 template <typename CharacterType> 56 inline void SpaceSplitString::Data::createVector(const CharacterType* characters, unsigned length) 57 { 58 unsigned start = 0; 59 while (true) { 60 while (start < length && isHTMLSpace<CharacterType>(characters[start])) 61 ++start; 62 if (start >= length) 63 break; 64 unsigned end = start + 1; 65 while (end < length && isNotHTMLSpace<CharacterType>(characters[end])) 66 ++end; 67 68 m_vector.append(AtomicString(characters + start, end - start)); 69 70 start = end + 1; 71 } 72 } 73 74 void SpaceSplitString::Data::createVector(const String& string) 75 { 76 unsigned length = string.length(); 77 78 if (string.is8Bit()) { 79 createVector(string.characters8(), length); 80 return; 81 } 82 83 createVector(string.characters16(), length); 84 } 85 86 bool SpaceSplitString::Data::containsAll(Data& other) 87 { 88 if (this == &other) 89 return true; 90 91 size_t thisSize = m_vector.size(); 92 size_t otherSize = other.m_vector.size(); 93 for (size_t i = 0; i < otherSize; ++i) { 94 const AtomicString& name = other.m_vector[i]; 95 size_t j; 96 for (j = 0; j < thisSize; ++j) { 97 if (m_vector[j] == name) 98 break; 99 } 100 if (j == thisSize) 101 return false; 102 } 103 return true; 104 } 105 106 void SpaceSplitString::Data::add(const AtomicString& string) 107 { 108 ASSERT(hasOneRef()); 109 ASSERT(!contains(string)); 110 m_vector.append(string); 111 } 112 113 void SpaceSplitString::Data::remove(unsigned index) 114 { 115 ASSERT(hasOneRef()); 116 m_vector.remove(index); 117 } 118 119 void SpaceSplitString::add(const AtomicString& string) 120 { 121 // FIXME: add() does not allow duplicates but createVector() does. 122 if (contains(string)) 123 return; 124 ensureUnique(); 125 if (m_data) 126 m_data->add(string); 127 } 128 129 bool SpaceSplitString::remove(const AtomicString& string) 130 { 131 if (!m_data) 132 return false; 133 unsigned i = 0; 134 bool changed = false; 135 while (i < m_data->size()) { 136 if ((*m_data)[i] == string) { 137 if (!changed) 138 ensureUnique(); 139 m_data->remove(i); 140 changed = true; 141 continue; 142 } 143 ++i; 144 } 145 return changed; 146 } 147 148 SpaceSplitString::DataMap& SpaceSplitString::sharedDataMap() 149 { 150 DEFINE_STATIC_LOCAL(DataMap, map, ()); 151 return map; 152 } 153 154 void SpaceSplitString::set(const AtomicString& inputString, bool shouldFoldCase) 155 { 156 if (inputString.isNull()) { 157 clear(); 158 return; 159 } 160 161 String string(inputString.string()); 162 if (shouldFoldCase && hasNonASCIIOrUpper(string)) 163 string = string.foldCase(); 164 165 m_data = Data::create(AtomicString(string)); 166 } 167 168 SpaceSplitString::Data::~Data() 169 { 170 if (!m_keyString.isNull()) 171 sharedDataMap().remove(m_keyString); 172 } 173 174 PassRefPtr<SpaceSplitString::Data> SpaceSplitString::Data::create(const AtomicString& string) 175 { 176 Data*& data = sharedDataMap().add(string, 0).storedValue->value; 177 if (!data) { 178 data = new Data(string); 179 return adoptRef(data); 180 } 181 return data; 182 } 183 184 PassRefPtr<SpaceSplitString::Data> SpaceSplitString::Data::createUnique(const Data& other) 185 { 186 return adoptRef(new SpaceSplitString::Data(other)); 187 } 188 189 SpaceSplitString::Data::Data(const AtomicString& string) 190 : m_keyString(string) 191 { 192 ASSERT(!string.isNull()); 193 createVector(string); 194 } 195 196 SpaceSplitString::Data::Data(const SpaceSplitString::Data& other) 197 : RefCounted<Data>() 198 , m_vector(other.m_vector) 199 { 200 // Note that we don't copy m_keyString to indicate to the destructor that there's nothing 201 // to be removed from the sharedDataMap(). 202 } 203 204 } // namespace blink 205