1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/logging.h" 6 #include "chrome/browser/autocomplete/autocomplete_match.h" 7 #include "grit/theme_resources.h" 8 9 // AutocompleteMatch ---------------------------------------------------------- 10 11 AutocompleteMatch::AutocompleteMatch() 12 : provider(NULL), 13 relevance(0), 14 deletable(false), 15 inline_autocomplete_offset(string16::npos), 16 transition(PageTransition::GENERATED), 17 is_history_what_you_typed_match(false), 18 type(SEARCH_WHAT_YOU_TYPED), 19 template_url(NULL), 20 starred(false), 21 from_previous(false) { 22 } 23 24 AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider, 25 int relevance, 26 bool deletable, 27 Type type) 28 : provider(provider), 29 relevance(relevance), 30 deletable(deletable), 31 inline_autocomplete_offset(string16::npos), 32 transition(PageTransition::TYPED), 33 is_history_what_you_typed_match(false), 34 type(type), 35 template_url(NULL), 36 starred(false), 37 from_previous(false) { 38 } 39 40 AutocompleteMatch::~AutocompleteMatch() { 41 } 42 43 // static 44 std::string AutocompleteMatch::TypeToString(Type type) { 45 const char* strings[NUM_TYPES] = { 46 "url-what-you-typed", 47 "history-url", 48 "history-title", 49 "history-body", 50 "history-keyword", 51 "navsuggest", 52 "search-what-you-typed", 53 "search-history", 54 "search-suggest", 55 "search-other-engine", 56 "extension-app", 57 }; 58 DCHECK(arraysize(strings) == NUM_TYPES); 59 return strings[type]; 60 } 61 62 // static 63 int AutocompleteMatch::TypeToIcon(Type type) { 64 int icons[NUM_TYPES] = { 65 IDR_OMNIBOX_HTTP, 66 IDR_OMNIBOX_HTTP, 67 IDR_OMNIBOX_HISTORY, 68 IDR_OMNIBOX_HISTORY, 69 IDR_OMNIBOX_HISTORY, 70 IDR_OMNIBOX_HTTP, 71 IDR_OMNIBOX_SEARCH, 72 IDR_OMNIBOX_SEARCH, 73 IDR_OMNIBOX_SEARCH, 74 IDR_OMNIBOX_SEARCH, 75 IDR_OMNIBOX_EXTENSION_APP, 76 }; 77 DCHECK(arraysize(icons) == NUM_TYPES); 78 return icons[type]; 79 } 80 81 // static 82 bool AutocompleteMatch::MoreRelevant(const AutocompleteMatch& elem1, 83 const AutocompleteMatch& elem2) { 84 // For equal-relevance matches, we sort alphabetically, so that providers 85 // who return multiple elements at the same priority get a "stable" sort 86 // across multiple updates. 87 if (elem1.relevance == elem2.relevance) 88 return elem1.contents > elem2.contents; 89 90 return elem1.relevance > elem2.relevance; 91 } 92 93 // static 94 bool AutocompleteMatch::DestinationSortFunc(const AutocompleteMatch& elem1, 95 const AutocompleteMatch& elem2) { 96 // Sort identical destination_urls together. Place the most relevant matches 97 // first, so that when we call std::unique(), these are the ones that get 98 // preserved. 99 return (elem1.destination_url != elem2.destination_url) ? 100 (elem1.destination_url < elem2.destination_url) : 101 MoreRelevant(elem1, elem2); 102 } 103 104 // static 105 bool AutocompleteMatch::DestinationsEqual(const AutocompleteMatch& elem1, 106 const AutocompleteMatch& elem2) { 107 return elem1.destination_url == elem2.destination_url; 108 } 109 110 // static 111 void AutocompleteMatch::ClassifyMatchInString( 112 const string16& find_text, 113 const string16& text, 114 int style, 115 ACMatchClassifications* classification) { 116 ClassifyLocationInString(text.find(find_text), find_text.length(), 117 text.length(), style, classification); 118 } 119 120 void AutocompleteMatch::ClassifyLocationInString( 121 size_t match_location, 122 size_t match_length, 123 size_t overall_length, 124 int style, 125 ACMatchClassifications* classification) { 126 classification->clear(); 127 128 // Don't classify anything about an empty string 129 // (AutocompleteMatch::Validate() checks this). 130 if (overall_length == 0) 131 return; 132 133 // Mark pre-match portion of string (if any). 134 if (match_location != 0) { 135 classification->push_back(ACMatchClassification(0, style)); 136 } 137 138 // Mark matching portion of string. 139 if (match_location == string16::npos) { 140 // No match, above classification will suffice for whole string. 141 return; 142 } 143 // Classifying an empty match makes no sense and will lead to validation 144 // errors later. 145 DCHECK(match_length > 0); 146 classification->push_back(ACMatchClassification(match_location, 147 (style | ACMatchClassification::MATCH) & ~ACMatchClassification::DIM)); 148 149 // Mark post-match portion of string (if any). 150 const size_t after_match(match_location + match_length); 151 if (after_match < overall_length) { 152 classification->push_back(ACMatchClassification(after_match, style)); 153 } 154 } 155 156 #ifndef NDEBUG 157 void AutocompleteMatch::Validate() const { 158 ValidateClassifications(contents, contents_class); 159 ValidateClassifications(description, description_class); 160 } 161 162 void AutocompleteMatch::ValidateClassifications( 163 const string16& text, 164 const ACMatchClassifications& classifications) const { 165 if (text.empty()) { 166 DCHECK(classifications.size() == 0); 167 return; 168 } 169 170 // The classifications should always cover the whole string. 171 DCHECK(!classifications.empty()) << "No classification for text"; 172 DCHECK(classifications[0].offset == 0) << "Classification misses beginning"; 173 if (classifications.size() == 1) 174 return; 175 176 // The classifications should always be sorted. 177 size_t last_offset = classifications[0].offset; 178 for (ACMatchClassifications::const_iterator i(classifications.begin() + 1); 179 i != classifications.end(); ++i) { 180 DCHECK(i->offset > last_offset) << "Classification unsorted"; 181 DCHECK(i->offset < text.length()) << "Classification out of bounds"; 182 last_offset = i->offset; 183 } 184 } 185 #endif 186