[email protected] | e7e0771 | 2014-07-30 08:53:23 | [diff] [blame] | 1 | // Copyright 2014 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 | |
[email protected] | b1c5ab68 | 2014-08-07 11:53:17 | [diff] [blame] | 5 | #include "components/omnibox/autocomplete_match.h" |
[email protected] | 371dab1 | 2012-06-01 03:23:55 | [diff] [blame] | 6 | |
[email protected] | 5281d42 | 2012-07-28 21:37:10 | [diff] [blame] | 7 | #include "base/i18n/time_formatting.h" |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 8 | #include "base/logging.h" |
[email protected] | 98570e1 | 2013-06-10 19:54:22 | [diff] [blame] | 9 | #include "base/strings/string16.h" |
[email protected] | 3ea1b18 | 2013-02-08 22:38:41 | [diff] [blame] | 10 | #include "base/strings/string_number_conversions.h" |
[email protected] | 98570e1 | 2013-06-10 19:54:22 | [diff] [blame] | 11 | #include "base/strings/string_util.h" |
[email protected] | 135cb80 | 2013-06-09 16:44:20 | [diff] [blame] | 12 | #include "base/strings/utf_string_conversions.h" |
[email protected] | 4dcb797 | 2013-06-28 15:15:41 | [diff] [blame] | 13 | #include "base/time/time.h" |
[email protected] | b1c5ab68 | 2014-08-07 11:53:17 | [diff] [blame] | 14 | #include "components/omnibox/autocomplete_provider.h" |
[email protected] | d550cb0 | 2014-06-25 06:48:11 | [diff] [blame] | 15 | #include "components/search_engines/template_url.h" |
[email protected] | bf5c532d | 2014-07-05 00:29:53 | [diff] [blame] | 16 | #include "components/search_engines/template_url_service.h" |
[email protected] | 4bafb26 | 2014-07-29 10:48:53 | [diff] [blame] | 17 | #include "grit/component_scaled_resources.h" |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 18 | |
[email protected] | 3b81314d | 2012-09-11 02:48:41 | [diff] [blame] | 19 | namespace { |
| 20 | |
| 21 | bool IsTrivialClassification(const ACMatchClassifications& classifications) { |
| 22 | return classifications.empty() || |
| 23 | ((classifications.size() == 1) && |
| 24 | (classifications.back().style == ACMatchClassification::NONE)); |
| 25 | } |
| 26 | |
| 27 | } // namespace |
| 28 | |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 29 | // AutocompleteMatch ---------------------------------------------------------- |
| 30 | |
[email protected] | 531e034 | 2011-11-10 15:08:41 | [diff] [blame] | 31 | // static |
[email protected] | b6775d78 | 2013-12-25 20:04:53 | [diff] [blame] | 32 | const base::char16 AutocompleteMatch::kInvalidChars[] = { |
[email protected] | 531e034 | 2011-11-10 15:08:41 | [diff] [blame] | 33 | '\n', '\r', '\t', |
| 34 | 0x2028, // Line separator |
| 35 | 0x2029, // Paragraph separator |
| 36 | 0 |
| 37 | }; |
| 38 | |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 39 | AutocompleteMatch::AutocompleteMatch() |
| 40 | : provider(NULL), |
| 41 | relevance(0), |
[email protected] | cf6256f | 2012-06-12 23:36:01 | [diff] [blame] | 42 | typed_count(-1), |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 43 | deletable(false), |
[email protected] | 45f89a9 | 2013-08-12 13:41:36 | [diff] [blame] | 44 | allowed_to_be_default_match(false), |
[email protected] | 2905f74 | 2011-10-13 03:51:58 | [diff] [blame] | 45 | transition(content::PAGE_TRANSITION_GENERATED), |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 46 | is_history_what_you_typed_match(false), |
[email protected] | b7f64d74 | 2013-05-21 04:04:04 | [diff] [blame] | 47 | type(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED), |
[email protected] | 7abfb346 | 2011-01-31 16:43:06 | [diff] [blame] | 48 | from_previous(false) { |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider, |
| 52 | int relevance, |
| 53 | bool deletable, |
| 54 | Type type) |
| 55 | : provider(provider), |
| 56 | relevance(relevance), |
[email protected] | cf6256f | 2012-06-12 23:36:01 | [diff] [blame] | 57 | typed_count(-1), |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 58 | deletable(deletable), |
[email protected] | 45f89a9 | 2013-08-12 13:41:36 | [diff] [blame] | 59 | allowed_to_be_default_match(false), |
[email protected] | 2905f74 | 2011-10-13 03:51:58 | [diff] [blame] | 60 | transition(content::PAGE_TRANSITION_TYPED), |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 61 | is_history_what_you_typed_match(false), |
| 62 | type(type), |
[email protected] | 7abfb346 | 2011-01-31 16:43:06 | [diff] [blame] | 63 | from_previous(false) { |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 64 | } |
| 65 | |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 66 | AutocompleteMatch::AutocompleteMatch(const AutocompleteMatch& match) |
| 67 | : provider(match.provider), |
| 68 | relevance(match.relevance), |
[email protected] | cf6256f | 2012-06-12 23:36:01 | [diff] [blame] | 69 | typed_count(match.typed_count), |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 70 | deletable(match.deletable), |
| 71 | fill_into_edit(match.fill_into_edit), |
[email protected] | 518024c | 2013-07-19 23:40:25 | [diff] [blame] | 72 | inline_autocompletion(match.inline_autocompletion), |
[email protected] | 45f89a9 | 2013-08-12 13:41:36 | [diff] [blame] | 73 | allowed_to_be_default_match(match.allowed_to_be_default_match), |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 74 | destination_url(match.destination_url), |
| 75 | stripped_destination_url(match.stripped_destination_url), |
| 76 | contents(match.contents), |
| 77 | contents_class(match.contents_class), |
| 78 | description(match.description), |
| 79 | description_class(match.description_class), |
[email protected] | 6ae91fa39 | 2014-05-17 17:41:31 | [diff] [blame] | 80 | answer_contents(match.answer_contents), |
| 81 | answer_type(match.answer_type), |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 82 | transition(match.transition), |
| 83 | is_history_what_you_typed_match(match.is_history_what_you_typed_match), |
| 84 | type(match.type), |
[email protected] | bca359b | 2012-06-24 07:53:04 | [diff] [blame] | 85 | associated_keyword(match.associated_keyword.get() ? |
| 86 | new AutocompleteMatch(*match.associated_keyword) : NULL), |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 87 | keyword(match.keyword), |
[email protected] | bca359b | 2012-06-24 07:53:04 | [diff] [blame] | 88 | from_previous(match.from_previous), |
| 89 | search_terms_args(match.search_terms_args.get() ? |
| 90 | new TemplateURLRef::SearchTermsArgs(*match.search_terms_args) : |
[email protected] | 5281d42 | 2012-07-28 21:37:10 | [diff] [blame] | 91 | NULL), |
[email protected] | 9caafa2 | 2014-02-28 01:26:13 | [diff] [blame] | 92 | additional_info(match.additional_info), |
| 93 | duplicate_matches(match.duplicate_matches) { |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 94 | } |
| 95 | |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 96 | AutocompleteMatch::~AutocompleteMatch() { |
| 97 | } |
| 98 | |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 99 | AutocompleteMatch& AutocompleteMatch::operator=( |
| 100 | const AutocompleteMatch& match) { |
| 101 | if (this == &match) |
| 102 | return *this; |
| 103 | |
| 104 | provider = match.provider; |
| 105 | relevance = match.relevance; |
[email protected] | cf6256f | 2012-06-12 23:36:01 | [diff] [blame] | 106 | typed_count = match.typed_count; |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 107 | deletable = match.deletable; |
| 108 | fill_into_edit = match.fill_into_edit; |
[email protected] | 518024c | 2013-07-19 23:40:25 | [diff] [blame] | 109 | inline_autocompletion = match.inline_autocompletion; |
[email protected] | 45f89a9 | 2013-08-12 13:41:36 | [diff] [blame] | 110 | allowed_to_be_default_match = match.allowed_to_be_default_match; |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 111 | destination_url = match.destination_url; |
| 112 | stripped_destination_url = match.stripped_destination_url; |
| 113 | contents = match.contents; |
| 114 | contents_class = match.contents_class; |
| 115 | description = match.description; |
| 116 | description_class = match.description_class; |
[email protected] | 6ae91fa39 | 2014-05-17 17:41:31 | [diff] [blame] | 117 | answer_contents = match.answer_contents; |
| 118 | answer_type = match.answer_type; |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 119 | transition = match.transition; |
| 120 | is_history_what_you_typed_match = match.is_history_what_you_typed_match; |
| 121 | type = match.type; |
| 122 | associated_keyword.reset(match.associated_keyword.get() ? |
| 123 | new AutocompleteMatch(*match.associated_keyword) : NULL); |
| 124 | keyword = match.keyword; |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 125 | from_previous = match.from_previous; |
[email protected] | bca359b | 2012-06-24 07:53:04 | [diff] [blame] | 126 | search_terms_args.reset(match.search_terms_args.get() ? |
| 127 | new TemplateURLRef::SearchTermsArgs(*match.search_terms_args) : NULL); |
[email protected] | 5281d42 | 2012-07-28 21:37:10 | [diff] [blame] | 128 | additional_info = match.additional_info; |
[email protected] | 9caafa2 | 2014-02-28 01:26:13 | [diff] [blame] | 129 | duplicate_matches = match.duplicate_matches; |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 130 | return *this; |
| 131 | } |
| 132 | |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 133 | // static |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 134 | int AutocompleteMatch::TypeToIcon(Type type) { |
[email protected] | fc65f27 | 2011-06-28 22:21:30 | [diff] [blame] | 135 | int icons[] = { |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 136 | IDR_OMNIBOX_HTTP, |
| 137 | IDR_OMNIBOX_HTTP, |
[email protected] | c37ad9e | 2012-06-12 04:57:13 | [diff] [blame] | 138 | IDR_OMNIBOX_HTTP, |
| 139 | IDR_OMNIBOX_HTTP, |
| 140 | IDR_OMNIBOX_HTTP, |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 141 | IDR_OMNIBOX_HTTP, |
| 142 | IDR_OMNIBOX_SEARCH, |
| 143 | IDR_OMNIBOX_SEARCH, |
| 144 | IDR_OMNIBOX_SEARCH, |
| 145 | IDR_OMNIBOX_SEARCH, |
[email protected] | 2c03c06b | 2013-12-11 20:45:02 | [diff] [blame] | 146 | IDR_OMNIBOX_SEARCH, |
| 147 | IDR_OMNIBOX_SEARCH, |
| 148 | IDR_OMNIBOX_SEARCH, |
| 149 | IDR_OMNIBOX_SEARCH, |
[email protected] | 8f740548 | 2011-04-13 11:08:52 | [diff] [blame] | 150 | IDR_OMNIBOX_EXTENSION_APP, |
[email protected] | dbacefb | 2012-09-12 03:32:06 | [diff] [blame] | 151 | IDR_OMNIBOX_SEARCH, |
[email protected] | 2532060 | 2012-10-18 22:05:56 | [diff] [blame] | 152 | IDR_OMNIBOX_HTTP, |
[email protected] | 78981d8c | 2014-05-09 15:05:47 | [diff] [blame] | 153 | IDR_OMNIBOX_HTTP, |
[email protected] | 457861f | 2014-06-13 04:26:14 | [diff] [blame] | 154 | IDR_OMNIBOX_SEARCH, |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 155 | }; |
[email protected] | b7f64d74 | 2013-05-21 04:04:04 | [diff] [blame] | 156 | COMPILE_ASSERT(arraysize(icons) == AutocompleteMatchType::NUM_TYPES, |
[email protected] | fc65f27 | 2011-06-28 22:21:30 | [diff] [blame] | 157 | icons_array_must_match_type_enum); |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 158 | return icons[type]; |
| 159 | } |
| 160 | |
| 161 | // static |
| 162 | bool AutocompleteMatch::MoreRelevant(const AutocompleteMatch& elem1, |
| 163 | const AutocompleteMatch& elem2) { |
| 164 | // For equal-relevance matches, we sort alphabetically, so that providers |
| 165 | // who return multiple elements at the same priority get a "stable" sort |
| 166 | // across multiple updates. |
[email protected] | 033f342 | 2012-03-13 21:24:18 | [diff] [blame] | 167 | return (elem1.relevance == elem2.relevance) ? |
| 168 | (elem1.contents < elem2.contents) : (elem1.relevance > elem2.relevance); |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | // static |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 172 | bool AutocompleteMatch::DestinationsEqual(const AutocompleteMatch& elem1, |
| 173 | const AutocompleteMatch& elem2) { |
[email protected] | 00193bf | 2012-09-15 14:52:50 | [diff] [blame] | 174 | if (elem1.stripped_destination_url.is_empty() && |
| 175 | elem2.stripped_destination_url.is_empty()) |
| 176 | return false; |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 177 | return elem1.stripped_destination_url == elem2.stripped_destination_url; |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | // static |
| 181 | void AutocompleteMatch::ClassifyMatchInString( |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 182 | const base::string16& find_text, |
| 183 | const base::string16& text, |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 184 | int style, |
| 185 | ACMatchClassifications* classification) { |
| 186 | ClassifyLocationInString(text.find(find_text), find_text.length(), |
| 187 | text.length(), style, classification); |
| 188 | } |
| 189 | |
[email protected] | 24d692aa | 2011-05-25 23:07:58 | [diff] [blame] | 190 | // static |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 191 | void AutocompleteMatch::ClassifyLocationInString( |
| 192 | size_t match_location, |
| 193 | size_t match_length, |
| 194 | size_t overall_length, |
| 195 | int style, |
| 196 | ACMatchClassifications* classification) { |
| 197 | classification->clear(); |
| 198 | |
| 199 | // Don't classify anything about an empty string |
| 200 | // (AutocompleteMatch::Validate() checks this). |
| 201 | if (overall_length == 0) |
| 202 | return; |
| 203 | |
| 204 | // Mark pre-match portion of string (if any). |
| 205 | if (match_location != 0) { |
| 206 | classification->push_back(ACMatchClassification(0, style)); |
| 207 | } |
| 208 | |
| 209 | // Mark matching portion of string. |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 210 | if (match_location == base::string16::npos) { |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 211 | // No match, above classification will suffice for whole string. |
| 212 | return; |
| 213 | } |
| 214 | // Classifying an empty match makes no sense and will lead to validation |
| 215 | // errors later. |
[email protected] | eac4499 | 2012-02-14 21:39:35 | [diff] [blame] | 216 | DCHECK_GT(match_length, 0U); |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 217 | classification->push_back(ACMatchClassification(match_location, |
| 218 | (style | ACMatchClassification::MATCH) & ~ACMatchClassification::DIM)); |
| 219 | |
| 220 | // Mark post-match portion of string (if any). |
| 221 | const size_t after_match(match_location + match_length); |
| 222 | if (after_match < overall_length) { |
| 223 | classification->push_back(ACMatchClassification(after_match, style)); |
| 224 | } |
| 225 | } |
| 226 | |
[email protected] | 5595f40d | 2011-10-28 17:29:18 | [diff] [blame] | 227 | // static |
[email protected] | 3b81314d | 2012-09-11 02:48:41 | [diff] [blame] | 228 | AutocompleteMatch::ACMatchClassifications |
| 229 | AutocompleteMatch::MergeClassifications( |
| 230 | const ACMatchClassifications& classifications1, |
| 231 | const ACMatchClassifications& classifications2) { |
| 232 | // We must return the empty vector only if both inputs are truly empty. |
| 233 | // The result of merging an empty vector with a single (0, NONE) |
| 234 | // classification is the latter one-entry vector. |
| 235 | if (IsTrivialClassification(classifications1)) |
| 236 | return classifications2.empty() ? classifications1 : classifications2; |
| 237 | if (IsTrivialClassification(classifications2)) |
| 238 | return classifications1; |
| 239 | |
| 240 | ACMatchClassifications output; |
| 241 | for (ACMatchClassifications::const_iterator i = classifications1.begin(), |
| 242 | j = classifications2.begin(); i != classifications1.end();) { |
| 243 | AutocompleteMatch::AddLastClassificationIfNecessary(&output, |
| 244 | std::max(i->offset, j->offset), i->style | j->style); |
| 245 | const size_t next_i_offset = (i + 1) == classifications1.end() ? |
| 246 | static_cast<size_t>(-1) : (i + 1)->offset; |
| 247 | const size_t next_j_offset = (j + 1) == classifications2.end() ? |
| 248 | static_cast<size_t>(-1) : (j + 1)->offset; |
| 249 | if (next_i_offset >= next_j_offset) |
| 250 | ++j; |
| 251 | if (next_j_offset >= next_i_offset) |
| 252 | ++i; |
| 253 | } |
| 254 | |
| 255 | return output; |
| 256 | } |
| 257 | |
| 258 | // static |
[email protected] | 9d2b5f3b | 2012-03-14 21:34:32 | [diff] [blame] | 259 | std::string AutocompleteMatch::ClassificationsToString( |
| 260 | const ACMatchClassifications& classifications) { |
| 261 | std::string serialized_classifications; |
| 262 | for (size_t i = 0; i < classifications.size(); ++i) { |
| 263 | if (i) |
| 264 | serialized_classifications += ','; |
| 265 | serialized_classifications += base::IntToString(classifications[i].offset) + |
| 266 | ',' + base::IntToString(classifications[i].style); |
| 267 | } |
| 268 | return serialized_classifications; |
| 269 | } |
| 270 | |
| 271 | // static |
| 272 | ACMatchClassifications AutocompleteMatch::ClassificationsFromString( |
| 273 | const std::string& serialized_classifications) { |
| 274 | ACMatchClassifications classifications; |
| 275 | std::vector<std::string> tokens; |
| 276 | Tokenize(serialized_classifications, ",", &tokens); |
| 277 | DCHECK(!(tokens.size() & 1)); // The number of tokens should be even. |
| 278 | for (size_t i = 0; i < tokens.size(); i += 2) { |
| 279 | int classification_offset = 0; |
| 280 | int classification_style = ACMatchClassification::NONE; |
| 281 | if (!base::StringToInt(tokens[i], &classification_offset) || |
| 282 | !base::StringToInt(tokens[i + 1], &classification_style)) { |
| 283 | NOTREACHED(); |
| 284 | return classifications; |
| 285 | } |
| 286 | classifications.push_back(ACMatchClassification(classification_offset, |
| 287 | classification_style)); |
| 288 | } |
| 289 | return classifications; |
| 290 | } |
| 291 | |
| 292 | // static |
| 293 | void AutocompleteMatch::AddLastClassificationIfNecessary( |
| 294 | ACMatchClassifications* classifications, |
| 295 | size_t offset, |
| 296 | int style) { |
| 297 | DCHECK(classifications); |
| 298 | if (classifications->empty() || classifications->back().style != style) { |
| 299 | DCHECK(classifications->empty() || |
| 300 | (offset > classifications->back().offset)); |
| 301 | classifications->push_back(ACMatchClassification(offset, style)); |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | // static |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 306 | base::string16 AutocompleteMatch::SanitizeString(const base::string16& text) { |
[email protected] | 5595f40d | 2011-10-28 17:29:18 | [diff] [blame] | 307 | // NOTE: This logic is mirrored by |sanitizeString()| in |
[email protected] | e87032e | 2013-03-11 00:17:14 | [diff] [blame] | 308 | // omnibox_custom_bindings.js. |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 309 | base::string16 result; |
[email protected] | 8af69c6c | 2014-03-03 19:05:31 | [diff] [blame] | 310 | base::TrimWhitespace(text, base::TRIM_LEADING, &result); |
[email protected] | 466c986 | 2013-12-03 22:05:28 | [diff] [blame] | 311 | base::RemoveChars(result, kInvalidChars, &result); |
[email protected] | 5595f40d | 2011-10-28 17:29:18 | [diff] [blame] | 312 | return result; |
| 313 | } |
| 314 | |
[email protected] | 749e7ae0 | 2012-09-05 18:47:46 | [diff] [blame] | 315 | // static |
| 316 | bool AutocompleteMatch::IsSearchType(Type type) { |
[email protected] | b7f64d74 | 2013-05-21 04:04:04 | [diff] [blame] | 317 | return type == AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED || |
| 318 | type == AutocompleteMatchType::SEARCH_HISTORY || |
| 319 | type == AutocompleteMatchType::SEARCH_SUGGEST || |
[email protected] | ef613d38 | 2014-03-25 23:25:58 | [diff] [blame] | 320 | type == AutocompleteMatchType::SEARCH_OTHER_ENGINE || |
| 321 | IsSpecializedSearchType(type); |
| 322 | } |
| 323 | |
| 324 | // static |
| 325 | bool AutocompleteMatch::IsSpecializedSearchType(Type type) { |
| 326 | return type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY || |
[email protected] | e264dbea | 2014-03-11 10:08:48 | [diff] [blame] | 327 | type == AutocompleteMatchType::SEARCH_SUGGEST_INFINITE || |
| 328 | type == AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED || |
[email protected] | 457861f | 2014-06-13 04:26:14 | [diff] [blame] | 329 | type == AutocompleteMatchType::SEARCH_SUGGEST_PROFILE || |
| 330 | type == AutocompleteMatchType::SEARCH_SUGGEST_ANSWER; |
[email protected] | 749e7ae0 | 2012-09-05 18:47:46 | [diff] [blame] | 331 | } |
| 332 | |
[email protected] | c7b8be0 | 2014-07-11 19:46:34 | [diff] [blame] | 333 | // static |
| 334 | TemplateURL* AutocompleteMatch::GetTemplateURLWithKeyword( |
| 335 | TemplateURLService* template_url_service, |
| 336 | const base::string16& keyword, |
| 337 | const std::string& host) { |
| 338 | if (template_url_service == NULL) |
| 339 | return NULL; |
| 340 | TemplateURL* template_url = keyword.empty() ? |
| 341 | NULL : template_url_service->GetTemplateURLForKeyword(keyword); |
| 342 | return (template_url || host.empty()) ? |
| 343 | template_url : template_url_service->GetTemplateURLForHost(host); |
| 344 | } |
| 345 | |
| 346 | // static |
| 347 | GURL AutocompleteMatch::GURLToStrippedGURL( |
| 348 | const GURL& url, |
| 349 | TemplateURLService* template_url_service, |
| 350 | const base::string16& keyword) { |
| 351 | if (!url.is_valid()) |
| 352 | return url; |
| 353 | |
| 354 | GURL stripped_destination_url = url; |
[email protected] | 345e8fda | 2012-09-06 01:07:47 | [diff] [blame] | 355 | |
[email protected] | dbff44658 | 2012-10-30 00:20:26 | [diff] [blame] | 356 | // If the destination URL looks like it was generated from a TemplateURL, |
| 357 | // remove all substitutions other than the search terms. This allows us |
| 358 | // to eliminate cases like past search URLs from history that differ only |
| 359 | // by some obscure query param from each other or from the search/keyword |
| 360 | // provider matches. |
[email protected] | c7b8be0 | 2014-07-11 19:46:34 | [diff] [blame] | 361 | TemplateURL* template_url = GetTemplateURLWithKeyword( |
| 362 | template_url_service, keyword, stripped_destination_url.host()); |
[email protected] | ce7ee5f | 2014-06-16 23:41:19 | [diff] [blame] | 363 | if (template_url != NULL && |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 364 | template_url->SupportsReplacement( |
| 365 | template_url_service->search_terms_data())) { |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 366 | base::string16 search_terms; |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 367 | if (template_url->ExtractSearchTermsFromURL( |
| 368 | stripped_destination_url, |
| 369 | template_url_service->search_terms_data(), |
| 370 | &search_terms)) { |
[email protected] | dbff44658 | 2012-10-30 00:20:26 | [diff] [blame] | 371 | stripped_destination_url = |
| 372 | GURL(template_url->url_ref().ReplaceSearchTerms( |
[email protected] | ce7ee5f | 2014-06-16 23:41:19 | [diff] [blame] | 373 | TemplateURLRef::SearchTermsArgs(search_terms), |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 374 | template_url_service->search_terms_data())); |
[email protected] | dbff44658 | 2012-10-30 00:20:26 | [diff] [blame] | 375 | } |
| 376 | } |
| 377 | |
[email protected] | 345e8fda | 2012-09-06 01:07:47 | [diff] [blame] | 378 | // |replacements| keeps all the substitions we're going to make to |
| 379 | // from {destination_url} to {stripped_destination_url}. |need_replacement| |
| 380 | // is a helper variable that helps us keep track of whether we need |
| 381 | // to apply the replacement. |
| 382 | bool needs_replacement = false; |
| 383 | GURL::Replacements replacements; |
| 384 | |
| 385 | // Remove the www. prefix from the host. |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 386 | static const char prefix[] = "www."; |
| 387 | static const size_t prefix_len = arraysize(prefix) - 1; |
[email protected] | dbff44658 | 2012-10-30 00:20:26 | [diff] [blame] | 388 | std::string host = stripped_destination_url.host(); |
[email protected] | 345e8fda | 2012-09-06 01:07:47 | [diff] [blame] | 389 | if (host.compare(0, prefix_len, prefix) == 0) { |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 390 | host = host.substr(prefix_len); |
[email protected] | 345e8fda | 2012-09-06 01:07:47 | [diff] [blame] | 391 | replacements.SetHostStr(host); |
| 392 | needs_replacement = true; |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 393 | } |
[email protected] | 345e8fda | 2012-09-06 01:07:47 | [diff] [blame] | 394 | |
| 395 | // Replace https protocol with http protocol. |
[email protected] | e8ca69c | 2014-05-07 15:31:19 | [diff] [blame] | 396 | if (stripped_destination_url.SchemeIs(url::kHttpsScheme)) { |
| 397 | replacements.SetScheme(url::kHttpScheme, |
| 398 | url::Component(0, strlen(url::kHttpScheme))); |
[email protected] | 345e8fda | 2012-09-06 01:07:47 | [diff] [blame] | 399 | needs_replacement = true; |
| 400 | } |
| 401 | |
| 402 | if (needs_replacement) |
[email protected] | dbff44658 | 2012-10-30 00:20:26 | [diff] [blame] | 403 | stripped_destination_url = stripped_destination_url.ReplaceComponents( |
| 404 | replacements); |
[email protected] | c7b8be0 | 2014-07-11 19:46:34 | [diff] [blame] | 405 | return stripped_destination_url; |
| 406 | } |
| 407 | |
| 408 | void AutocompleteMatch::ComputeStrippedDestinationURL( |
| 409 | TemplateURLService* template_url_service) { |
| 410 | stripped_destination_url = |
| 411 | GURLToStrippedGURL(destination_url, template_url_service, keyword); |
| 412 | } |
| 413 | |
| 414 | void AutocompleteMatch::EnsureUWYTIsAllowedToBeDefault( |
| 415 | const GURL& canonical_input_url, |
| 416 | TemplateURLService* template_url_service) { |
| 417 | if (!allowed_to_be_default_match) { |
| 418 | const GURL& stripped_canonical_input_url = |
| 419 | AutocompleteMatch::GURLToStrippedGURL( |
| 420 | canonical_input_url, template_url_service, base::string16()); |
| 421 | ComputeStrippedDestinationURL(template_url_service); |
| 422 | allowed_to_be_default_match = |
| 423 | stripped_canonical_input_url == stripped_destination_url; |
| 424 | } |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 425 | } |
| 426 | |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 427 | void AutocompleteMatch::GetKeywordUIState( |
| 428 | TemplateURLService* template_url_service, |
| 429 | base::string16* keyword, |
| 430 | bool* is_keyword_hint) const { |
[email protected] | 033f342 | 2012-03-13 21:24:18 | [diff] [blame] | 431 | *is_keyword_hint = associated_keyword.get() != NULL; |
| 432 | keyword->assign(*is_keyword_hint ? associated_keyword->keyword : |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 433 | GetSubstitutingExplicitlyInvokedKeyword(template_url_service)); |
[email protected] | 033f342 | 2012-03-13 21:24:18 | [diff] [blame] | 434 | } |
| 435 | |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 436 | base::string16 AutocompleteMatch::GetSubstitutingExplicitlyInvokedKeyword( |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 437 | TemplateURLService* template_url_service) const { |
| 438 | if (transition != content::PAGE_TRANSITION_KEYWORD || |
| 439 | template_url_service == NULL) { |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 440 | return base::string16(); |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 441 | } |
| 442 | |
| 443 | const TemplateURL* t_url = GetTemplateURL(template_url_service, false); |
[email protected] | ce7ee5f | 2014-06-16 23:41:19 | [diff] [blame] | 444 | return (t_url && |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 445 | t_url->SupportsReplacement( |
| 446 | template_url_service->search_terms_data())) ? |
[email protected] | ce7ee5f | 2014-06-16 23:41:19 | [diff] [blame] | 447 | keyword : base::string16(); |
[email protected] | 033f342 | 2012-03-13 21:24:18 | [diff] [blame] | 448 | } |
| 449 | |
[email protected] | dbff44658 | 2012-10-30 00:20:26 | [diff] [blame] | 450 | TemplateURL* AutocompleteMatch::GetTemplateURL( |
[email protected] | cbb7dbd | 2014-07-02 22:52:57 | [diff] [blame] | 451 | TemplateURLService* template_url_service, |
| 452 | bool allow_fallback_to_destination_host) const { |
[email protected] | c7b8be0 | 2014-07-11 19:46:34 | [diff] [blame] | 453 | return GetTemplateURLWithKeyword( |
| 454 | template_url_service, keyword, |
| 455 | allow_fallback_to_destination_host ? |
| 456 | destination_url.host() : std::string()); |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 457 | } |
| 458 | |
[email protected] | 5281d42 | 2012-07-28 21:37:10 | [diff] [blame] | 459 | void AutocompleteMatch::RecordAdditionalInfo(const std::string& property, |
| 460 | const std::string& value) { |
[email protected] | bc8bb0cd | 2013-06-24 21:50:23 | [diff] [blame] | 461 | DCHECK(!property.empty()); |
| 462 | DCHECK(!value.empty()); |
[email protected] | 5281d42 | 2012-07-28 21:37:10 | [diff] [blame] | 463 | additional_info[property] = value; |
| 464 | } |
| 465 | |
| 466 | void AutocompleteMatch::RecordAdditionalInfo(const std::string& property, |
| 467 | int value) { |
[email protected] | bc8bb0cd | 2013-06-24 21:50:23 | [diff] [blame] | 468 | RecordAdditionalInfo(property, base::IntToString(value)); |
[email protected] | 5281d42 | 2012-07-28 21:37:10 | [diff] [blame] | 469 | } |
| 470 | |
| 471 | void AutocompleteMatch::RecordAdditionalInfo(const std::string& property, |
| 472 | const base::Time& value) { |
| 473 | RecordAdditionalInfo(property, |
[email protected] | 670d323 | 2013-12-24 17:58:58 | [diff] [blame] | 474 | base::UTF16ToUTF8( |
| 475 | base::TimeFormatShortDateAndTime(value))); |
[email protected] | 5281d42 | 2012-07-28 21:37:10 | [diff] [blame] | 476 | } |
| 477 | |
[email protected] | d30268a | 2013-06-25 22:31:07 | [diff] [blame] | 478 | std::string AutocompleteMatch::GetAdditionalInfo( |
| 479 | const std::string& property) const { |
| 480 | AdditionalInfo::const_iterator i(additional_info.find(property)); |
| 481 | return (i == additional_info.end()) ? std::string() : i->second; |
| 482 | } |
| 483 | |
[email protected] | 1fce7dd4 | 2013-08-06 02:29:17 | [diff] [blame] | 484 | bool AutocompleteMatch::IsVerbatimType() const { |
| 485 | const bool is_keyword_verbatim_match = |
| 486 | (type == AutocompleteMatchType::SEARCH_OTHER_ENGINE && |
| 487 | provider != NULL && |
| 488 | provider->type() == AutocompleteProvider::TYPE_SEARCH); |
| 489 | return type == AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED || |
| 490 | type == AutocompleteMatchType::URL_WHAT_YOU_TYPED || |
| 491 | is_keyword_verbatim_match; |
| 492 | } |
| 493 | |
[email protected] | 9caafa2 | 2014-02-28 01:26:13 | [diff] [blame] | 494 | bool AutocompleteMatch::SupportsDeletion() const { |
| 495 | if (deletable) |
| 496 | return true; |
| 497 | |
| 498 | for (ACMatches::const_iterator it(duplicate_matches.begin()); |
| 499 | it != duplicate_matches.end(); ++it) { |
| 500 | if (it->deletable) |
| 501 | return true; |
| 502 | } |
| 503 | return false; |
| 504 | } |
| 505 | |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 506 | #ifndef NDEBUG |
| 507 | void AutocompleteMatch::Validate() const { |
| 508 | ValidateClassifications(contents, contents_class); |
| 509 | ValidateClassifications(description, description_class); |
| 510 | } |
| 511 | |
| 512 | void AutocompleteMatch::ValidateClassifications( |
[email protected] | 9692015 | 2013-12-04 21:00:16 | [diff] [blame] | 513 | const base::string16& text, |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 514 | const ACMatchClassifications& classifications) const { |
| 515 | if (text.empty()) { |
[email protected] | 37b9573 | 2011-05-26 23:11:09 | [diff] [blame] | 516 | DCHECK(classifications.empty()); |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 517 | return; |
| 518 | } |
| 519 | |
| 520 | // The classifications should always cover the whole string. |
[email protected] | eac4499 | 2012-02-14 21:39:35 | [diff] [blame] | 521 | DCHECK(!classifications.empty()) << "No classification for \"" << text << '"'; |
| 522 | DCHECK_EQ(0U, classifications[0].offset) |
| 523 | << "Classification misses beginning for \"" << text << '"'; |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 524 | if (classifications.size() == 1) |
| 525 | return; |
| 526 | |
| 527 | // The classifications should always be sorted. |
| 528 | size_t last_offset = classifications[0].offset; |
| 529 | for (ACMatchClassifications::const_iterator i(classifications.begin() + 1); |
| 530 | i != classifications.end(); ++i) { |
[email protected] | 35f1f4f0 | 2012-09-11 13:17:00 | [diff] [blame] | 531 | const char* provider_name = provider ? provider->GetName() : "None"; |
[email protected] | eac4499 | 2012-02-14 21:39:35 | [diff] [blame] | 532 | DCHECK_GT(i->offset, last_offset) |
[email protected] | 6d478b1 | 2012-06-06 12:19:34 | [diff] [blame] | 533 | << " Classification for \"" << text << "\" with offset of " << i->offset |
| 534 | << " is unsorted in relation to last offset of " << last_offset |
[email protected] | 35f1f4f0 | 2012-09-11 13:17:00 | [diff] [blame] | 535 | << ". Provider: " << provider_name << "."; |
[email protected] | eac4499 | 2012-02-14 21:39:35 | [diff] [blame] | 536 | DCHECK_LT(i->offset, text.length()) |
[email protected] | 6d478b1 | 2012-06-06 12:19:34 | [diff] [blame] | 537 | << " Classification of [" << i->offset << "," << text.length() |
| 538 | << "] is out of bounds for \"" << text << "\". Provider: " |
[email protected] | 35f1f4f0 | 2012-09-11 13:17:00 | [diff] [blame] | 539 | << provider_name << "."; |
[email protected] | 9ac4009 | 2010-10-27 23:05:26 | [diff] [blame] | 540 | last_offset = i->offset; |
| 541 | } |
| 542 | } |
| 543 | #endif |