OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) |
3 * 1999 Waldo Bastian (bastian@kde.org) | 3 * 1999 Waldo Bastian (bastian@kde.org) |
4 * 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch) | 4 * 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch) |
5 * 2001-2003 Dirk Mueller (mueller@kde.org) | 5 * 2001-2003 Dirk Mueller (mueller@kde.org) |
6 * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv
ed. | 6 * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv
ed. |
7 * Copyright (C) 2008 David Smith (catfish.man@gmail.com) | 7 * Copyright (C) 2008 David Smith (catfish.man@gmail.com) |
8 * Copyright (C) 2010 Google Inc. All rights reserved. | 8 * Copyright (C) 2010 Google Inc. All rights reserved. |
9 * | 9 * |
10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "core/css/CSSSelector.h" | 27 #include "core/css/CSSSelector.h" |
28 | 28 |
29 #include "HTMLNames.h" | 29 #include "HTMLNames.h" |
30 #include "RuntimeEnabledFeatures.h" | 30 #include "RuntimeEnabledFeatures.h" |
31 #include "core/css/CSSOMUtils.h" | 31 #include "core/css/CSSOMUtils.h" |
32 #include "core/css/CSSSelectorList.h" | 32 #include "core/css/CSSSelectorList.h" |
33 #include "wtf/Assertions.h" | 33 #include "wtf/Assertions.h" |
34 #include "wtf/HashMap.h" | 34 #include "wtf/HashMap.h" |
35 #include "wtf/StdLibExtras.h" | 35 #include "wtf/StdLibExtras.h" |
36 #include "wtf/text/StringBuilder.h" | 36 #include "wtf/text/StringBuilder.h" |
37 #include "wtf/text/StringHash.h" | |
38 | 37 |
39 #ifndef NDEBUG | 38 #ifndef NDEBUG |
40 #include <stdio.h> | 39 #include <stdio.h> |
41 #endif | 40 #endif |
42 | 41 |
43 namespace WebCore { | 42 namespace WebCore { |
44 | 43 |
45 using namespace HTMLNames; | 44 using namespace HTMLNames; |
46 | 45 |
47 struct SameSizeAsCSSSelector { | 46 struct SameSizeAsCSSSelector { |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 } | 268 } |
270 | 269 |
271 // Could be made smaller and faster by replacing pointer with an | 270 // Could be made smaller and faster by replacing pointer with an |
272 // offset into a string buffer and making the bit fields smaller but | 271 // offset into a string buffer and making the bit fields smaller but |
273 // that could not be maintained by hand. | 272 // that could not be maintained by hand. |
274 struct NameToPseudoStruct { | 273 struct NameToPseudoStruct { |
275 const char* string; | 274 const char* string; |
276 unsigned type:8; | 275 unsigned type:8; |
277 }; | 276 }; |
278 | 277 |
| 278 // This table should be kept sorted. |
279 const static NameToPseudoStruct pseudoTypeMap[] = { | 279 const static NameToPseudoStruct pseudoTypeMap[] = { |
280 {"active", CSSSelector::PseudoActive}, | |
281 {"after", CSSSelector::PseudoAfter}, | |
282 {"-webkit-any(", CSSSelector::PseudoAny}, | 280 {"-webkit-any(", CSSSelector::PseudoAny}, |
283 {"-webkit-any-link", CSSSelector::PseudoAnyLink}, | 281 {"-webkit-any-link", CSSSelector::PseudoAnyLink}, |
284 {"-webkit-autofill", CSSSelector::PseudoAutofill}, | 282 {"-webkit-autofill", CSSSelector::PseudoAutofill}, |
285 {"backdrop", CSSSelector::PseudoBackdrop}, | |
286 {"before", CSSSelector::PseudoBefore}, | |
287 {"checked", CSSSelector::PseudoChecked}, | |
288 {"default", CSSSelector::PseudoDefault}, | |
289 {"disabled", CSSSelector::PseudoDisabled}, | |
290 {"read-only", CSSSelector::PseudoReadOnly}, | |
291 {"read-write", CSSSelector::PseudoReadWrite}, | |
292 {"valid", CSSSelector::PseudoValid}, | |
293 {"invalid", CSSSelector::PseudoInvalid}, | |
294 {"-webkit-drag", CSSSelector::PseudoDrag}, | 283 {"-webkit-drag", CSSSelector::PseudoDrag}, |
295 {"empty", CSSSelector::PseudoEmpty}, | |
296 {"enabled", CSSSelector::PseudoEnabled}, | |
297 {"first-child", CSSSelector::PseudoFirstChild}, | |
298 {"first-letter", CSSSelector::PseudoFirstLetter}, | |
299 {"first-line", CSSSelector::PseudoFirstLine}, | |
300 {"first-of-type", CSSSelector::PseudoFirstOfType}, | |
301 {"-webkit-full-page-media", CSSSelector::PseudoFullPageMedia}, | 284 {"-webkit-full-page-media", CSSSelector::PseudoFullPageMedia}, |
302 {"nth-child(", CSSSelector::PseudoNthChild}, | 285 {"-webkit-full-screen", CSSSelector::PseudoFullScreen}, |
303 {"nth-of-type(", CSSSelector::PseudoNthOfType}, | 286 {"-webkit-full-screen-ancestor", CSSSelector::PseudoFullScreenAncestor}, |
304 {"nth-last-child(", CSSSelector::PseudoNthLastChild}, | 287 {"-webkit-full-screen-document", CSSSelector::PseudoFullScreenDocument}, |
305 {"nth-last-of-type(", CSSSelector::PseudoNthLastOfType}, | |
306 {"focus", CSSSelector::PseudoFocus}, | |
307 {"hover", CSSSelector::PseudoHover}, | |
308 {"indeterminate", CSSSelector::PseudoIndeterminate}, | |
309 {"last-child", CSSSelector::PseudoLastChild}, | |
310 {"last-of-type", CSSSelector::PseudoLastOfType}, | |
311 {"link", CSSSelector::PseudoLink}, | |
312 {"lang(", CSSSelector::PseudoLang}, | |
313 {"not(", CSSSelector::PseudoNot}, | |
314 {"only-child", CSSSelector::PseudoOnlyChild}, | |
315 {"only-of-type", CSSSelector::PseudoOnlyOfType}, | |
316 {"optional", CSSSelector::PseudoOptional}, | |
317 {"required", CSSSelector::PseudoRequired}, | |
318 {"-webkit-resizer", CSSSelector::PseudoResizer}, | 288 {"-webkit-resizer", CSSSelector::PseudoResizer}, |
319 {"root", CSSSelector::PseudoRoot}, | |
320 {"-webkit-scrollbar", CSSSelector::PseudoScrollbar}, | 289 {"-webkit-scrollbar", CSSSelector::PseudoScrollbar}, |
321 {"-webkit-scrollbar-button", CSSSelector::PseudoScrollbarButton}, | 290 {"-webkit-scrollbar-button", CSSSelector::PseudoScrollbarButton}, |
322 {"-webkit-scrollbar-corner", CSSSelector::PseudoScrollbarCorner}, | 291 {"-webkit-scrollbar-corner", CSSSelector::PseudoScrollbarCorner}, |
323 {"-webkit-scrollbar-thumb", CSSSelector::PseudoScrollbarThumb}, | 292 {"-webkit-scrollbar-thumb", CSSSelector::PseudoScrollbarThumb}, |
324 {"-webkit-scrollbar-track", CSSSelector::PseudoScrollbarTrack}, | 293 {"-webkit-scrollbar-track", CSSSelector::PseudoScrollbarTrack}, |
325 {"-webkit-scrollbar-track-piece", CSSSelector::PseudoScrollbarTrackPiece}, | 294 {"-webkit-scrollbar-track-piece", CSSSelector::PseudoScrollbarTrackPiece}, |
326 {"selection", CSSSelector::PseudoSelection}, | 295 {"active", CSSSelector::PseudoActive}, |
327 {"target", CSSSelector::PseudoTarget}, | 296 {"after", CSSSelector::PseudoAfter}, |
328 {"visited", CSSSelector::PseudoVisited}, | 297 {"backdrop", CSSSelector::PseudoBackdrop}, |
329 {"window-inactive", CSSSelector::PseudoWindowInactive}, | 298 {"before", CSSSelector::PseudoBefore}, |
| 299 {"checked", CSSSelector::PseudoChecked}, |
| 300 {"content", CSSSelector::PseudoContent}, |
| 301 {"corner-present", CSSSelector::PseudoCornerPresent}, |
| 302 {"cue", CSSSelector::PseudoWebKitCustomElement}, |
| 303 {"cue(", CSSSelector::PseudoCue}, |
330 {"decrement", CSSSelector::PseudoDecrement}, | 304 {"decrement", CSSSelector::PseudoDecrement}, |
331 {"increment", CSSSelector::PseudoIncrement}, | 305 {"default", CSSSelector::PseudoDefault}, |
332 {"start", CSSSelector::PseudoStart}, | 306 {"disabled", CSSSelector::PseudoDisabled}, |
| 307 {"double-button", CSSSelector::PseudoDoubleButton}, |
| 308 {"empty", CSSSelector::PseudoEmpty}, |
| 309 {"enabled", CSSSelector::PseudoEnabled}, |
333 {"end", CSSSelector::PseudoEnd}, | 310 {"end", CSSSelector::PseudoEnd}, |
| 311 {"first", CSSSelector::PseudoFirstPage}, |
| 312 {"first-child", CSSSelector::PseudoFirstChild}, |
| 313 {"first-letter", CSSSelector::PseudoFirstLetter}, |
| 314 {"first-line", CSSSelector::PseudoFirstLine}, |
| 315 {"first-of-type", CSSSelector::PseudoFirstOfType}, |
| 316 {"focus", CSSSelector::PseudoFocus}, |
| 317 {"future", CSSSelector::PseudoFutureCue}, |
334 {"horizontal", CSSSelector::PseudoHorizontal}, | 318 {"horizontal", CSSSelector::PseudoHorizontal}, |
335 {"vertical", CSSSelector::PseudoVertical}, | |
336 {"double-button", CSSSelector::PseudoDoubleButton}, | |
337 {"single-button", CSSSelector::PseudoSingleButton}, | |
338 {"no-button", CSSSelector::PseudoNoButton}, | |
339 {"corner-present", CSSSelector::PseudoCornerPresent}, | |
340 {"first", CSSSelector::PseudoFirstPage}, | |
341 {"left", CSSSelector::PseudoLeftPage}, | |
342 {"right", CSSSelector::PseudoRightPage}, | |
343 {"-webkit-full-screen", CSSSelector::PseudoFullScreen}, | |
344 {"-webkit-full-screen-document", CSSSelector::PseudoFullScreenDocument}, | |
345 {"-webkit-full-screen-ancestor", CSSSelector::PseudoFullScreenAncestor}, | |
346 {"cue(", CSSSelector::PseudoCue}, | |
347 {"cue", CSSSelector::PseudoWebKitCustomElement}, | |
348 {"future", CSSSelector::PseudoFutureCue}, | |
349 {"past", CSSSelector::PseudoPastCue}, | |
350 {"in-range", CSSSelector::PseudoInRange}, | |
351 {"out-of-range", CSSSelector::PseudoOutOfRange}, | |
352 {"scope", CSSSelector::PseudoScope}, | |
353 {"unresolved", CSSSelector::PseudoUnresolved}, | |
354 {"host", CSSSelector::PseudoHost}, | 319 {"host", CSSSelector::PseudoHost}, |
355 {"host(", CSSSelector::PseudoHost}, | 320 {"host(", CSSSelector::PseudoHost}, |
356 {"host-context(", CSSSelector::PseudoHostContext}, | 321 {"host-context(", CSSSelector::PseudoHostContext}, |
357 {"content", CSSSelector::PseudoContent}, | 322 {"hover", CSSSelector::PseudoHover}, |
| 323 {"in-range", CSSSelector::PseudoInRange}, |
| 324 {"increment", CSSSelector::PseudoIncrement}, |
| 325 {"indeterminate", CSSSelector::PseudoIndeterminate}, |
| 326 {"invalid", CSSSelector::PseudoInvalid}, |
| 327 {"lang(", CSSSelector::PseudoLang}, |
| 328 {"last-child", CSSSelector::PseudoLastChild}, |
| 329 {"last-of-type", CSSSelector::PseudoLastOfType}, |
| 330 {"left", CSSSelector::PseudoLeftPage}, |
| 331 {"link", CSSSelector::PseudoLink}, |
| 332 {"no-button", CSSSelector::PseudoNoButton}, |
| 333 {"not(", CSSSelector::PseudoNot}, |
| 334 {"nth-child(", CSSSelector::PseudoNthChild}, |
| 335 {"nth-last-child(", CSSSelector::PseudoNthLastChild}, |
| 336 {"nth-last-of-type(", CSSSelector::PseudoNthLastOfType}, |
| 337 {"nth-of-type(", CSSSelector::PseudoNthOfType}, |
| 338 {"only-child", CSSSelector::PseudoOnlyChild}, |
| 339 {"only-of-type", CSSSelector::PseudoOnlyOfType}, |
| 340 {"optional", CSSSelector::PseudoOptional}, |
| 341 {"out-of-range", CSSSelector::PseudoOutOfRange}, |
| 342 {"past", CSSSelector::PseudoPastCue}, |
| 343 {"read-only", CSSSelector::PseudoReadOnly}, |
| 344 {"read-write", CSSSelector::PseudoReadWrite}, |
| 345 {"required", CSSSelector::PseudoRequired}, |
| 346 {"right", CSSSelector::PseudoRightPage}, |
| 347 {"root", CSSSelector::PseudoRoot}, |
| 348 {"scope", CSSSelector::PseudoScope}, |
| 349 {"selection", CSSSelector::PseudoSelection}, |
358 {"shadow", CSSSelector::PseudoShadow}, | 350 {"shadow", CSSSelector::PseudoShadow}, |
| 351 {"single-button", CSSSelector::PseudoSingleButton}, |
| 352 {"start", CSSSelector::PseudoStart}, |
| 353 {"target", CSSSelector::PseudoTarget}, |
| 354 {"unresolved", CSSSelector::PseudoUnresolved}, |
| 355 {"valid", CSSSelector::PseudoValid}, |
| 356 {"vertical", CSSSelector::PseudoVertical}, |
| 357 {"visited", CSSSelector::PseudoVisited}, |
| 358 {"window-inactive", CSSSelector::PseudoWindowInactive}, |
359 }; | 359 }; |
360 | 360 |
361 static HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap() | 361 class NameToPseudoCompare { |
362 { | 362 public: |
363 static HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0; | 363 NameToPseudoCompare(const AtomicString& key) : m_key(key) { ASSERT(m_key.is8
Bit()); } |
364 if (!nameToPseudoType) { | |
365 nameToPseudoType = new HashMap<StringImpl*, CSSSelector::PseudoType>; | |
366 | 364 |
367 size_t pseudoCount = WTF_ARRAY_LENGTH(pseudoTypeMap); | 365 bool operator()(const NameToPseudoStruct& entry, const NameToPseudoStruct&) |
368 for (size_t i = 0; i < pseudoCount; i++) { | 366 { |
369 const char* str = pseudoTypeMap[i].string; | 367 ASSERT(entry.string); |
370 CSSSelector::PseudoType type; | 368 const char* key = reinterpret_cast<const char*>(m_key.characters8()); |
371 type = static_cast<CSSSelector::PseudoType>(pseudoTypeMap[i].type); | 369 // If strncmp returns 0, then either the keys are equal, or |m_key| sort
s before |entry|. |
372 // This is a one-time leak. | 370 return strncmp(entry.string, key, m_key.length()) < 0; |
373 AtomicString* name = new AtomicString(str, strlen(str), AtomicString
::ConstructFromLiteral); | |
374 nameToPseudoType->set(name->impl(), type); | |
375 } | |
376 } | 371 } |
377 | 372 |
378 return nameToPseudoType; | 373 private: |
| 374 const AtomicString& m_key; |
| 375 }; |
| 376 |
| 377 static CSSSelector::PseudoType nameToPseudoType(const AtomicString& name) |
| 378 { |
| 379 if (name.isNull() || !name.is8Bit()) |
| 380 return CSSSelector::PseudoUnknown; |
| 381 |
| 382 const NameToPseudoStruct* pseudoTypeMapEnd = pseudoTypeMap + WTF_ARRAY_LENGT
H(pseudoTypeMap); |
| 383 NameToPseudoStruct dummyKey = { 0, CSSSelector::PseudoUnknown }; |
| 384 const NameToPseudoStruct* match = std::lower_bound(pseudoTypeMap, pseudoType
MapEnd, dummyKey, NameToPseudoCompare(name)); |
| 385 if (match == pseudoTypeMapEnd || match->string != name.string()) |
| 386 return CSSSelector::PseudoUnknown; |
| 387 |
| 388 return static_cast<CSSSelector::PseudoType>(match->type); |
379 } | 389 } |
380 | 390 |
381 #ifndef NDEBUG | 391 #ifndef NDEBUG |
382 void CSSSelector::show(int indent) const | 392 void CSSSelector::show(int indent) const |
383 { | 393 { |
384 printf("%*sselectorText(): %s\n", indent, "", selectorText().ascii().data())
; | 394 printf("%*sselectorText(): %s\n", indent, "", selectorText().ascii().data())
; |
385 printf("%*sm_match: %d\n", indent, "", m_match); | 395 printf("%*sm_match: %d\n", indent, "", m_match); |
386 printf("%*sisCustomPseudoElement(): %d\n", indent, "", isCustomPseudoElement
()); | 396 printf("%*sisCustomPseudoElement(): %d\n", indent, "", isCustomPseudoElement
()); |
387 if (m_match != Tag) | 397 if (m_match != Tag) |
388 printf("%*svalue(): %s\n", indent, "", value().ascii().data()); | 398 printf("%*svalue(): %s\n", indent, "", value().ascii().data()); |
(...skipping 16 matching lines...) Expand all Loading... |
405 void CSSSelector::show() const | 415 void CSSSelector::show() const |
406 { | 416 { |
407 printf("\n******* CSSSelector::show(\"%s\") *******\n", selectorText().ascii
().data()); | 417 printf("\n******* CSSSelector::show(\"%s\") *******\n", selectorText().ascii
().data()); |
408 show(2); | 418 show(2); |
409 printf("******* end *******\n"); | 419 printf("******* end *******\n"); |
410 } | 420 } |
411 #endif | 421 #endif |
412 | 422 |
413 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name) | 423 CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name) |
414 { | 424 { |
415 if (name.isNull()) | 425 CSSSelector::PseudoType pseudoType = nameToPseudoType(name); |
416 return PseudoUnknown; | 426 if (pseudoType != PseudoUnknown) |
417 HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseu
doTypeMap(); | 427 return pseudoType; |
418 HashMap<StringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoT
ype->find(name.impl()); | |
419 | |
420 if (slot != nameToPseudoType->end()) | |
421 return slot->value; | |
422 | 428 |
423 if (name.startsWith("-webkit-")) | 429 if (name.startsWith("-webkit-")) |
424 return PseudoWebKitCustomElement; | 430 return PseudoWebKitCustomElement; |
425 if (name.startsWith("cue")) | 431 if (name.startsWith("cue")) |
426 return PseudoUserAgentCustomElement; | 432 return PseudoUserAgentCustomElement; |
427 | 433 |
428 return PseudoUnknown; | 434 return PseudoUnknown; |
429 } | 435 } |
430 | 436 |
431 void CSSSelector::extractPseudoType() const | 437 void CSSSelector::extractPseudoType() const |
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
878 return false; | 884 return false; |
879 return (count - m_b) % m_a == 0; | 885 return (count - m_b) % m_a == 0; |
880 } else { | 886 } else { |
881 if (count > m_b) | 887 if (count > m_b) |
882 return false; | 888 return false; |
883 return (m_b - count) % (-m_a) == 0; | 889 return (m_b - count) % (-m_a) == 0; |
884 } | 890 } |
885 } | 891 } |
886 | 892 |
887 } // namespace WebCore | 893 } // namespace WebCore |
OLD | NEW |