OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/autocomplete/search_provider.h" | 5 #include "chrome/browser/autocomplete/search_provider.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
100 } | 100 } |
101 } | 101 } |
102 return false; | 102 return false; |
103 } | 103 } |
104 | 104 |
105 // Builds the match contents and classification for the contents, and updates | 105 // Builds the match contents and classification for the contents, and updates |
106 // the given |AutocompleteMatch|. | 106 // the given |AutocompleteMatch|. |
107 void SetAndClassifyMatchContents(const base::string16& query_string, | 107 void SetAndClassifyMatchContents(const base::string16& query_string, |
108 const base::string16& input_text, | 108 const base::string16& input_text, |
109 const base::string16& match_contents, | 109 const base::string16& match_contents, |
110 const base::string16& annotation, | |
111 AutocompleteMatch* match) { | 110 AutocompleteMatch* match) { |
112 size_t match_contents_start = 0; | 111 match->contents = match_contents.empty() ? query_string : match_contents; |
113 size_t annotation_start = match_contents.size(); | |
114 // Append annotation if present. | |
115 if (annotation.empty()) { | |
116 match->contents = match_contents; | |
117 } else { | |
118 std::vector<size_t> positions; | |
119 match->contents = l10n_util::GetStringFUTF16( | |
120 IDS_ANNOTATED_SUGGESTION, match_contents, annotation, &positions); | |
Peter Kasting
2013/12/10 03:52:30
If we're removing the only reference to IDS_ANNOTA
Anuj
2013/12/10 23:08:09
Done.
| |
121 match_contents_start = positions[0]; | |
122 annotation_start = positions[1]; | |
123 } | |
124 size_t match_contents_end = match_contents_start + match_contents.size(); | |
125 | |
126 if (!annotation.empty() && (annotation_start < match_contents_start)) | |
127 match->contents_class.push_back(ACMatchClassification( | |
128 annotation_start, ACMatchClassification::DIM)); | |
129 | 112 |
130 // We do intra-string highlighting for suggestions - the suggested segment | 113 // We do intra-string highlighting for suggestions - the suggested segment |
131 // will be highlighted, e.g. for input_text = "you" the suggestion may be | 114 // will be highlighted, e.g. for input_text = "you" the suggestion may be |
132 // "youtube", so we'll bold the "tube" section: you*tube*. | 115 // "youtube", so we'll bold the "tube" section: you*tube*. |
133 if (input_text != match_contents) { | 116 if (input_text != match_contents) { |
134 size_t input_position = match->contents.substr( | 117 size_t input_position = match->contents.find(input_text); |
135 match_contents_start, match_contents.length()).find(input_text); | |
136 if (input_position == base::string16::npos) { | 118 if (input_position == base::string16::npos) { |
137 // The input text is not a substring of the query string, e.g. input | 119 // The input text is not a substring of the query string, e.g. input |
138 // text is "slasdot" and the query string is "slashdot", so we bold the | 120 // text is "slasdot" and the query string is "slashdot", so we bold the |
139 // whole thing. | 121 // whole thing. |
140 match->contents_class.push_back(ACMatchClassification( | 122 match->contents_class.push_back(ACMatchClassification( |
141 match_contents_start, ACMatchClassification::MATCH)); | 123 0, ACMatchClassification::MATCH)); |
142 } else { | 124 } else { |
143 input_position += match_contents_start; | |
144 | |
145 // TODO(beng): ACMatchClassification::MATCH now seems to just mean | 125 // TODO(beng): ACMatchClassification::MATCH now seems to just mean |
146 // "bold" this. Consider modifying the terminology. | 126 // "bold" this. Consider modifying the terminology. |
147 // We don't iterate over the string here annotating all matches because | 127 // We don't iterate over the string here annotating all matches because |
148 // it looks odd to have every occurrence of a substring that may be as | 128 // it looks odd to have every occurrence of a substring that may be as |
149 // short as a single character highlighted in a query suggestion result, | 129 // short as a single character highlighted in a query suggestion result, |
150 // e.g. for input text "s" and query string "southwest airlines", it | 130 // e.g. for input text "s" and query string "southwest airlines", it |
151 // looks odd if both the first and last s are highlighted. | 131 // looks odd if both the first and last s are highlighted. |
152 if (input_position != match_contents_start) { | 132 if (input_position != 0) { |
153 match->contents_class.push_back(ACMatchClassification( | 133 match->contents_class.push_back(ACMatchClassification( |
154 match_contents_start, ACMatchClassification::MATCH)); | 134 0, ACMatchClassification::MATCH)); |
155 } | 135 } |
156 match->contents_class.push_back( | 136 match->contents_class.push_back( |
157 ACMatchClassification(input_position, ACMatchClassification::NONE)); | 137 ACMatchClassification(input_position, ACMatchClassification::NONE)); |
158 size_t next_fragment_position = input_position + input_text.length(); | 138 size_t next_fragment_position = input_position + input_text.length(); |
159 if (next_fragment_position < query_string.length()) { | 139 if (next_fragment_position < query_string.length()) { |
160 match->contents_class.push_back(ACMatchClassification( | 140 match->contents_class.push_back(ACMatchClassification( |
161 next_fragment_position, ACMatchClassification::MATCH)); | 141 next_fragment_position, ACMatchClassification::MATCH)); |
162 } | 142 } |
163 } | 143 } |
164 } else { | 144 } else { |
165 // Otherwise, |match| is a verbatim (what-you-typed) match, either for the | 145 // Otherwise, |match| is a verbatim (what-you-typed) match, either for the |
166 // default provider or a keyword search provider. | 146 // default provider or a keyword search provider. |
167 match->contents_class.push_back(ACMatchClassification( | 147 match->contents_class.push_back(ACMatchClassification( |
168 match_contents_start, ACMatchClassification::NONE)); | 148 0, ACMatchClassification::NONE)); |
169 } | 149 } |
150 } | |
170 | 151 |
171 if (!annotation.empty() && (annotation_start >= match_contents_start)) | 152 AutocompleteMatchType::Type GetAutocompleteMatchType(const std::string& type) { |
172 match->contents_class.push_back(ACMatchClassification( | 153 if (type == "ENTITY") |
173 match_contents_end, ACMatchClassification::DIM)); | 154 return AutocompleteMatchType::SEARCH_SUGGEST_ENTITY; |
155 if (type == "INFINITE") | |
156 return AutocompleteMatchType::SEARCH_SUGGEST_INFINITE; | |
157 if (type == "PERSONALIZED") | |
158 return AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED; | |
159 if (type == "PROFILE") | |
160 return AutocompleteMatchType::SEARCH_SUGGEST_PROFILE; | |
161 return AutocompleteMatchType::SEARCH_SUGGEST; | |
174 } | 162 } |
175 | 163 |
176 } // namespace | 164 } // namespace |
177 | 165 |
178 | 166 |
179 // SuggestionDeletionHandler ------------------------------------------------- | 167 // SuggestionDeletionHandler ------------------------------------------------- |
180 | 168 |
181 // This class handles making requests to the server in order to delete | 169 // This class handles making requests to the server in order to delete |
182 // personalized suggestions. | 170 // personalized suggestions. |
183 class SuggestionDeletionHandler : public net::URLFetcherDelegate { | 171 class SuggestionDeletionHandler : public net::URLFetcherDelegate { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
259 } | 247 } |
260 | 248 |
261 SearchProvider::Result::~Result() { | 249 SearchProvider::Result::~Result() { |
262 } | 250 } |
263 | 251 |
264 | 252 |
265 // SearchProvider::SuggestResult ---------------------------------------------- | 253 // SearchProvider::SuggestResult ---------------------------------------------- |
266 | 254 |
267 SearchProvider::SuggestResult::SuggestResult( | 255 SearchProvider::SuggestResult::SuggestResult( |
268 const base::string16& suggestion, | 256 const base::string16& suggestion, |
257 AutocompleteMatchType::Type type, | |
269 const base::string16& match_contents, | 258 const base::string16& match_contents, |
270 const base::string16& annotation, | 259 const base::string16& annotation, |
271 const std::string& suggest_query_params, | 260 const std::string& suggest_query_params, |
272 const std::string& deletion_url, | 261 const std::string& deletion_url, |
273 bool from_keyword_provider, | 262 bool from_keyword_provider, |
274 int relevance, | 263 int relevance, |
275 bool relevance_from_server, | 264 bool relevance_from_server, |
276 bool should_prefetch) | 265 bool should_prefetch) |
277 : Result(from_keyword_provider, relevance, relevance_from_server), | 266 : Result(from_keyword_provider, relevance, relevance_from_server), |
278 suggestion_(suggestion), | 267 suggestion_(suggestion), |
268 type_(type), | |
279 match_contents_(match_contents), | 269 match_contents_(match_contents), |
280 annotation_(annotation), | 270 annotation_(annotation), |
281 suggest_query_params_(suggest_query_params), | 271 suggest_query_params_(suggest_query_params), |
282 deletion_url_(deletion_url), | 272 deletion_url_(deletion_url), |
283 should_prefetch_(should_prefetch) { | 273 should_prefetch_(should_prefetch) { |
284 } | 274 } |
285 | 275 |
286 SearchProvider::SuggestResult::~SuggestResult() { | 276 SearchProvider::SuggestResult::~SuggestResult() { |
287 } | 277 } |
288 | 278 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
419 const std::string& suggest_query_params, | 409 const std::string& suggest_query_params, |
420 int accepted_suggestion, | 410 int accepted_suggestion, |
421 int omnibox_start_margin, | 411 int omnibox_start_margin, |
422 bool append_extra_query_params) { | 412 bool append_extra_query_params) { |
423 AutocompleteMatch match(autocomplete_provider, relevance, false, type); | 413 AutocompleteMatch match(autocomplete_provider, relevance, false, type); |
424 | 414 |
425 if (!template_url) | 415 if (!template_url) |
426 return match; | 416 return match; |
427 match.keyword = template_url->keyword(); | 417 match.keyword = template_url->keyword(); |
428 | 418 |
429 SetAndClassifyMatchContents( | 419 SetAndClassifyMatchContents(query_string, input_text, match_contents, &match); |
430 query_string, input_text, match_contents, annotation, &match); | 420 |
421 if (!annotation.empty()) | |
422 match.description = annotation; | |
431 | 423 |
432 match.allowed_to_be_default_match = (input_text == match_contents); | 424 match.allowed_to_be_default_match = (input_text == match_contents); |
433 | 425 |
434 // When the user forced a query, we need to make sure all the fill_into_edit | 426 // When the user forced a query, we need to make sure all the fill_into_edit |
435 // values preserve that property. Otherwise, if the user starts editing a | 427 // values preserve that property. Otherwise, if the user starts editing a |
436 // suggestion, non-Search results will suddenly appear. | 428 // suggestion, non-Search results will suddenly appear. |
437 if (input.type() == AutocompleteInput::FORCED_QUERY) | 429 if (input.type() == AutocompleteInput::FORCED_QUERY) |
438 match.fill_into_edit.assign(ASCIIToUTF16("?")); | 430 match.fill_into_edit.assign(ASCIIToUTF16("?")); |
439 if (is_keyword) | 431 if (is_keyword) |
440 match.fill_into_edit.append(match.keyword + char16(' ')); | 432 match.fill_into_edit.append(match.keyword + char16(' ')); |
(...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1172 // Do not blindly trust the URL coming from the server to be valid. | 1164 // Do not blindly trust the URL coming from the server to be valid. |
1173 GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion), std::string())); | 1165 GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion), std::string())); |
1174 if (url.is_valid() && allow_navsuggest) { | 1166 if (url.is_valid() && allow_navsuggest) { |
1175 base::string16 title; | 1167 base::string16 title; |
1176 if (descriptions != NULL) | 1168 if (descriptions != NULL) |
1177 descriptions->GetString(index, &title); | 1169 descriptions->GetString(index, &title); |
1178 results->navigation_results.push_back(NavigationResult( | 1170 results->navigation_results.push_back(NavigationResult( |
1179 *this, url, title, is_keyword, relevance, true)); | 1171 *this, url, title, is_keyword, relevance, true)); |
1180 } | 1172 } |
1181 } else { | 1173 } else { |
1174 AutocompleteMatchType::Type match_type = GetAutocompleteMatchType(type); | |
1182 bool should_prefetch = static_cast<int>(index) == prefetch_index; | 1175 bool should_prefetch = static_cast<int>(index) == prefetch_index; |
1183 DictionaryValue* suggestion_detail = NULL; | 1176 DictionaryValue* suggestion_detail = NULL; |
1184 base::string16 match_contents = suggestion; | 1177 base::string16 match_contents = suggestion; |
1185 base::string16 annotation; | 1178 base::string16 annotation; |
1186 std::string suggest_query_params; | 1179 std::string suggest_query_params; |
1187 std::string deletion_url; | 1180 std::string deletion_url; |
1188 | 1181 |
1189 if (suggestion_details) { | 1182 if (suggestion_details) { |
1190 suggestion_details->GetDictionary(index, &suggestion_detail); | 1183 suggestion_details->GetDictionary(index, &suggestion_detail); |
1191 if (suggestion_detail) { | 1184 if (suggestion_detail) { |
1192 suggestion_detail->GetString("du", &deletion_url); | 1185 suggestion_detail->GetString("du", &deletion_url); |
1193 | 1186 suggestion_detail->GetString("title", &match_contents) || |
1194 if (type == "ENTITY") { | 1187 suggestion_detail->GetString("t", &match_contents); |
1195 suggestion_detail->GetString("a", &annotation); | 1188 suggestion_detail->GetString("annotation", &annotation) || |
1196 | 1189 suggestion_detail->GetString("a", &annotation); |
1197 base::string16 disambiguating_query; | 1190 suggestion_detail->GetString("query_params", &suggest_query_params) || |
1198 if (suggestion_detail->GetString("dq", &disambiguating_query) && | 1191 suggestion_detail->GetString("q", &suggest_query_params); |
1199 !disambiguating_query.empty()) | |
1200 suggestion = disambiguating_query; | |
1201 | |
1202 suggestion_detail->GetString("q", &suggest_query_params); | |
1203 } | |
1204 } | 1192 } |
1205 } | 1193 } |
1206 | 1194 |
1207 // TODO(kochi): Improve calculator suggestion presentation. | 1195 // TODO(kochi): Improve calculator suggestion presentation. |
1208 results->suggest_results.push_back(SuggestResult( | 1196 results->suggest_results.push_back(SuggestResult( |
1209 suggestion, match_contents, annotation, suggest_query_params, | 1197 suggestion, match_type, match_contents, annotation, |
1210 deletion_url, is_keyword, relevance, true, should_prefetch)); | 1198 suggest_query_params, deletion_url, is_keyword, relevance, true, |
1199 should_prefetch)); | |
1211 } | 1200 } |
1212 } | 1201 } |
1213 | 1202 |
1214 // Ignore suggested scores for non-keyword matches in keyword mode; if the | 1203 // Ignore suggested scores for non-keyword matches in keyword mode; if the |
1215 // server is allowed to score these, it could interfere with the user's | 1204 // server is allowed to score these, it could interfere with the user's |
1216 // ability to get good keyword results. | 1205 // ability to get good keyword results. |
1217 const bool abandon_suggested_scores = | 1206 const bool abandon_suggested_scores = |
1218 !is_keyword && !providers_.keyword_provider().empty(); | 1207 !is_keyword && !providers_.keyword_provider().empty(); |
1219 // Apply calculated relevance scores to suggestions if a valid list was | 1208 // Apply calculated relevance scores to suggestions if a valid list was |
1220 // not provided or we're abandoning suggested scores entirely. | 1209 // not provided or we're abandoning suggested scores entirely. |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1647 if (!prevent_inline_autocomplete && classifier && (i->term != input_text)) { | 1636 if (!prevent_inline_autocomplete && classifier && (i->term != input_text)) { |
1648 AutocompleteMatch match; | 1637 AutocompleteMatch match; |
1649 classifier->Classify(i->term, false, false, &match, NULL); | 1638 classifier->Classify(i->term, false, false, &match, NULL); |
1650 prevent_inline_autocomplete = | 1639 prevent_inline_autocomplete = |
1651 !AutocompleteMatch::IsSearchType(match.type); | 1640 !AutocompleteMatch::IsSearchType(match.type); |
1652 } | 1641 } |
1653 | 1642 |
1654 int relevance = CalculateRelevanceForHistory( | 1643 int relevance = CalculateRelevanceForHistory( |
1655 i->time, is_keyword, !prevent_inline_autocomplete, | 1644 i->time, is_keyword, !prevent_inline_autocomplete, |
1656 prevent_search_history_inlining); | 1645 prevent_search_history_inlining); |
1657 scored_results.push_back( | 1646 scored_results.push_back(SuggestResult( |
1658 SuggestResult(i->term, base::string16(), base::string16(), | 1647 i->term, AutocompleteMatchType::SEARCH_HISTORY, base::string16(), |
1659 std::string(), std::string(), is_keyword, relevance, | 1648 base::string16(), std::string(), std::string(), is_keyword, relevance, |
1660 false, false)); | 1649 false, false)); |
1661 } | 1650 } |
1662 | 1651 |
1663 // History returns results sorted for us. However, we may have docked some | 1652 // History returns results sorted for us. However, we may have docked some |
1664 // results' scores, so things are no longer in order. Do a stable sort to get | 1653 // results' scores, so things are no longer in order. Do a stable sort to get |
1665 // things back in order without otherwise disturbing results with equal | 1654 // things back in order without otherwise disturbing results with equal |
1666 // scores, then force the scores to be unique, so that the order in which | 1655 // scores, then force the scores to be unique, so that the order in which |
1667 // they're shown is deterministic. | 1656 // they're shown is deterministic. |
1668 std::stable_sort(scored_results.begin(), scored_results.end(), | 1657 std::stable_sort(scored_results.begin(), scored_results.end(), |
1669 CompareScoredResults()); | 1658 CompareScoredResults()); |
1670 int last_relevance = 0; | 1659 int last_relevance = 0; |
(...skipping 12 matching lines...) Expand all Loading... | |
1683 MatchMap* map) { | 1672 MatchMap* map) { |
1684 for (size_t i = 0; i < results.size(); ++i) { | 1673 for (size_t i = 0; i < results.size(); ++i) { |
1685 const bool is_keyword = results[i].from_keyword_provider(); | 1674 const bool is_keyword = results[i].from_keyword_provider(); |
1686 const base::string16& input = is_keyword ? keyword_input_.text() | 1675 const base::string16& input = is_keyword ? keyword_input_.text() |
1687 : input_.text(); | 1676 : input_.text(); |
1688 AddMatchToMap(input, | 1677 AddMatchToMap(input, |
1689 results[i].relevance(), | 1678 results[i].relevance(), |
1690 results[i].relevance_from_server(), | 1679 results[i].relevance_from_server(), |
1691 results[i].should_prefetch(), | 1680 results[i].should_prefetch(), |
1692 metadata, | 1681 metadata, |
1693 AutocompleteMatchType::SEARCH_SUGGEST, | 1682 results[i].type(), |
1694 is_keyword, | 1683 is_keyword, |
1695 results[i].match_contents(), | 1684 results[i].match_contents(), |
1696 results[i].annotation(), | 1685 results[i].annotation(), |
1697 results[i].suggestion(), | 1686 results[i].suggestion(), |
1698 i, | 1687 i, |
1699 results[i].suggest_query_params(), | 1688 results[i].suggest_query_params(), |
1700 results[i].deletion_url(), | 1689 results[i].deletion_url(), |
1701 map); | 1690 map); |
1702 } | 1691 } |
1703 } | 1692 } |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2084 if (!OmniboxFieldTrial::InZeroSuggestFieldTrial() || | 2073 if (!OmniboxFieldTrial::InZeroSuggestFieldTrial() || |
2085 service == NULL || | 2074 service == NULL || |
2086 !service->IsSyncEnabledAndLoggedIn() || | 2075 !service->IsSyncEnabledAndLoggedIn() || |
2087 !sync_prefs.GetPreferredDataTypes(syncer::UserTypes()).Has( | 2076 !sync_prefs.GetPreferredDataTypes(syncer::UserTypes()).Has( |
2088 syncer::PROXY_TABS) || | 2077 syncer::PROXY_TABS) || |
2089 service->GetEncryptedDataTypes().Has(syncer::SESSIONS)) | 2078 service->GetEncryptedDataTypes().Has(syncer::SESSIONS)) |
2090 return false; | 2079 return false; |
2091 | 2080 |
2092 return true; | 2081 return true; |
2093 } | 2082 } |
OLD | NEW |