Index: Source/core/css/CSSSelector.cpp |
diff --git a/Source/core/css/CSSSelector.cpp b/Source/core/css/CSSSelector.cpp |
index 94238d4c17481b5b12a844c5c404e252577c8dc6..b06280e5613737b3aab5ffe11e772e670e308ce4 100644 |
--- a/Source/core/css/CSSSelector.cpp |
+++ b/Source/core/css/CSSSelector.cpp |
@@ -34,7 +34,6 @@ |
#include "wtf/HashMap.h" |
#include "wtf/StdLibExtras.h" |
#include "wtf/text/StringBuilder.h" |
-#include "wtf/text/StringHash.h" |
#ifndef NDEBUG |
#include <stdio.h> |
@@ -276,106 +275,117 @@ struct NameToPseudoStruct { |
unsigned type:8; |
}; |
+// This table should be kept sorted. |
const static NameToPseudoStruct pseudoTypeMap[] = { |
-{"active", CSSSelector::PseudoActive}, |
-{"after", CSSSelector::PseudoAfter}, |
{"-webkit-any(", CSSSelector::PseudoAny}, |
{"-webkit-any-link", CSSSelector::PseudoAnyLink}, |
{"-webkit-autofill", CSSSelector::PseudoAutofill}, |
+{"-webkit-drag", CSSSelector::PseudoDrag}, |
+{"-webkit-full-page-media", CSSSelector::PseudoFullPageMedia}, |
+{"-webkit-full-screen", CSSSelector::PseudoFullScreen}, |
+{"-webkit-full-screen-ancestor", CSSSelector::PseudoFullScreenAncestor}, |
+{"-webkit-full-screen-document", CSSSelector::PseudoFullScreenDocument}, |
+{"-webkit-resizer", CSSSelector::PseudoResizer}, |
+{"-webkit-scrollbar", CSSSelector::PseudoScrollbar}, |
+{"-webkit-scrollbar-button", CSSSelector::PseudoScrollbarButton}, |
+{"-webkit-scrollbar-corner", CSSSelector::PseudoScrollbarCorner}, |
+{"-webkit-scrollbar-thumb", CSSSelector::PseudoScrollbarThumb}, |
+{"-webkit-scrollbar-track", CSSSelector::PseudoScrollbarTrack}, |
+{"-webkit-scrollbar-track-piece", CSSSelector::PseudoScrollbarTrackPiece}, |
+{"active", CSSSelector::PseudoActive}, |
+{"after", CSSSelector::PseudoAfter}, |
{"backdrop", CSSSelector::PseudoBackdrop}, |
{"before", CSSSelector::PseudoBefore}, |
{"checked", CSSSelector::PseudoChecked}, |
+{"content", CSSSelector::PseudoContent}, |
+{"corner-present", CSSSelector::PseudoCornerPresent}, |
+{"cue", CSSSelector::PseudoWebKitCustomElement}, |
+{"cue(", CSSSelector::PseudoCue}, |
+{"decrement", CSSSelector::PseudoDecrement}, |
{"default", CSSSelector::PseudoDefault}, |
{"disabled", CSSSelector::PseudoDisabled}, |
-{"read-only", CSSSelector::PseudoReadOnly}, |
-{"read-write", CSSSelector::PseudoReadWrite}, |
-{"valid", CSSSelector::PseudoValid}, |
-{"invalid", CSSSelector::PseudoInvalid}, |
-{"-webkit-drag", CSSSelector::PseudoDrag}, |
+{"double-button", CSSSelector::PseudoDoubleButton}, |
{"empty", CSSSelector::PseudoEmpty}, |
{"enabled", CSSSelector::PseudoEnabled}, |
+{"end", CSSSelector::PseudoEnd}, |
+{"first", CSSSelector::PseudoFirstPage}, |
{"first-child", CSSSelector::PseudoFirstChild}, |
{"first-letter", CSSSelector::PseudoFirstLetter}, |
{"first-line", CSSSelector::PseudoFirstLine}, |
{"first-of-type", CSSSelector::PseudoFirstOfType}, |
-{"-webkit-full-page-media", CSSSelector::PseudoFullPageMedia}, |
-{"nth-child(", CSSSelector::PseudoNthChild}, |
-{"nth-of-type(", CSSSelector::PseudoNthOfType}, |
-{"nth-last-child(", CSSSelector::PseudoNthLastChild}, |
-{"nth-last-of-type(", CSSSelector::PseudoNthLastOfType}, |
{"focus", CSSSelector::PseudoFocus}, |
+{"future", CSSSelector::PseudoFutureCue}, |
+{"horizontal", CSSSelector::PseudoHorizontal}, |
+{"host", CSSSelector::PseudoHost}, |
+{"host(", CSSSelector::PseudoHost}, |
+{"host-context(", CSSSelector::PseudoHostContext}, |
{"hover", CSSSelector::PseudoHover}, |
+{"in-range", CSSSelector::PseudoInRange}, |
+{"increment", CSSSelector::PseudoIncrement}, |
{"indeterminate", CSSSelector::PseudoIndeterminate}, |
+{"invalid", CSSSelector::PseudoInvalid}, |
+{"lang(", CSSSelector::PseudoLang}, |
{"last-child", CSSSelector::PseudoLastChild}, |
{"last-of-type", CSSSelector::PseudoLastOfType}, |
+{"left", CSSSelector::PseudoLeftPage}, |
{"link", CSSSelector::PseudoLink}, |
-{"lang(", CSSSelector::PseudoLang}, |
+{"no-button", CSSSelector::PseudoNoButton}, |
{"not(", CSSSelector::PseudoNot}, |
+{"nth-child(", CSSSelector::PseudoNthChild}, |
+{"nth-last-child(", CSSSelector::PseudoNthLastChild}, |
+{"nth-last-of-type(", CSSSelector::PseudoNthLastOfType}, |
+{"nth-of-type(", CSSSelector::PseudoNthOfType}, |
{"only-child", CSSSelector::PseudoOnlyChild}, |
{"only-of-type", CSSSelector::PseudoOnlyOfType}, |
{"optional", CSSSelector::PseudoOptional}, |
+{"out-of-range", CSSSelector::PseudoOutOfRange}, |
+{"past", CSSSelector::PseudoPastCue}, |
+{"read-only", CSSSelector::PseudoReadOnly}, |
+{"read-write", CSSSelector::PseudoReadWrite}, |
{"required", CSSSelector::PseudoRequired}, |
-{"-webkit-resizer", CSSSelector::PseudoResizer}, |
+{"right", CSSSelector::PseudoRightPage}, |
{"root", CSSSelector::PseudoRoot}, |
-{"-webkit-scrollbar", CSSSelector::PseudoScrollbar}, |
-{"-webkit-scrollbar-button", CSSSelector::PseudoScrollbarButton}, |
-{"-webkit-scrollbar-corner", CSSSelector::PseudoScrollbarCorner}, |
-{"-webkit-scrollbar-thumb", CSSSelector::PseudoScrollbarThumb}, |
-{"-webkit-scrollbar-track", CSSSelector::PseudoScrollbarTrack}, |
-{"-webkit-scrollbar-track-piece", CSSSelector::PseudoScrollbarTrackPiece}, |
+{"scope", CSSSelector::PseudoScope}, |
{"selection", CSSSelector::PseudoSelection}, |
+{"shadow", CSSSelector::PseudoShadow}, |
+{"single-button", CSSSelector::PseudoSingleButton}, |
+{"start", CSSSelector::PseudoStart}, |
{"target", CSSSelector::PseudoTarget}, |
+{"unresolved", CSSSelector::PseudoUnresolved}, |
+{"valid", CSSSelector::PseudoValid}, |
+{"vertical", CSSSelector::PseudoVertical}, |
{"visited", CSSSelector::PseudoVisited}, |
{"window-inactive", CSSSelector::PseudoWindowInactive}, |
-{"decrement", CSSSelector::PseudoDecrement}, |
-{"increment", CSSSelector::PseudoIncrement}, |
-{"start", CSSSelector::PseudoStart}, |
-{"end", CSSSelector::PseudoEnd}, |
-{"horizontal", CSSSelector::PseudoHorizontal}, |
-{"vertical", CSSSelector::PseudoVertical}, |
-{"double-button", CSSSelector::PseudoDoubleButton}, |
-{"single-button", CSSSelector::PseudoSingleButton}, |
-{"no-button", CSSSelector::PseudoNoButton}, |
-{"corner-present", CSSSelector::PseudoCornerPresent}, |
-{"first", CSSSelector::PseudoFirstPage}, |
-{"left", CSSSelector::PseudoLeftPage}, |
-{"right", CSSSelector::PseudoRightPage}, |
-{"-webkit-full-screen", CSSSelector::PseudoFullScreen}, |
-{"-webkit-full-screen-document", CSSSelector::PseudoFullScreenDocument}, |
-{"-webkit-full-screen-ancestor", CSSSelector::PseudoFullScreenAncestor}, |
-{"cue(", CSSSelector::PseudoCue}, |
-{"cue", CSSSelector::PseudoWebKitCustomElement}, |
-{"future", CSSSelector::PseudoFutureCue}, |
-{"past", CSSSelector::PseudoPastCue}, |
-{"in-range", CSSSelector::PseudoInRange}, |
-{"out-of-range", CSSSelector::PseudoOutOfRange}, |
-{"scope", CSSSelector::PseudoScope}, |
-{"unresolved", CSSSelector::PseudoUnresolved}, |
-{"host", CSSSelector::PseudoHost}, |
-{"host(", CSSSelector::PseudoHost}, |
-{"host-context(", CSSSelector::PseudoHostContext}, |
-{"content", CSSSelector::PseudoContent}, |
-{"shadow", CSSSelector::PseudoShadow}, |
}; |
-static HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap() |
-{ |
- static HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0; |
- if (!nameToPseudoType) { |
- nameToPseudoType = new HashMap<StringImpl*, CSSSelector::PseudoType>; |
- |
- size_t pseudoCount = WTF_ARRAY_LENGTH(pseudoTypeMap); |
- for (size_t i = 0; i < pseudoCount; i++) { |
- const char* str = pseudoTypeMap[i].string; |
- CSSSelector::PseudoType type; |
- type = static_cast<CSSSelector::PseudoType>(pseudoTypeMap[i].type); |
- // This is a one-time leak. |
- AtomicString* name = new AtomicString(str, strlen(str), AtomicString::ConstructFromLiteral); |
- nameToPseudoType->set(name->impl(), type); |
- } |
+class NameToPseudoCompare { |
+public: |
+ NameToPseudoCompare(const AtomicString& key) : m_key(key) { ASSERT(m_key.is8Bit()); } |
+ |
+ bool operator()(const NameToPseudoStruct& entry, const NameToPseudoStruct&) |
+ { |
+ ASSERT(entry.string); |
+ const char* key = reinterpret_cast<const char*>(m_key.characters8()); |
+ // If strncmp returns 0, then either the keys are equal, or |m_key| sorts before |entry|. |
+ return strncmp(entry.string, key, m_key.length()) < 0; |
} |
- return nameToPseudoType; |
+private: |
+ const AtomicString& m_key; |
+}; |
+ |
+static CSSSelector::PseudoType nameToPseudoType(const AtomicString& name) |
+{ |
+ if (name.isNull() || !name.is8Bit()) |
+ return CSSSelector::PseudoUnknown; |
+ |
+ const NameToPseudoStruct* pseudoTypeMapEnd = pseudoTypeMap + WTF_ARRAY_LENGTH(pseudoTypeMap); |
+ NameToPseudoStruct dummyKey = { 0, CSSSelector::PseudoUnknown }; |
+ const NameToPseudoStruct* match = std::lower_bound(pseudoTypeMap, pseudoTypeMapEnd, dummyKey, NameToPseudoCompare(name)); |
+ if (match == pseudoTypeMapEnd || match->string != name.string()) |
+ return CSSSelector::PseudoUnknown; |
+ |
+ return static_cast<CSSSelector::PseudoType>(match->type); |
} |
#ifndef NDEBUG |
@@ -412,13 +422,9 @@ void CSSSelector::show() const |
CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name) |
{ |
- if (name.isNull()) |
- return PseudoUnknown; |
- HashMap<StringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap(); |
- HashMap<StringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl()); |
- |
- if (slot != nameToPseudoType->end()) |
- return slot->value; |
+ CSSSelector::PseudoType pseudoType = nameToPseudoType(name); |
+ if (pseudoType != PseudoUnknown) |
+ return pseudoType; |
if (name.startsWith("-webkit-")) |
return PseudoWebKitCustomElement; |