Changeset 181525 in webkit
- Timestamp:
- Mar 15, 2015, 11:51:44 PM (11 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 14 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/selectors/attribute-endswith-value-matching-is-ascii-case-insensitive-expected.txt (added)
-
LayoutTests/fast/selectors/attribute-endswith-value-matching-is-ascii-case-insensitive.html (added)
-
LayoutTests/fast/selectors/attribute-hyphen-value-matching-is-ascii-case-insensitive-expected.txt (added)
-
LayoutTests/fast/selectors/attribute-hyphen-value-matching-is-ascii-case-insensitive.html (added)
-
LayoutTests/fast/selectors/attribute-startswith-value-matching-is-ascii-case-insensitive-expected.txt (added)
-
LayoutTests/fast/selectors/attribute-startswith-value-matching-is-ascii-case-insensitive.html (added)
-
Source/WTF/ChangeLog (modified) (1 diff)
-
Source/WTF/wtf/text/AtomicString.h (modified) (2 diffs)
-
Source/WTF/wtf/text/StringCommon.h (modified) (3 diffs)
-
Source/WTF/wtf/text/StringImpl.cpp (modified) (5 diffs)
-
Source/WTF/wtf/text/StringImpl.h (modified) (3 diffs)
-
Source/WTF/wtf/text/StringView.cpp (modified) (1 diff)
-
Source/WTF/wtf/text/StringView.h (modified) (2 diffs)
-
Source/WTF/wtf/text/WTFString.h (modified) (2 diffs)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/css/SelectorChecker.cpp (modified) (2 diffs)
-
Source/WebCore/cssjit/SelectorCompiler.cpp (modified) (4 diffs)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r181522 r181525 1 2015-03-15 Benjamin Poulain <benjamin@webkit.org> 2 3 CSS: fix the case-insensitive matching of the attribute selectors Begin, End and Hyphen 4 https://bugs.webkit.org/show_bug.cgi?id=142715 5 6 Reviewed by Brent Fulgham. 7 8 * fast/selectors/attribute-endswith-value-matching-is-ascii-case-insensitive-expected.txt: Added. 9 * fast/selectors/attribute-endswith-value-matching-is-ascii-case-insensitive.html: Added. 10 * fast/selectors/attribute-hyphen-value-matching-is-ascii-case-insensitive-expected.txt: Added. 11 * fast/selectors/attribute-hyphen-value-matching-is-ascii-case-insensitive.html: Added. 12 * fast/selectors/attribute-startswith-value-matching-is-ascii-case-insensitive-expected.txt: Added. 13 * fast/selectors/attribute-startswith-value-matching-is-ascii-case-insensitive.html: Added. 14 1 15 2015-03-15 Brent Fulgham <bfulgham@apple.com> 2 16 -
trunk/Source/WTF/ChangeLog
r181512 r181525 1 2015-03-15 Benjamin Poulain <benjamin@webkit.org> 2 3 CSS: fix the case-insensitive matching of the attribute selectors Begin, End and Hyphen 4 https://bugs.webkit.org/show_bug.cgi?id=142715 5 6 Reviewed by Brent Fulgham. 7 8 Add the necessary infrastructure to test startsWith() and endsWith() with 9 ASCII case-insentive comparisons. 10 11 * wtf/text/AtomicString.h: 12 (WTF::AtomicString::startsWith): 13 (WTF::AtomicString::startsWithIgnoringASCIICase): 14 (WTF::AtomicString::endsWith): 15 (WTF::AtomicString::endsWithIgnoringASCIICase): 16 17 * wtf/text/StringCommon.h: 18 (WTF::loadUnaligned): 19 (WTF::equal): 20 I moved the low level equal() code from StringImpl to StringCommon 21 since it is used by both StringImpl and StringView. 22 23 (WTF::equalCommon): 24 (WTF::equalIgnoringASCIICaseCommon): 25 Ideally we should drop the "Common" part of the name but StringView 26 wants this inline for some reason. I prefered keeping the current behavior 27 since I don't know how StringView's matching performance was evaluated. 28 29 (WTF::startsWith): 30 (WTF::startsWithIgnoringASCIICase): 31 (WTF::endsWith): 32 (WTF::endsWithIgnoringASCIICase): 33 Make all that code shared between StringView and Stringimpl. 34 35 * wtf/text/StringImpl.cpp: 36 (WTF::StringImpl::startsWith): 37 (WTF::StringImpl::startsWithIgnoringASCIICase): 38 (WTF::StringImpl::endsWith): 39 (WTF::StringImpl::endsWithIgnoringASCIICase): 40 (WTF::equal): 41 (WTF::stringImplContentEqual): Deleted. 42 * wtf/text/StringImpl.h: 43 (WTF::loadUnaligned): Deleted. 44 (WTF::equal): Deleted. 45 46 * wtf/text/StringView.cpp: 47 (WTF::StringView::startsWith): 48 (WTF::StringView::startsWithIgnoringASCIICase): 49 (WTF::StringView::endsWith): 50 (WTF::StringView::endsWithIgnoringASCIICase): 51 * wtf/text/StringView.h: 52 Since those are new, we can safely make them out-of-line and 53 evaluate the inlining impact as needed. 54 55 * wtf/text/WTFString.h: 56 (WTF::String::startsWithIgnoringASCIICase): 57 (WTF::String::endsWith): 58 (WTF::String::endsWithIgnoringASCIICase): 59 1 60 2015-03-15 Benjamin Poulain <bpoulain@apple.com> 2 61 -
trunk/Source/WTF/wtf/text/AtomicString.h
r181512 r181525 127 127 { return m_string.find(matchFunction, start); } 128 128 129 bool startsWith(const String& s, bool caseSensitive = true) const 129 bool startsWith(const String& s) const 130 { return m_string.startsWith(s); } 131 bool startsWithIgnoringASCIICase(const String& s) const 132 { return m_string.startsWithIgnoringASCIICase(s); } 133 bool startsWith(const String& s, bool caseSensitive) const 130 134 { return m_string.startsWith(s, caseSensitive); } 131 135 bool startsWith(UChar character) const … … 135 139 { return m_string.startsWith<matchLength>(prefix, caseSensitive); } 136 140 137 bool endsWith(const String& s, bool caseSensitive = true) const 141 bool endsWith(const String& s) const 142 { return m_string.endsWith(s); } 143 bool endsWithIgnoringASCIICase(const String& s) const 144 { return m_string.endsWithIgnoringASCIICase(s); } 145 bool endsWith(const String& s, bool caseSensitive) const 138 146 { return m_string.endsWith(s, caseSensitive); } 139 147 bool endsWith(UChar character) const -
trunk/Source/WTF/wtf/text/StringCommon.h
r181512 r181525 32 32 namespace WTF { 33 33 34 template<typename T> 35 inline T loadUnaligned(const char* s) 36 { 37 #if COMPILER(CLANG) 38 T tmp; 39 memcpy(&tmp, s, sizeof(T)); 40 return tmp; 41 #else 42 // This may result in undefined behavior due to unaligned access. 43 return *reinterpret_cast<const T*>(s); 44 #endif 45 } 46 47 // Do comparisons 8 or 4 bytes-at-a-time on architectures where it's safe. 48 #if (CPU(X86_64) || CPU(ARM64)) && !ASAN_ENABLED 49 ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length) 50 { 51 unsigned dwordLength = length >> 3; 52 53 const char* a = reinterpret_cast<const char*>(aLChar); 54 const char* b = reinterpret_cast<const char*>(bLChar); 55 56 if (dwordLength) { 57 for (unsigned i = 0; i != dwordLength; ++i) { 58 if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b)) 59 return false; 60 61 a += sizeof(uint64_t); 62 b += sizeof(uint64_t); 63 } 64 } 65 66 if (length & 4) { 67 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b)) 68 return false; 69 70 a += sizeof(uint32_t); 71 b += sizeof(uint32_t); 72 } 73 74 if (length & 2) { 75 if (loadUnaligned<uint16_t>(a) != loadUnaligned<uint16_t>(b)) 76 return false; 77 78 a += sizeof(uint16_t); 79 b += sizeof(uint16_t); 80 } 81 82 if (length & 1 && (*reinterpret_cast<const LChar*>(a) != *reinterpret_cast<const LChar*>(b))) 83 return false; 84 85 return true; 86 } 87 88 ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length) 89 { 90 unsigned dwordLength = length >> 2; 91 92 const char* a = reinterpret_cast<const char*>(aUChar); 93 const char* b = reinterpret_cast<const char*>(bUChar); 94 95 if (dwordLength) { 96 for (unsigned i = 0; i != dwordLength; ++i) { 97 if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b)) 98 return false; 99 100 a += sizeof(uint64_t); 101 b += sizeof(uint64_t); 102 } 103 } 104 105 if (length & 2) { 106 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b)) 107 return false; 108 109 a += sizeof(uint32_t); 110 b += sizeof(uint32_t); 111 } 112 113 if (length & 1 && (*reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b))) 114 return false; 115 116 return true; 117 } 118 #elif CPU(X86) && !ASAN_ENABLED 119 ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length) 120 { 121 const char* a = reinterpret_cast<const char*>(aLChar); 122 const char* b = reinterpret_cast<const char*>(bLChar); 123 124 unsigned wordLength = length >> 2; 125 for (unsigned i = 0; i != wordLength; ++i) { 126 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b)) 127 return false; 128 a += sizeof(uint32_t); 129 b += sizeof(uint32_t); 130 } 131 132 length &= 3; 133 134 if (length) { 135 const LChar* aRemainder = reinterpret_cast<const LChar*>(a); 136 const LChar* bRemainder = reinterpret_cast<const LChar*>(b); 137 138 for (unsigned i = 0; i < length; ++i) { 139 if (aRemainder[i] != bRemainder[i]) 140 return false; 141 } 142 } 143 144 return true; 145 } 146 147 ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length) 148 { 149 const char* a = reinterpret_cast<const char*>(aUChar); 150 const char* b = reinterpret_cast<const char*>(bUChar); 151 152 unsigned wordLength = length >> 1; 153 for (unsigned i = 0; i != wordLength; ++i) { 154 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b)) 155 return false; 156 a += sizeof(uint32_t); 157 b += sizeof(uint32_t); 158 } 159 160 if (length & 1 && *reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b)) 161 return false; 162 163 return true; 164 } 165 #elif PLATFORM(IOS) && WTF_ARM_ARCH_AT_LEAST(7) && !ASAN_ENABLED 166 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length) 167 { 168 bool isEqual = false; 169 uint32_t aValue; 170 uint32_t bValue; 171 asm("subs %[length], #4\n" 172 "blo 2f\n" 173 174 "0:\n" // Label 0 = Start of loop over 32 bits. 175 "ldr %[aValue], [%[a]], #4\n" 176 "ldr %[bValue], [%[b]], #4\n" 177 "cmp %[aValue], %[bValue]\n" 178 "bne 66f\n" 179 "subs %[length], #4\n" 180 "bhs 0b\n" 181 182 // At this point, length can be: 183 // -0: 00000000000000000000000000000000 (0 bytes left) 184 // -1: 11111111111111111111111111111111 (3 bytes left) 185 // -2: 11111111111111111111111111111110 (2 bytes left) 186 // -3: 11111111111111111111111111111101 (1 byte left) 187 // -4: 11111111111111111111111111111100 (length was 0) 188 // The pointers are at the correct position. 189 "2:\n" // Label 2 = End of loop over 32 bits, check for pair of characters. 190 "tst %[length], #2\n" 191 "beq 1f\n" 192 "ldrh %[aValue], [%[a]], #2\n" 193 "ldrh %[bValue], [%[b]], #2\n" 194 "cmp %[aValue], %[bValue]\n" 195 "bne 66f\n" 196 197 "1:\n" // Label 1 = Check for a single character left. 198 "tst %[length], #1\n" 199 "beq 42f\n" 200 "ldrb %[aValue], [%[a]]\n" 201 "ldrb %[bValue], [%[b]]\n" 202 "cmp %[aValue], %[bValue]\n" 203 "bne 66f\n" 204 205 "42:\n" // Label 42 = Success. 206 "mov %[isEqual], #1\n" 207 "66:\n" // Label 66 = End without changing isEqual to 1. 208 : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue) 209 : 210 : 211 ); 212 return isEqual; 213 } 214 215 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length) 216 { 217 bool isEqual = false; 218 uint32_t aValue; 219 uint32_t bValue; 220 asm("subs %[length], #2\n" 221 "blo 1f\n" 222 223 "0:\n" // Label 0 = Start of loop over 32 bits. 224 "ldr %[aValue], [%[a]], #4\n" 225 "ldr %[bValue], [%[b]], #4\n" 226 "cmp %[aValue], %[bValue]\n" 227 "bne 66f\n" 228 "subs %[length], #2\n" 229 "bhs 0b\n" 230 231 // At this point, length can be: 232 // -0: 00000000000000000000000000000000 (0 bytes left) 233 // -1: 11111111111111111111111111111111 (1 character left, 2 bytes) 234 // -2: 11111111111111111111111111111110 (length was zero) 235 // The pointers are at the correct position. 236 "1:\n" // Label 1 = Check for a single character left. 237 "tst %[length], #1\n" 238 "beq 42f\n" 239 "ldrh %[aValue], [%[a]]\n" 240 "ldrh %[bValue], [%[b]]\n" 241 "cmp %[aValue], %[bValue]\n" 242 "bne 66f\n" 243 244 "42:\n" // Label 42 = Success. 245 "mov %[isEqual], #1\n" 246 "66:\n" // Label 66 = End without changing isEqual to 1. 247 : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue) 248 : 249 : 250 ); 251 return isEqual; 252 } 253 #elif !ASAN_ENABLED 254 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length) { return !memcmp(a, b, length); } 255 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length) { return !memcmp(a, b, length * sizeof(UChar)); } 256 #else 257 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length) 258 { 259 for (unsigned i = 0; i < length; ++i) { 260 if (a[i] != b[i]) 261 return false; 262 } 263 return true; 264 } 265 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length) 266 { 267 for (unsigned i = 0; i < length; ++i) { 268 if (a[i] != b[i]) 269 return false; 270 } 271 return true; 272 } 273 #endif 274 275 ALWAYS_INLINE bool equal(const LChar* a, const UChar* b, unsigned length) 276 { 277 for (unsigned i = 0; i < length; ++i) { 278 if (a[i] != b[i]) 279 return false; 280 } 281 return true; 282 } 283 284 ALWAYS_INLINE bool equal(const UChar* a, const LChar* b, unsigned length) { return equal(b, a, length); } 285 286 template<typename StringClassA, typename StringClassB> 287 ALWAYS_INLINE bool equalCommon(const StringClassA& a, const StringClassB& b) 288 { 289 unsigned length = a.length(); 290 if (length != b.length()) 291 return false; 292 293 if (a.is8Bit()) { 294 if (b.is8Bit()) 295 return equal(a.characters8(), b.characters8(), length); 296 297 return equal(a.characters8(), b.characters16(), length); 298 } 299 300 if (b.is8Bit()) 301 return equal(a.characters16(), b.characters8(), length); 302 303 return equal(a.characters16(), b.characters16(), length); 304 } 305 306 template<typename StringClassA, typename StringClassB> 307 ALWAYS_INLINE bool equalCommon(const StringClassA* a, const StringClassB* b) 308 { 309 if (a == b) 310 return true; 311 if (!a || !b) 312 return false; 313 return equal(*a, *b); 314 } 315 34 316 template<typename CharacterTypeA, typename CharacterTypeB> 35 317 inline bool equalIgnoringASCIICase(const CharacterTypeA* a, const CharacterTypeB* b, unsigned length) … … 42 324 } 43 325 44 template<typename StringClass >45 bool equalIgnoringASCIICaseCommon(const StringClass & a, const StringClass& b)326 template<typename StringClassA, typename StringClassB> 327 bool equalIgnoringASCIICaseCommon(const StringClassA& a, const StringClassB& b) 46 328 { 47 329 unsigned length = a.length(); … … 62 344 } 63 345 346 template<typename StringClassA, typename StringClassB> 347 bool startsWith(const StringClassA& reference, const StringClassB& prefix) 348 { 349 unsigned prefixLength = prefix.length(); 350 if (prefixLength > reference.length()) 351 return false; 352 353 if (reference.is8Bit()) { 354 if (prefix.is8Bit()) 355 return equal(reference.characters8(), prefix.characters8(), prefixLength); 356 return equal(reference.characters8(), prefix.characters16(), prefixLength); 357 } 358 if (prefix.is8Bit()) 359 return equal(reference.characters16(), prefix.characters8(), prefixLength); 360 return equal(reference.characters16(), prefix.characters16(), prefixLength); 361 } 362 363 template<typename StringClassA, typename StringClassB> 364 bool startsWithIgnoringASCIICase(const StringClassA& reference, const StringClassB& prefix) 365 { 366 unsigned prefixLength = prefix.length(); 367 if (prefixLength > reference.length()) 368 return false; 369 370 if (reference.is8Bit()) { 371 if (prefix.is8Bit()) 372 return equalIgnoringASCIICase(reference.characters8(), prefix.characters8(), prefixLength); 373 return equalIgnoringASCIICase(reference.characters8(), prefix.characters16(), prefixLength); 374 } 375 if (prefix.is8Bit()) 376 return equalIgnoringASCIICase(reference.characters16(), prefix.characters8(), prefixLength); 377 return equalIgnoringASCIICase(reference.characters16(), prefix.characters16(), prefixLength); 378 } 379 380 template<typename StringClassA, typename StringClassB> 381 bool endsWith(const StringClassA& reference, const StringClassB& suffix) 382 { 383 unsigned suffixLength = suffix.length(); 384 unsigned referenceLength = reference.length(); 385 if (suffixLength > referenceLength) 386 return false; 387 388 unsigned startOffset = referenceLength - suffixLength; 389 390 if (reference.is8Bit()) { 391 if (suffix.is8Bit()) 392 return equal(reference.characters8() + startOffset, suffix.characters8(), suffixLength); 393 return equal(reference.characters8() + startOffset, suffix.characters16(), suffixLength); 394 } 395 if (suffix.is8Bit()) 396 return equal(reference.characters16() + startOffset, suffix.characters8(), suffixLength); 397 return equal(reference.characters16() + startOffset, suffix.characters16(), suffixLength); 398 } 399 400 template<typename StringClassA, typename StringClassB> 401 bool endsWithIgnoringASCIICase(const StringClassA& reference, const StringClassB& suffix) 402 { 403 unsigned suffixLength = suffix.length(); 404 unsigned referenceLength = reference.length(); 405 if (suffixLength > referenceLength) 406 return false; 407 408 unsigned startOffset = referenceLength - suffixLength; 409 410 if (reference.is8Bit()) { 411 if (suffix.is8Bit()) 412 return equalIgnoringASCIICase(reference.characters8() + startOffset, suffix.characters8(), suffixLength); 413 return equalIgnoringASCIICase(reference.characters8() + startOffset, suffix.characters16(), suffixLength); 414 } 415 if (suffix.is8Bit()) 416 return equalIgnoringASCIICase(reference.characters16() + startOffset, suffix.characters8(), suffixLength); 417 return equalIgnoringASCIICase(reference.characters16() + startOffset, suffix.characters16(), suffixLength); 418 } 419 64 420 } 65 421 -
trunk/Source/WTF/wtf/text/StringImpl.cpp
r181512 r181525 1381 1381 if (!str) 1382 1382 return false; 1383 1384 if (str->length() > length()) 1383 return ::WTF::startsWith(*this, *str); 1384 } 1385 1386 bool StringImpl::startsWith(const StringImpl& str) const 1387 { 1388 return ::WTF::startsWith(*this, str); 1389 } 1390 1391 bool StringImpl::startsWithIgnoringASCIICase(const StringImpl* prefix) const 1392 { 1393 if (!prefix) 1385 1394 return false; 1386 1395 1387 if (is8Bit()) { 1388 if (str->is8Bit()) 1389 return equal(characters8(), str->characters8(), str->length()); 1390 return equal(characters8(), str->characters16(), str->length()); 1391 } 1392 if (str->is8Bit()) 1393 return equal(characters16(), str->characters8(), str->length()); 1394 return equal(characters16(), str->characters16(), str->length()); 1396 return ::WTF::startsWithIgnoringASCIICase(*this, *prefix); 1397 } 1398 1399 bool StringImpl::startsWithIgnoringASCIICase(const StringImpl& prefix) const 1400 { 1401 return ::WTF::startsWithIgnoringASCIICase(*this, prefix); 1395 1402 } 1396 1403 … … 1413 1420 } 1414 1421 1422 bool StringImpl::endsWith(StringImpl* suffix) 1423 { 1424 if (!suffix) 1425 return false; 1426 1427 return ::WTF::endsWith(*this, *suffix); 1428 } 1429 1430 bool StringImpl::endsWith(StringImpl& suffix) 1431 { 1432 return ::WTF::endsWith(*this, suffix); 1433 } 1434 1415 1435 bool StringImpl::endsWith(StringImpl* matchString, bool caseSensitive) 1416 1436 { … … 1421 1441 } 1422 1442 return false; 1443 } 1444 1445 bool StringImpl::endsWithIgnoringASCIICase(const StringImpl* suffix) const 1446 { 1447 if (!suffix) 1448 return false; 1449 1450 return ::WTF::endsWithIgnoringASCIICase(*this, *suffix); 1451 } 1452 1453 bool StringImpl::endsWithIgnoringASCIICase(const StringImpl& suffix) const 1454 { 1455 return ::WTF::endsWithIgnoringASCIICase(*this, suffix); 1423 1456 } 1424 1457 … … 1825 1858 } 1826 1859 1827 static ALWAYS_INLINE bool stringImplContentEqual(const StringImpl& a, const StringImpl& b)1828 {1829 unsigned aLength = a.length();1830 unsigned bLength = b.length();1831 if (aLength != bLength)1832 return false;1833 1834 if (a.is8Bit()) {1835 if (b.is8Bit())1836 return equal(a.characters8(), b.characters8(), aLength);1837 1838 return equal(a.characters8(), b.characters16(), aLength);1839 }1840 1841 if (b.is8Bit())1842 return equal(a.characters16(), b.characters8(), aLength);1843 1844 return equal(a.characters16(), b.characters16(), aLength);1845 }1846 1847 1860 bool equal(const StringImpl* a, const StringImpl* b) 1848 1861 { 1849 if (a == b) 1850 return true; 1851 if (!a || !b) 1852 return false; 1853 1854 return stringImplContentEqual(*a, *b); 1862 return equalCommon(a, b); 1855 1863 } 1856 1864 … … 1917 1925 bool equal(const StringImpl& a, const StringImpl& b) 1918 1926 { 1919 if (&a == &b) 1920 return true; 1921 1922 return stringImplContentEqual(a, b); 1927 return equalCommon(a, b); 1923 1928 } 1924 1929 -
trunk/Source/WTF/wtf/text/StringImpl.h
r181512 r181525 670 670 671 671 WTF_EXPORT_STRING_API bool startsWith(const StringImpl*) const; 672 WTF_EXPORT_STRING_API bool startsWith(const StringImpl&) const; 673 WTF_EXPORT_STRING_API bool startsWithIgnoringASCIICase(const StringImpl*) const; 674 WTF_EXPORT_STRING_API bool startsWithIgnoringASCIICase(const StringImpl&) const; 672 675 bool startsWith(StringImpl* str, bool caseSensitive) { return caseSensitive ? startsWith(str) : (reverseFindIgnoringCase(str, 0) == 0); } 673 676 WTF_EXPORT_STRING_API bool startsWith(UChar) const; … … 677 680 WTF_EXPORT_STRING_API bool hasInfixStartingAt(const StringImpl&, unsigned startOffset) const; 678 681 679 WTF_EXPORT_STRING_API bool endsWith(StringImpl*, bool caseSensitive = true); 682 WTF_EXPORT_STRING_API bool endsWith(StringImpl*); 683 WTF_EXPORT_STRING_API bool endsWith(StringImpl&); 684 WTF_EXPORT_STRING_API bool endsWithIgnoringASCIICase(const StringImpl*) const; 685 WTF_EXPORT_STRING_API bool endsWithIgnoringASCIICase(const StringImpl&) const; 686 WTF_EXPORT_STRING_API bool endsWith(StringImpl*, bool caseSensitive); 680 687 WTF_EXPORT_STRING_API bool endsWith(UChar) const; 681 688 WTF_EXPORT_STRING_API bool endsWith(const char*, unsigned matchLength, bool caseSensitive) const; … … 862 869 WTF_EXPORT_STRING_API bool equal(const StringImpl& a, const StringImpl& b); 863 870 864 template<typename T>865 inline T loadUnaligned(const char* s)866 {867 #if COMPILER(CLANG)868 T tmp;869 memcpy(&tmp, s, sizeof(T));870 return tmp;871 #else872 // This may result in undefined behavior due to unaligned access.873 return *reinterpret_cast<const T*>(s);874 #endif875 }876 877 // Do comparisons 8 or 4 bytes-at-a-time on architectures where it's safe.878 #if (CPU(X86_64) || CPU(ARM64)) && !ASAN_ENABLED879 ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length)880 {881 unsigned dwordLength = length >> 3;882 883 const char* a = reinterpret_cast<const char*>(aLChar);884 const char* b = reinterpret_cast<const char*>(bLChar);885 886 if (dwordLength) {887 for (unsigned i = 0; i != dwordLength; ++i) {888 if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b))889 return false;890 891 a += sizeof(uint64_t);892 b += sizeof(uint64_t);893 }894 }895 896 if (length & 4) {897 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))898 return false;899 900 a += sizeof(uint32_t);901 b += sizeof(uint32_t);902 }903 904 if (length & 2) {905 if (loadUnaligned<uint16_t>(a) != loadUnaligned<uint16_t>(b))906 return false;907 908 a += sizeof(uint16_t);909 b += sizeof(uint16_t);910 }911 912 if (length & 1 && (*reinterpret_cast<const LChar*>(a) != *reinterpret_cast<const LChar*>(b)))913 return false;914 915 return true;916 }917 918 ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length)919 {920 unsigned dwordLength = length >> 2;921 922 const char* a = reinterpret_cast<const char*>(aUChar);923 const char* b = reinterpret_cast<const char*>(bUChar);924 925 if (dwordLength) {926 for (unsigned i = 0; i != dwordLength; ++i) {927 if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b))928 return false;929 930 a += sizeof(uint64_t);931 b += sizeof(uint64_t);932 }933 }934 935 if (length & 2) {936 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))937 return false;938 939 a += sizeof(uint32_t);940 b += sizeof(uint32_t);941 }942 943 if (length & 1 && (*reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b)))944 return false;945 946 return true;947 }948 #elif CPU(X86) && !ASAN_ENABLED949 ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length)950 {951 const char* a = reinterpret_cast<const char*>(aLChar);952 const char* b = reinterpret_cast<const char*>(bLChar);953 954 unsigned wordLength = length >> 2;955 for (unsigned i = 0; i != wordLength; ++i) {956 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))957 return false;958 a += sizeof(uint32_t);959 b += sizeof(uint32_t);960 }961 962 length &= 3;963 964 if (length) {965 const LChar* aRemainder = reinterpret_cast<const LChar*>(a);966 const LChar* bRemainder = reinterpret_cast<const LChar*>(b);967 968 for (unsigned i = 0; i < length; ++i) {969 if (aRemainder[i] != bRemainder[i])970 return false;971 }972 }973 974 return true;975 }976 977 ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length)978 {979 const char* a = reinterpret_cast<const char*>(aUChar);980 const char* b = reinterpret_cast<const char*>(bUChar);981 982 unsigned wordLength = length >> 1;983 for (unsigned i = 0; i != wordLength; ++i) {984 if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))985 return false;986 a += sizeof(uint32_t);987 b += sizeof(uint32_t);988 }989 990 if (length & 1 && *reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b))991 return false;992 993 return true;994 }995 #elif PLATFORM(IOS) && WTF_ARM_ARCH_AT_LEAST(7) && !ASAN_ENABLED996 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)997 {998 bool isEqual = false;999 uint32_t aValue;1000 uint32_t bValue;1001 asm("subs %[length], #4\n"1002 "blo 2f\n"1003 1004 "0:\n" // Label 0 = Start of loop over 32 bits.1005 "ldr %[aValue], [%[a]], #4\n"1006 "ldr %[bValue], [%[b]], #4\n"1007 "cmp %[aValue], %[bValue]\n"1008 "bne 66f\n"1009 "subs %[length], #4\n"1010 "bhs 0b\n"1011 1012 // At this point, length can be:1013 // -0: 00000000000000000000000000000000 (0 bytes left)1014 // -1: 11111111111111111111111111111111 (3 bytes left)1015 // -2: 11111111111111111111111111111110 (2 bytes left)1016 // -3: 11111111111111111111111111111101 (1 byte left)1017 // -4: 11111111111111111111111111111100 (length was 0)1018 // The pointers are at the correct position.1019 "2:\n" // Label 2 = End of loop over 32 bits, check for pair of characters.1020 "tst %[length], #2\n"1021 "beq 1f\n"1022 "ldrh %[aValue], [%[a]], #2\n"1023 "ldrh %[bValue], [%[b]], #2\n"1024 "cmp %[aValue], %[bValue]\n"1025 "bne 66f\n"1026 1027 "1:\n" // Label 1 = Check for a single character left.1028 "tst %[length], #1\n"1029 "beq 42f\n"1030 "ldrb %[aValue], [%[a]]\n"1031 "ldrb %[bValue], [%[b]]\n"1032 "cmp %[aValue], %[bValue]\n"1033 "bne 66f\n"1034 1035 "42:\n" // Label 42 = Success.1036 "mov %[isEqual], #1\n"1037 "66:\n" // Label 66 = End without changing isEqual to 1.1038 : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue)1039 :1040 :1041 );1042 return isEqual;1043 }1044 1045 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)1046 {1047 bool isEqual = false;1048 uint32_t aValue;1049 uint32_t bValue;1050 asm("subs %[length], #2\n"1051 "blo 1f\n"1052 1053 "0:\n" // Label 0 = Start of loop over 32 bits.1054 "ldr %[aValue], [%[a]], #4\n"1055 "ldr %[bValue], [%[b]], #4\n"1056 "cmp %[aValue], %[bValue]\n"1057 "bne 66f\n"1058 "subs %[length], #2\n"1059 "bhs 0b\n"1060 1061 // At this point, length can be:1062 // -0: 00000000000000000000000000000000 (0 bytes left)1063 // -1: 11111111111111111111111111111111 (1 character left, 2 bytes)1064 // -2: 11111111111111111111111111111110 (length was zero)1065 // The pointers are at the correct position.1066 "1:\n" // Label 1 = Check for a single character left.1067 "tst %[length], #1\n"1068 "beq 42f\n"1069 "ldrh %[aValue], [%[a]]\n"1070 "ldrh %[bValue], [%[b]]\n"1071 "cmp %[aValue], %[bValue]\n"1072 "bne 66f\n"1073 1074 "42:\n" // Label 42 = Success.1075 "mov %[isEqual], #1\n"1076 "66:\n" // Label 66 = End without changing isEqual to 1.1077 : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue)1078 :1079 :1080 );1081 return isEqual;1082 }1083 #elif !ASAN_ENABLED1084 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length) { return !memcmp(a, b, length); }1085 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length) { return !memcmp(a, b, length * sizeof(UChar)); }1086 #else1087 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)1088 {1089 for (unsigned i = 0; i < length; ++i) {1090 if (a[i] != b[i])1091 return false;1092 }1093 return true;1094 }1095 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)1096 {1097 for (unsigned i = 0; i < length; ++i) {1098 if (a[i] != b[i])1099 return false;1100 }1101 return true;1102 }1103 #endif1104 1105 ALWAYS_INLINE bool equal(const LChar* a, const UChar* b, unsigned length)1106 {1107 for (unsigned i = 0; i < length; ++i) {1108 if (a[i] != b[i])1109 return false;1110 }1111 return true;1112 }1113 1114 ALWAYS_INLINE bool equal(const UChar* a, const LChar* b, unsigned length) { return equal(b, a, length); }1115 1116 871 WTF_EXPORT_STRING_API bool equalIgnoringCase(const StringImpl*, const StringImpl*); 1117 872 WTF_EXPORT_STRING_API bool equalIgnoringCase(const StringImpl*, const LChar*); -
trunk/Source/WTF/wtf/text/StringView.cpp
r174395 r181525 119 119 } 120 120 121 bool StringView::startsWith(const StringView& prefix) const 122 { 123 return ::WTF::startsWith(*this, prefix); 124 } 125 126 bool StringView::startsWithIgnoringASCIICase(const StringView& prefix) const 127 { 128 return ::WTF::endsWithIgnoringASCIICase(*this, prefix); 129 } 130 131 bool StringView::endsWith(const StringView& prefix) const 132 { 133 return ::WTF::startsWith(*this, prefix); 134 } 135 136 bool StringView::endsWithIgnoringASCIICase(const StringView& prefix) const 137 { 138 return ::WTF::endsWithIgnoringASCIICase(*this, prefix); 139 } 140 121 141 } 122 142 -
trunk/Source/WTF/wtf/text/StringView.h
r181512 r181525 107 107 bool contains(UChar) const; 108 108 109 bool startsWith(const StringView&) const; 110 bool startsWithIgnoringASCIICase(const StringView&) const; 111 112 bool endsWith(const StringView&) const; 113 bool endsWithIgnoringASCIICase(const StringView&) const; 114 109 115 int toInt(bool& isValid) const; 110 116 float toFloat(bool& isValid) const; … … 470 476 inline bool equal(StringView a, StringView b) 471 477 { 472 unsigned aLength = a.length(); 473 unsigned bLength = b.length(); 474 if (aLength != bLength) 475 return false; 476 477 if (a.is8Bit()) { 478 if (b.is8Bit()) 479 return equal(a.characters8(), b.characters8(), aLength); 480 481 return equal(a.characters8(), b.characters16(), aLength); 482 } 483 484 if (b.is8Bit()) 485 return equal(a.characters16(), b.characters8(), aLength); 486 487 return equal(a.characters16(), b.characters16(), aLength); 478 return equalCommon(a, b); 488 479 } 489 480 -
trunk/Source/WTF/wtf/text/WTFString.h
r181512 r181525 264 264 bool startsWith(const String& s) const 265 265 { return m_impl ? m_impl->startsWith(s.impl()) : s.isEmpty(); } 266 bool startsWithIgnoringASCIICase(const String& s) const 267 { return m_impl ? m_impl->startsWithIgnoringASCIICase(s.impl()) : s.isEmpty(); } 266 268 bool startsWith(const String& s, bool caseSensitive) const 267 269 { return m_impl ? m_impl->startsWith(s.impl(), caseSensitive) : s.isEmpty(); } … … 274 276 { return m_impl && prefix.impl() ? m_impl->hasInfixStartingAt(*prefix.impl(), startOffset) : false; } 275 277 276 bool endsWith(const String& s, bool caseSensitive = true) const 278 bool endsWith(const String& s) const 279 { return m_impl ? m_impl->endsWith(s.impl()) : s.isEmpty(); } 280 bool endsWithIgnoringASCIICase(const String& s) const 281 { return m_impl ? m_impl->endsWithIgnoringASCIICase(s.impl()) : s.isEmpty(); } 282 bool endsWith(const String& s, bool caseSensitive) const 277 283 { return m_impl ? m_impl->endsWith(s.impl(), caseSensitive) : s.isEmpty(); } 278 284 bool endsWith(UChar character) const -
trunk/Source/WebCore/ChangeLog
r181524 r181525 1 2015-03-15 Benjamin Poulain <benjamin@webkit.org> 2 3 CSS: fix the case-insensitive matching of the attribute selectors Begin, End and Hyphen 4 https://bugs.webkit.org/show_bug.cgi?id=142715 5 6 Reviewed by Brent Fulgham. 7 8 Fix attribute matching with: 9 -Begin: [a^=b]. 10 -End: [a$=b]. 11 -Hyphen: [a|=b]. 12 13 Tests: fast/selectors/attribute-endswith-value-matching-is-ascii-case-insensitive.html 14 fast/selectors/attribute-hyphen-value-matching-is-ascii-case-insensitive.html 15 fast/selectors/attribute-startswith-value-matching-is-ascii-case-insensitive.html 16 17 * css/SelectorChecker.cpp: 18 (WebCore::attributeValueMatches): 19 I forgot to change CSSSelector::Exact in my last patch. 20 The tests could not catch that since we use the CSS JIT almost everywhere. 21 22 * cssjit/SelectorCompiler.cpp: 23 (WebCore::SelectorCompiler::attributeValueBeginsWith): 24 (WebCore::SelectorCompiler::attributeValueEndsWith): 25 (WebCore::SelectorCompiler::attributeValueMatchHyphenRule): 26 1 27 2015-03-15 Dan Bernstein <mitz@apple.com> 2 28 -
trunk/Source/WebCore/css/SelectorChecker.cpp
r181197 r181525 421 421 break; 422 422 case CSSSelector::Exact: 423 if (caseSensitive ? selectorValue != value : !equalIgnoring Case(selectorValue, value))423 if (caseSensitive ? selectorValue != value : !equalIgnoringASCIICase(selectorValue, value)) 424 424 return false; 425 425 break; … … 451 451 break; 452 452 case CSSSelector::Begin: 453 if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isEmpty()) 454 return false; 453 if (selectorValue.isEmpty()) 454 return false; 455 if (caseSensitive) { 456 if (!value.startsWith(selectorValue)) 457 return false; 458 } else { 459 if (!value.startsWithIgnoringASCIICase(selectorValue)) 460 return false; 461 } 455 462 break; 456 463 case CSSSelector::End: 457 if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmpty()) 458 return false; 464 if (selectorValue.isEmpty()) 465 return false; 466 if (caseSensitive) { 467 if (!value.endsWith(selectorValue)) 468 return false; 469 } else { 470 if (!value.endsWithIgnoringASCIICase(selectorValue)) 471 return false; 472 } 459 473 break; 460 474 case CSSSelector::Hyphen: 461 475 if (value.length() < selectorValue.length()) 462 476 return false; 463 if (!value.startsWith(selectorValue, caseSensitive)) 464 return false; 477 if (caseSensitive) { 478 if (!value.startsWith(selectorValue)) 479 return false; 480 } else { 481 if (!value.startsWithIgnoringASCIICase(selectorValue)) 482 return false; 483 } 465 484 // It they start the same, check for exact match or following '-': 466 485 if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-') -
trunk/Source/WebCore/cssjit/SelectorCompiler.cpp
r181512 r181525 2804 2804 static bool attributeValueBeginsWith(const Attribute* attribute, AtomicStringImpl* expectedString) 2805 2805 { 2806 ASSERT(expectedString); 2807 2806 2808 AtomicStringImpl& valueImpl = *attribute->value().impl(); 2807 2809 if (caseSensitivity == CaseSensitive) 2808 return valueImpl.startsWith( expectedString);2809 return valueImpl.startsWith (expectedString, false);2810 return valueImpl.startsWith(*expectedString); 2811 return valueImpl.startsWithIgnoringASCIICase(*expectedString); 2810 2812 } 2811 2813 … … 2822 2824 static bool attributeValueEndsWith(const Attribute* attribute, AtomicStringImpl* expectedString) 2823 2825 { 2826 ASSERT(expectedString); 2827 2824 2828 AtomicStringImpl& valueImpl = *attribute->value().impl(); 2825 2829 if (caseSensitivity == CaseSensitive) 2826 return valueImpl.endsWith( expectedString);2827 return valueImpl.endsWith (expectedString, false);2830 return valueImpl.endsWith(*expectedString); 2831 return valueImpl.endsWithIgnoringASCIICase(*expectedString); 2828 2832 } 2829 2833 … … 2831 2835 static bool attributeValueMatchHyphenRule(const Attribute* attribute, AtomicStringImpl* expectedString) 2832 2836 { 2837 ASSERT(expectedString); 2838 2833 2839 AtomicStringImpl& valueImpl = *attribute->value().impl(); 2834 2840 if (valueImpl.length() < expectedString->length()) … … 2837 2843 bool valueStartsWithExpectedString; 2838 2844 if (caseSensitivity == CaseSensitive) 2839 valueStartsWithExpectedString = valueImpl.startsWith( expectedString);2845 valueStartsWithExpectedString = valueImpl.startsWith(*expectedString); 2840 2846 else 2841 valueStartsWithExpectedString = valueImpl.startsWith (expectedString, false);2847 valueStartsWithExpectedString = valueImpl.startsWithIgnoringASCIICase(*expectedString); 2842 2848 2843 2849 if (!valueStartsWithExpectedString) -
trunk/Tools/ChangeLog
r181512 r181525 1 2015-03-15 Benjamin Poulain <benjamin@webkit.org> 2 3 CSS: fix the case-insensitive matching of the attribute selectors Begin, End and Hyphen 4 https://bugs.webkit.org/show_bug.cgi?id=142715 5 6 Reviewed by Brent Fulgham. 7 8 * TestWebKitAPI/Tests/WTF/StringImpl.cpp: 9 (TestWebKitAPI::TEST): 10 1 11 2015-03-15 Benjamin Poulain <bpoulain@apple.com> 2 12 -
trunk/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp
r181512 r181525 165 165 } 166 166 167 TEST(WTF, StringImplStartsWithIgnoringASCIICaseBasic) 168 { 169 RefPtr<StringImpl> reference = StringImpl::create(reinterpret_cast<const LChar*>("aBcéX")); 170 RefPtr<StringImpl> referenceEquivalent = StringImpl::create(reinterpret_cast<const LChar*>("AbCéx")); 171 172 // Identity. 173 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(reference.get())); 174 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*reference.get())); 175 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(referenceEquivalent.get())); 176 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*referenceEquivalent.get())); 177 ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(reference.get())); 178 ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(*reference.get())); 179 ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(referenceEquivalent.get())); 180 ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(*referenceEquivalent.get())); 181 182 // Proper prefixes. 183 RefPtr<StringImpl> aLower = StringImpl::createFromLiteral("a"); 184 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(aLower.get())); 185 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*aLower.get())); 186 RefPtr<StringImpl> aUpper = StringImpl::createFromLiteral("A"); 187 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(aUpper.get())); 188 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*aUpper.get())); 189 190 RefPtr<StringImpl> abcLower = StringImpl::createFromLiteral("abc"); 191 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcLower.get())); 192 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcLower.get())); 193 RefPtr<StringImpl> abcUpper = StringImpl::createFromLiteral("ABC"); 194 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcUpper.get())); 195 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcUpper.get())); 196 197 RefPtr<StringImpl> abcAccentLower = StringImpl::create(reinterpret_cast<const LChar*>("abcé")); 198 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcAccentLower.get())); 199 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcAccentLower.get())); 200 RefPtr<StringImpl> abcAccentUpper = StringImpl::create(reinterpret_cast<const LChar*>("ABCé")); 201 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcAccentUpper.get())); 202 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcAccentUpper.get())); 203 204 // Negative cases. 205 RefPtr<StringImpl> differentFirstChar = StringImpl::create(reinterpret_cast<const LChar*>("bBcéX")); 206 RefPtr<StringImpl> differentFirstCharProperPrefix = StringImpl::create(reinterpret_cast<const LChar*>("CBcé")); 207 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(differentFirstChar.get())); 208 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*differentFirstChar.get())); 209 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(differentFirstCharProperPrefix.get())); 210 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*differentFirstCharProperPrefix.get())); 211 212 RefPtr<StringImpl> uppercaseAccent = StringImpl::create(reinterpret_cast<const LChar*>("aBcÉX")); 213 RefPtr<StringImpl> uppercaseAccentProperPrefix = StringImpl::create(reinterpret_cast<const LChar*>("aBcÉX")); 214 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(uppercaseAccent.get())); 215 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*uppercaseAccent.get())); 216 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(uppercaseAccentProperPrefix.get())); 217 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*uppercaseAccentProperPrefix.get())); 218 } 219 220 TEST(WTF, StringImplStartsWithIgnoringASCIICaseWithNull) 221 { 222 RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG"); 223 ASSERT_FALSE(reference->startsWithIgnoringASCIICase(nullptr)); 224 225 RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>("")); 226 ASSERT_FALSE(empty->startsWithIgnoringASCIICase(nullptr)); 227 } 228 229 TEST(WTF, StringImplStartsWithIgnoringASCIICaseWithEmpty) 230 { 231 RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG"); 232 RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>("")); 233 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(empty.get())); 234 ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*empty.get())); 235 ASSERT_TRUE(empty->startsWithIgnoringASCIICase(empty.get())); 236 ASSERT_TRUE(empty->startsWithIgnoringASCIICase(*empty.get())); 237 ASSERT_FALSE(empty->startsWithIgnoringASCIICase(reference.get())); 238 ASSERT_FALSE(empty->startsWithIgnoringASCIICase(*reference.get())); 239 } 240 241 TEST(WTF, StringImplEndsWithIgnoringASCIICaseBasic) 242 { 243 RefPtr<StringImpl> reference = StringImpl::create(reinterpret_cast<const LChar*>("XÉCbA")); 244 RefPtr<StringImpl> referenceEquivalent = StringImpl::create(reinterpret_cast<const LChar*>("xÉcBa")); 245 246 // Identity. 247 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(reference.get())); 248 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*reference.get())); 249 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(referenceEquivalent.get())); 250 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*referenceEquivalent.get())); 251 ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(reference.get())); 252 ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(*reference.get())); 253 ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(referenceEquivalent.get())); 254 ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(*referenceEquivalent.get())); 255 256 // Proper suffixes. 257 RefPtr<StringImpl> aLower = StringImpl::createFromLiteral("a"); 258 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(aLower.get())); 259 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*aLower.get())); 260 RefPtr<StringImpl> aUpper = StringImpl::createFromLiteral("a"); 261 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(aUpper.get())); 262 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*aUpper.get())); 263 264 RefPtr<StringImpl> abcLower = StringImpl::createFromLiteral("cba"); 265 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcLower.get())); 266 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcLower.get())); 267 RefPtr<StringImpl> abcUpper = StringImpl::createFromLiteral("CBA"); 268 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcUpper.get())); 269 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcUpper.get())); 270 271 RefPtr<StringImpl> abcAccentLower = StringImpl::create(reinterpret_cast<const LChar*>("Écba")); 272 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcAccentLower.get())); 273 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcAccentLower.get())); 274 RefPtr<StringImpl> abcAccentUpper = StringImpl::create(reinterpret_cast<const LChar*>("ÉCBA")); 275 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcAccentUpper.get())); 276 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcAccentUpper.get())); 277 278 // Negative cases. 279 RefPtr<StringImpl> differentLastChar = StringImpl::create(reinterpret_cast<const LChar*>("XÉCbB")); 280 RefPtr<StringImpl> differentLastCharProperSuffix = StringImpl::create(reinterpret_cast<const LChar*>("ÉCbb")); 281 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(differentLastChar.get())); 282 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*differentLastChar.get())); 283 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(differentLastCharProperSuffix.get())); 284 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*differentLastCharProperSuffix.get())); 285 286 RefPtr<StringImpl> lowercaseAccent = StringImpl::create(reinterpret_cast<const LChar*>("aBcéX")); 287 RefPtr<StringImpl> loweraseAccentProperSuffix = StringImpl::create(reinterpret_cast<const LChar*>("aBcéX")); 288 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(lowercaseAccent.get())); 289 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*lowercaseAccent.get())); 290 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(loweraseAccentProperSuffix.get())); 291 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*loweraseAccentProperSuffix.get())); 292 } 293 294 TEST(WTF, StringImplEndsWithIgnoringASCIICaseWithNull) 295 { 296 RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG"); 297 ASSERT_FALSE(reference->endsWithIgnoringASCIICase(nullptr)); 298 299 RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>("")); 300 ASSERT_FALSE(empty->endsWithIgnoringASCIICase(nullptr)); 301 } 302 303 TEST(WTF, StringImplEndsWithIgnoringASCIICaseWithEmpty) 304 { 305 RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG"); 306 RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>("")); 307 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(empty.get())); 308 ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*empty.get())); 309 ASSERT_TRUE(empty->endsWithIgnoringASCIICase(empty.get())); 310 ASSERT_TRUE(empty->endsWithIgnoringASCIICase(*empty.get())); 311 ASSERT_FALSE(empty->endsWithIgnoringASCIICase(reference.get())); 312 ASSERT_FALSE(empty->endsWithIgnoringASCIICase(*reference.get())); 313 } 314 167 315 } // namespace TestWebKitAPI
Note:
See TracChangeset
for help on using the changeset viewer.