blob: f1c31f2346a299c9acaec287ff46ea4ac0e258c2 [file] [log] [blame]
[email protected]e7e07712014-07-30 08:53:231// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]9ac40092010-10-27 23:05:262// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]b1c5ab682014-08-07 11:53:175#include "components/omnibox/autocomplete_match.h"
[email protected]371dab12012-06-01 03:23:556
[email protected]5281d422012-07-28 21:37:107#include "base/i18n/time_formatting.h"
[email protected]9ac40092010-10-27 23:05:268#include "base/logging.h"
[email protected]98570e12013-06-10 19:54:229#include "base/strings/string16.h"
[email protected]3ea1b182013-02-08 22:38:4110#include "base/strings/string_number_conversions.h"
[email protected]98570e12013-06-10 19:54:2211#include "base/strings/string_util.h"
[email protected]135cb802013-06-09 16:44:2012#include "base/strings/utf_string_conversions.h"
[email protected]4dcb7972013-06-28 15:15:4113#include "base/time/time.h"
[email protected]b1c5ab682014-08-07 11:53:1714#include "components/omnibox/autocomplete_provider.h"
[email protected]d550cb02014-06-25 06:48:1115#include "components/search_engines/template_url.h"
[email protected]bf5c532d2014-07-05 00:29:5316#include "components/search_engines/template_url_service.h"
[email protected]4bafb262014-07-29 10:48:5317#include "grit/component_scaled_resources.h"
[email protected]9ac40092010-10-27 23:05:2618
[email protected]3b81314d2012-09-11 02:48:4119namespace {
20
21bool 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]9ac40092010-10-27 23:05:2629// AutocompleteMatch ----------------------------------------------------------
30
[email protected]531e0342011-11-10 15:08:4131// static
[email protected]b6775d782013-12-25 20:04:5332const base::char16 AutocompleteMatch::kInvalidChars[] = {
[email protected]531e0342011-11-10 15:08:4133 '\n', '\r', '\t',
34 0x2028, // Line separator
35 0x2029, // Paragraph separator
36 0
37};
38
[email protected]9ac40092010-10-27 23:05:2639AutocompleteMatch::AutocompleteMatch()
40 : provider(NULL),
41 relevance(0),
[email protected]cf6256f2012-06-12 23:36:0142 typed_count(-1),
[email protected]9ac40092010-10-27 23:05:2643 deletable(false),
[email protected]45f89a92013-08-12 13:41:3644 allowed_to_be_default_match(false),
[email protected]2905f742011-10-13 03:51:5845 transition(content::PAGE_TRANSITION_GENERATED),
[email protected]9ac40092010-10-27 23:05:2646 is_history_what_you_typed_match(false),
[email protected]b7f64d742013-05-21 04:04:0447 type(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED),
[email protected]7abfb3462011-01-31 16:43:0648 from_previous(false) {
[email protected]9ac40092010-10-27 23:05:2649}
50
51AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider,
52 int relevance,
53 bool deletable,
54 Type type)
55 : provider(provider),
56 relevance(relevance),
[email protected]cf6256f2012-06-12 23:36:0157 typed_count(-1),
[email protected]9ac40092010-10-27 23:05:2658 deletable(deletable),
[email protected]45f89a92013-08-12 13:41:3659 allowed_to_be_default_match(false),
[email protected]2905f742011-10-13 03:51:5860 transition(content::PAGE_TRANSITION_TYPED),
[email protected]9ac40092010-10-27 23:05:2661 is_history_what_you_typed_match(false),
62 type(type),
[email protected]7abfb3462011-01-31 16:43:0663 from_previous(false) {
[email protected]9ac40092010-10-27 23:05:2664}
65
[email protected]3cb0f8d92012-02-29 05:43:3466AutocompleteMatch::AutocompleteMatch(const AutocompleteMatch& match)
67 : provider(match.provider),
68 relevance(match.relevance),
[email protected]cf6256f2012-06-12 23:36:0169 typed_count(match.typed_count),
[email protected]3cb0f8d92012-02-29 05:43:3470 deletable(match.deletable),
71 fill_into_edit(match.fill_into_edit),
[email protected]518024c2013-07-19 23:40:2572 inline_autocompletion(match.inline_autocompletion),
[email protected]45f89a92013-08-12 13:41:3673 allowed_to_be_default_match(match.allowed_to_be_default_match),
[email protected]3cb0f8d92012-02-29 05:43:3474 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]6ae91fa392014-05-17 17:41:3180 answer_contents(match.answer_contents),
81 answer_type(match.answer_type),
[email protected]3cb0f8d92012-02-29 05:43:3482 transition(match.transition),
83 is_history_what_you_typed_match(match.is_history_what_you_typed_match),
84 type(match.type),
[email protected]bca359b2012-06-24 07:53:0485 associated_keyword(match.associated_keyword.get() ?
86 new AutocompleteMatch(*match.associated_keyword) : NULL),
[email protected]3cb0f8d92012-02-29 05:43:3487 keyword(match.keyword),
[email protected]bca359b2012-06-24 07:53:0488 from_previous(match.from_previous),
89 search_terms_args(match.search_terms_args.get() ?
90 new TemplateURLRef::SearchTermsArgs(*match.search_terms_args) :
[email protected]5281d422012-07-28 21:37:1091 NULL),
[email protected]9caafa22014-02-28 01:26:1392 additional_info(match.additional_info),
93 duplicate_matches(match.duplicate_matches) {
[email protected]3cb0f8d92012-02-29 05:43:3494}
95
[email protected]9ac40092010-10-27 23:05:2696AutocompleteMatch::~AutocompleteMatch() {
97}
98
[email protected]3cb0f8d92012-02-29 05:43:3499AutocompleteMatch& AutocompleteMatch::operator=(
100 const AutocompleteMatch& match) {
101 if (this == &match)
102 return *this;
103
104 provider = match.provider;
105 relevance = match.relevance;
[email protected]cf6256f2012-06-12 23:36:01106 typed_count = match.typed_count;
[email protected]3cb0f8d92012-02-29 05:43:34107 deletable = match.deletable;
108 fill_into_edit = match.fill_into_edit;
[email protected]518024c2013-07-19 23:40:25109 inline_autocompletion = match.inline_autocompletion;
[email protected]45f89a92013-08-12 13:41:36110 allowed_to_be_default_match = match.allowed_to_be_default_match;
[email protected]3cb0f8d92012-02-29 05:43:34111 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]6ae91fa392014-05-17 17:41:31117 answer_contents = match.answer_contents;
118 answer_type = match.answer_type;
[email protected]3cb0f8d92012-02-29 05:43:34119 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]3cb0f8d92012-02-29 05:43:34125 from_previous = match.from_previous;
[email protected]bca359b2012-06-24 07:53:04126 search_terms_args.reset(match.search_terms_args.get() ?
127 new TemplateURLRef::SearchTermsArgs(*match.search_terms_args) : NULL);
[email protected]5281d422012-07-28 21:37:10128 additional_info = match.additional_info;
[email protected]9caafa22014-02-28 01:26:13129 duplicate_matches = match.duplicate_matches;
[email protected]3cb0f8d92012-02-29 05:43:34130 return *this;
131}
132
[email protected]9ac40092010-10-27 23:05:26133// static
[email protected]9ac40092010-10-27 23:05:26134int AutocompleteMatch::TypeToIcon(Type type) {
[email protected]fc65f272011-06-28 22:21:30135 int icons[] = {
[email protected]9ac40092010-10-27 23:05:26136 IDR_OMNIBOX_HTTP,
137 IDR_OMNIBOX_HTTP,
[email protected]c37ad9e2012-06-12 04:57:13138 IDR_OMNIBOX_HTTP,
139 IDR_OMNIBOX_HTTP,
140 IDR_OMNIBOX_HTTP,
[email protected]9ac40092010-10-27 23:05:26141 IDR_OMNIBOX_HTTP,
142 IDR_OMNIBOX_SEARCH,
143 IDR_OMNIBOX_SEARCH,
144 IDR_OMNIBOX_SEARCH,
145 IDR_OMNIBOX_SEARCH,
[email protected]2c03c06b2013-12-11 20:45:02146 IDR_OMNIBOX_SEARCH,
147 IDR_OMNIBOX_SEARCH,
148 IDR_OMNIBOX_SEARCH,
149 IDR_OMNIBOX_SEARCH,
[email protected]8f7405482011-04-13 11:08:52150 IDR_OMNIBOX_EXTENSION_APP,
[email protected]dbacefb2012-09-12 03:32:06151 IDR_OMNIBOX_SEARCH,
[email protected]25320602012-10-18 22:05:56152 IDR_OMNIBOX_HTTP,
[email protected]78981d8c2014-05-09 15:05:47153 IDR_OMNIBOX_HTTP,
[email protected]457861f2014-06-13 04:26:14154 IDR_OMNIBOX_SEARCH,
[email protected]9ac40092010-10-27 23:05:26155 };
[email protected]b7f64d742013-05-21 04:04:04156 COMPILE_ASSERT(arraysize(icons) == AutocompleteMatchType::NUM_TYPES,
[email protected]fc65f272011-06-28 22:21:30157 icons_array_must_match_type_enum);
[email protected]9ac40092010-10-27 23:05:26158 return icons[type];
159}
160
161// static
162bool 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]033f3422012-03-13 21:24:18167 return (elem1.relevance == elem2.relevance) ?
168 (elem1.contents < elem2.contents) : (elem1.relevance > elem2.relevance);
[email protected]9ac40092010-10-27 23:05:26169}
170
171// static
[email protected]9ac40092010-10-27 23:05:26172bool AutocompleteMatch::DestinationsEqual(const AutocompleteMatch& elem1,
173 const AutocompleteMatch& elem2) {
[email protected]00193bf2012-09-15 14:52:50174 if (elem1.stripped_destination_url.is_empty() &&
175 elem2.stripped_destination_url.is_empty())
176 return false;
[email protected]3cb0f8d92012-02-29 05:43:34177 return elem1.stripped_destination_url == elem2.stripped_destination_url;
[email protected]9ac40092010-10-27 23:05:26178}
179
180// static
181void AutocompleteMatch::ClassifyMatchInString(
[email protected]96920152013-12-04 21:00:16182 const base::string16& find_text,
183 const base::string16& text,
[email protected]9ac40092010-10-27 23:05:26184 int style,
185 ACMatchClassifications* classification) {
186 ClassifyLocationInString(text.find(find_text), find_text.length(),
187 text.length(), style, classification);
188}
189
[email protected]24d692aa2011-05-25 23:07:58190// static
[email protected]9ac40092010-10-27 23:05:26191void 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]96920152013-12-04 21:00:16210 if (match_location == base::string16::npos) {
[email protected]9ac40092010-10-27 23:05:26211 // 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]eac44992012-02-14 21:39:35216 DCHECK_GT(match_length, 0U);
[email protected]9ac40092010-10-27 23:05:26217 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]5595f40d2011-10-28 17:29:18227// static
[email protected]3b81314d2012-09-11 02:48:41228AutocompleteMatch::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]9d2b5f3b2012-03-14 21:34:32259std::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
272ACMatchClassifications 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
293void 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]96920152013-12-04 21:00:16306base::string16 AutocompleteMatch::SanitizeString(const base::string16& text) {
[email protected]5595f40d2011-10-28 17:29:18307 // NOTE: This logic is mirrored by |sanitizeString()| in
[email protected]e87032e2013-03-11 00:17:14308 // omnibox_custom_bindings.js.
[email protected]96920152013-12-04 21:00:16309 base::string16 result;
[email protected]8af69c6c2014-03-03 19:05:31310 base::TrimWhitespace(text, base::TRIM_LEADING, &result);
[email protected]466c9862013-12-03 22:05:28311 base::RemoveChars(result, kInvalidChars, &result);
[email protected]5595f40d2011-10-28 17:29:18312 return result;
313}
314
[email protected]749e7ae02012-09-05 18:47:46315// static
316bool AutocompleteMatch::IsSearchType(Type type) {
[email protected]b7f64d742013-05-21 04:04:04317 return type == AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED ||
318 type == AutocompleteMatchType::SEARCH_HISTORY ||
319 type == AutocompleteMatchType::SEARCH_SUGGEST ||
[email protected]ef613d382014-03-25 23:25:58320 type == AutocompleteMatchType::SEARCH_OTHER_ENGINE ||
321 IsSpecializedSearchType(type);
322}
323
324// static
325bool AutocompleteMatch::IsSpecializedSearchType(Type type) {
326 return type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY ||
[email protected]e264dbea2014-03-11 10:08:48327 type == AutocompleteMatchType::SEARCH_SUGGEST_INFINITE ||
328 type == AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED ||
[email protected]457861f2014-06-13 04:26:14329 type == AutocompleteMatchType::SEARCH_SUGGEST_PROFILE ||
330 type == AutocompleteMatchType::SEARCH_SUGGEST_ANSWER;
[email protected]749e7ae02012-09-05 18:47:46331}
332
[email protected]c7b8be02014-07-11 19:46:34333// static
334TemplateURL* 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
347GURL 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]345e8fda2012-09-06 01:07:47355
[email protected]dbff446582012-10-30 00:20:26356 // 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]c7b8be02014-07-11 19:46:34361 TemplateURL* template_url = GetTemplateURLWithKeyword(
362 template_url_service, keyword, stripped_destination_url.host());
[email protected]ce7ee5f2014-06-16 23:41:19363 if (template_url != NULL &&
[email protected]cbb7dbd2014-07-02 22:52:57364 template_url->SupportsReplacement(
365 template_url_service->search_terms_data())) {
[email protected]96920152013-12-04 21:00:16366 base::string16 search_terms;
[email protected]cbb7dbd2014-07-02 22:52:57367 if (template_url->ExtractSearchTermsFromURL(
368 stripped_destination_url,
369 template_url_service->search_terms_data(),
370 &search_terms)) {
[email protected]dbff446582012-10-30 00:20:26371 stripped_destination_url =
372 GURL(template_url->url_ref().ReplaceSearchTerms(
[email protected]ce7ee5f2014-06-16 23:41:19373 TemplateURLRef::SearchTermsArgs(search_terms),
[email protected]cbb7dbd2014-07-02 22:52:57374 template_url_service->search_terms_data()));
[email protected]dbff446582012-10-30 00:20:26375 }
376 }
377
[email protected]345e8fda2012-09-06 01:07:47378 // |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]3cb0f8d92012-02-29 05:43:34386 static const char prefix[] = "www.";
387 static const size_t prefix_len = arraysize(prefix) - 1;
[email protected]dbff446582012-10-30 00:20:26388 std::string host = stripped_destination_url.host();
[email protected]345e8fda2012-09-06 01:07:47389 if (host.compare(0, prefix_len, prefix) == 0) {
[email protected]3cb0f8d92012-02-29 05:43:34390 host = host.substr(prefix_len);
[email protected]345e8fda2012-09-06 01:07:47391 replacements.SetHostStr(host);
392 needs_replacement = true;
[email protected]3cb0f8d92012-02-29 05:43:34393 }
[email protected]345e8fda2012-09-06 01:07:47394
395 // Replace https protocol with http protocol.
[email protected]e8ca69c2014-05-07 15:31:19396 if (stripped_destination_url.SchemeIs(url::kHttpsScheme)) {
397 replacements.SetScheme(url::kHttpScheme,
398 url::Component(0, strlen(url::kHttpScheme)));
[email protected]345e8fda2012-09-06 01:07:47399 needs_replacement = true;
400 }
401
402 if (needs_replacement)
[email protected]dbff446582012-10-30 00:20:26403 stripped_destination_url = stripped_destination_url.ReplaceComponents(
404 replacements);
[email protected]c7b8be02014-07-11 19:46:34405 return stripped_destination_url;
406}
407
408void AutocompleteMatch::ComputeStrippedDestinationURL(
409 TemplateURLService* template_url_service) {
410 stripped_destination_url =
411 GURLToStrippedGURL(destination_url, template_url_service, keyword);
412}
413
414void 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]3cb0f8d92012-02-29 05:43:34425}
426
[email protected]cbb7dbd2014-07-02 22:52:57427void AutocompleteMatch::GetKeywordUIState(
428 TemplateURLService* template_url_service,
429 base::string16* keyword,
430 bool* is_keyword_hint) const {
[email protected]033f3422012-03-13 21:24:18431 *is_keyword_hint = associated_keyword.get() != NULL;
432 keyword->assign(*is_keyword_hint ? associated_keyword->keyword :
[email protected]cbb7dbd2014-07-02 22:52:57433 GetSubstitutingExplicitlyInvokedKeyword(template_url_service));
[email protected]033f3422012-03-13 21:24:18434}
435
[email protected]96920152013-12-04 21:00:16436base::string16 AutocompleteMatch::GetSubstitutingExplicitlyInvokedKeyword(
[email protected]cbb7dbd2014-07-02 22:52:57437 TemplateURLService* template_url_service) const {
438 if (transition != content::PAGE_TRANSITION_KEYWORD ||
439 template_url_service == NULL) {
[email protected]96920152013-12-04 21:00:16440 return base::string16();
[email protected]cbb7dbd2014-07-02 22:52:57441 }
442
443 const TemplateURL* t_url = GetTemplateURL(template_url_service, false);
[email protected]ce7ee5f2014-06-16 23:41:19444 return (t_url &&
[email protected]cbb7dbd2014-07-02 22:52:57445 t_url->SupportsReplacement(
446 template_url_service->search_terms_data())) ?
[email protected]ce7ee5f2014-06-16 23:41:19447 keyword : base::string16();
[email protected]033f3422012-03-13 21:24:18448}
449
[email protected]dbff446582012-10-30 00:20:26450TemplateURL* AutocompleteMatch::GetTemplateURL(
[email protected]cbb7dbd2014-07-02 22:52:57451 TemplateURLService* template_url_service,
452 bool allow_fallback_to_destination_host) const {
[email protected]c7b8be02014-07-11 19:46:34453 return GetTemplateURLWithKeyword(
454 template_url_service, keyword,
455 allow_fallback_to_destination_host ?
456 destination_url.host() : std::string());
[email protected]3cb0f8d92012-02-29 05:43:34457}
458
[email protected]5281d422012-07-28 21:37:10459void AutocompleteMatch::RecordAdditionalInfo(const std::string& property,
460 const std::string& value) {
[email protected]bc8bb0cd2013-06-24 21:50:23461 DCHECK(!property.empty());
462 DCHECK(!value.empty());
[email protected]5281d422012-07-28 21:37:10463 additional_info[property] = value;
464}
465
466void AutocompleteMatch::RecordAdditionalInfo(const std::string& property,
467 int value) {
[email protected]bc8bb0cd2013-06-24 21:50:23468 RecordAdditionalInfo(property, base::IntToString(value));
[email protected]5281d422012-07-28 21:37:10469}
470
471void AutocompleteMatch::RecordAdditionalInfo(const std::string& property,
472 const base::Time& value) {
473 RecordAdditionalInfo(property,
[email protected]670d3232013-12-24 17:58:58474 base::UTF16ToUTF8(
475 base::TimeFormatShortDateAndTime(value)));
[email protected]5281d422012-07-28 21:37:10476}
477
[email protected]d30268a2013-06-25 22:31:07478std::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]1fce7dd42013-08-06 02:29:17484bool 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]9caafa22014-02-28 01:26:13494bool 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]9ac40092010-10-27 23:05:26506#ifndef NDEBUG
507void AutocompleteMatch::Validate() const {
508 ValidateClassifications(contents, contents_class);
509 ValidateClassifications(description, description_class);
510}
511
512void AutocompleteMatch::ValidateClassifications(
[email protected]96920152013-12-04 21:00:16513 const base::string16& text,
[email protected]9ac40092010-10-27 23:05:26514 const ACMatchClassifications& classifications) const {
515 if (text.empty()) {
[email protected]37b95732011-05-26 23:11:09516 DCHECK(classifications.empty());
[email protected]9ac40092010-10-27 23:05:26517 return;
518 }
519
520 // The classifications should always cover the whole string.
[email protected]eac44992012-02-14 21:39:35521 DCHECK(!classifications.empty()) << "No classification for \"" << text << '"';
522 DCHECK_EQ(0U, classifications[0].offset)
523 << "Classification misses beginning for \"" << text << '"';
[email protected]9ac40092010-10-27 23:05:26524 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]35f1f4f02012-09-11 13:17:00531 const char* provider_name = provider ? provider->GetName() : "None";
[email protected]eac44992012-02-14 21:39:35532 DCHECK_GT(i->offset, last_offset)
[email protected]6d478b12012-06-06 12:19:34533 << " Classification for \"" << text << "\" with offset of " << i->offset
534 << " is unsorted in relation to last offset of " << last_offset
[email protected]35f1f4f02012-09-11 13:17:00535 << ". Provider: " << provider_name << ".";
[email protected]eac44992012-02-14 21:39:35536 DCHECK_LT(i->offset, text.length())
[email protected]6d478b12012-06-06 12:19:34537 << " Classification of [" << i->offset << "," << text.length()
538 << "] is out of bounds for \"" << text << "\". Provider: "
[email protected]35f1f4f02012-09-11 13:17:00539 << provider_name << ".";
[email protected]9ac40092010-10-27 23:05:26540 last_offset = i->offset;
541 }
542}
543#endif