[email protected] | 8f740548 | 2011-04-13 11:08:52 | [diff] [blame^] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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), |
[email protected] | a2fedb1e | 2011-01-25 15:23:36 | [diff] [blame] | 15 | inline_autocomplete_offset(string16::npos), |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 16 | transition(PageTransition::GENERATED), |
| 17 | is_history_what_you_typed_match(false), |
| 18 | type(SEARCH_WHAT_YOU_TYPED), |
| 19 | template_url(NULL), |
[email protected] | 7abfb346 | 2011-01-31 16:43:06 | [diff] [blame] | 20 | starred(false), |
| 21 | from_previous(false) { |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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), |
[email protected] | a2fedb1e | 2011-01-25 15:23:36 | [diff] [blame] | 31 | inline_autocomplete_offset(string16::npos), |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 32 | transition(PageTransition::TYPED), |
| 33 | is_history_what_you_typed_match(false), |
| 34 | type(type), |
| 35 | template_url(NULL), |
[email protected] | 7abfb346 | 2011-01-31 16:43:06 | [diff] [blame] | 36 | starred(false), |
| 37 | from_previous(false) { |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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", |
[email protected] | 8f740548 | 2011-04-13 11:08:52 | [diff] [blame^] | 56 | "extension-app", |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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, |
[email protected] | 8f740548 | 2011-04-13 11:08:52 | [diff] [blame^] | 75 | IDR_OMNIBOX_EXTENSION_APP, |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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 | |
[email protected] | dff945e | 2011-01-20 17:45:01 | [diff] [blame] | 90 | return elem1.relevance > elem2.relevance; |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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( |
[email protected] | a2fedb1e | 2011-01-25 15:23:36 | [diff] [blame] | 112 | const string16& find_text, |
| 113 | const string16& text, |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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. |
[email protected] | a2fedb1e | 2011-01-25 15:23:36 | [diff] [blame] | 139 | if (match_location == string16::npos) { |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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( |
[email protected] | a2fedb1e | 2011-01-25 15:23:36 | [diff] [blame] | 163 | const string16& text, |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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. |
[email protected] | 6775e40a | 2011-03-04 21:03:47 | [diff] [blame] | 171 | DCHECK(!classifications.empty()) << "No classification for text"; |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 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 |