Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Unified Diff: chrome/browser/autocomplete/zerosuggest_provider.cc

Issue 10832256: Experimental AutocompleteProvider for zerosuggest. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Rip out timer. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/autocomplete/zerosuggest_provider.cc
diff --git a/chrome/browser/autocomplete/zerosuggest_provider.cc b/chrome/browser/autocomplete/zerosuggest_provider.cc
new file mode 100644
index 0000000000000000000000000000000000000000..47650c1f9305e989d57416d67ac3abd4d0091562
--- /dev/null
+++ b/chrome/browser/autocomplete/zerosuggest_provider.cc
@@ -0,0 +1,221 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autocomplete/zerosuggest_provider.h"
+
+#include "base/callback.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autocomplete/autocomplete_input.h"
+#include "chrome/browser/autocomplete/autocomplete_match.h"
+#include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
+
+ZerosuggestProvider::ZerosuggestProvider(
+ AutocompleteProviderListener* listener,
+ Profile* profile,
+ const std::string& url_prefix)
+ : AutocompleteProvider(listener, profile, "Zerosuggest"),
+ url_prefix_(url_prefix),
+ template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
+}
+
+void ZerosuggestProvider::Start(const AutocompleteInput& input,
+ bool /*minimal_changes*/) {
+ UpdateMatches(input.text());
+}
+
+void ZerosuggestProvider::StartZerosuggest(
+ const GURL& url,
+ const string16& user_text) {
+ const std::string& spec = url.possibly_invalid_spec();
+ if (spec.empty() || url.scheme() != chrome::kHttpScheme)
samarth 2012/08/13 17:42:37 You should also consider checking the scheme for u
Jered 2012/08/13 22:23:59 I'm not sure we need that for testing. Seems like
+ // Do not query empty URLs nor non-http URLs. There will be no useful
+ // suggestions for https or chrome URLs.
+ return;
+ matches_.clear();
+ done_ = false;
+ user_text_ = user_text;
+ current_query_ = spec;
+ current_query_text_ = ASCIIToUTF16(spec);
+ Run();
+}
+
+void ZerosuggestProvider::Stop(bool clear_cached_results) {
+ fetcher_.reset();
+ done_ = true;
+ if (clear_cached_results) {
+ results_.clear();
+ current_query_.clear();
+ current_query_text_.clear();
+ }
+}
+
+void ZerosuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) {
+ const net::HttpResponseHeaders* const response_headers =
+ source->GetResponseHeaders();
+ std::string json_data;
+ source->GetResponseAsString(&json_data);
+ if (response_headers) {
+ std::string charset;
+ if (response_headers->GetCharset(&charset)) {
+ string16 data_16;
+ if (base::CodepageToUTF16(json_data, charset.c_str(),
+ base::OnStringConversionError::FAIL,
+ &data_16))
+ json_data = UTF16ToUTF8(data_16);
+ }
+ }
+ const bool request_succeeded =
samarth 2012/08/13 17:42:37 If json_data is empty at this point, do we still c
Jered 2012/08/13 22:23:59 Yep, but results_updated will be true only if the
+ source->GetStatus().is_success() && source->GetResponseCode() == 200;
+
+ bool results_updated = false;
+ if (request_succeeded) {
+ JSONStringValueSerializer deserializer(json_data);
+ deserializer.set_allow_trailing_comma(true);
+ scoped_ptr<Value> data(deserializer.Deserialize(NULL, NULL));
+ results_updated = data.get() && ParseSuggestResults(data.get());
+ }
+ done_ = true;
+
+ ConvertResultsToAutocompleteMatches();
+ if (results_updated)
+ listener_->OnProviderUpdate(results_updated);
+}
+
+ZerosuggestProvider::~ZerosuggestProvider() {
+}
+
+void ZerosuggestProvider::Run() {
+ const int kFetcherID = 1;
+ fetcher_.reset(
+ net::URLFetcher::Create(kFetcherID,
+ GURL(url_prefix_ + current_query_),
+ net::URLFetcher::GET, this));
+ fetcher_->SetRequestContext(profile_->GetRequestContext());
+ fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
+ fetcher_->Start();
+}
+
+void ZerosuggestProvider::UpdateMatches(const string16& user_text) {
+ user_text_ = user_text;
+ const size_t prev_num_matches = matches_.size();
+ ConvertResultsToAutocompleteMatches();
+ if (matches_.size() != prev_num_matches)
+ listener_->OnProviderUpdate(true);
+}
+
+bool ZerosuggestProvider::ParseSuggestResults(Value* root_val) {
+ std::string query;
+ ListValue* root_list = NULL;
+ ListValue* results = NULL;
+ if (!root_val->GetAsList(&root_list) || !root_list->GetString(0, &query) ||
+ (query != current_query_) || !root_list->GetList(1, &results))
+ return false;
+
+ results_.clear();
+ ListValue* one_result = NULL;
+ for (size_t index = 0; results->GetList(index, &one_result); ++index) {
+ string16 result;
+ one_result->GetString(0, &result);
+ if (result.empty())
+ continue;
+ results_.push_back(result);
+ }
+
+ return true;
+}
+
+void ZerosuggestProvider::ConvertResultsToAutocompleteMatches() {
+ const TemplateURL* search_provider =
+ template_url_service_->GetDefaultSearchProvider();
+ if (search_provider == NULL || !search_provider->SupportsReplacement())
+ // Fail if we can't set the clickthrough URL for query suggestions.
+ return;
+ matches_.clear();
+ if (results_.empty())
+ // Do not add anything if there are no results for this URL.
+ return;
+ AddMatchForCurrentURL();
+ for (size_t i = 0; i < results_.size(); ++i)
+ AddMatchForResult(search_provider, i, results_[i]);
+}
+
+// TODO(jered): Rip this out once the first match is decoupled from the current
+// typing in the omnibox.
+void ZerosuggestProvider::AddMatchForCurrentURL() {
+ // If the user has typed something besides the current url, they probably
+ // don't intend to refresh it.
+ const bool user_text_is_url = user_text_ == current_query_text_;
+ if (user_text_.empty() || user_text_is_url) {
+ AutocompleteMatch match(this, 2000, false,
samarth 2012/08/13 17:42:37 Make 2000 a constant, and add TODO about getting s
Jered 2012/08/13 22:23:59 Done. I added a comment about why 2000 here, and a
+ AutocompleteMatch::SEARCH_ZEROSUGGEST_URL);
+ match.destination_url = GURL(current_query_);
+ match.contents = current_query_text_;
+ if (!user_text_is_url) {
+ match.fill_into_edit = current_query_text_;
+ match.inline_autocomplete_offset = 0;
+ }
+ AutocompleteMatch::ClassifyLocationInString(0, current_query_.size(),
+ match.contents.length(), ACMatchClassification::URL,
+ &match.contents_class);
+ matches_.push_back(match);
+ }
+}
+
+void ZerosuggestProvider::AddMatchForResult(
+ const TemplateURL* search_provider,
+ size_t result_index,
+ const string16& result) {
+ // TODO(jered): Rip out user_text_is_url logic when AddMatchForCurrentURL goes.
samarth 2012/08/13 17:42:37 nit: long line
Jered 2012/08/13 22:23:59 Done.
+ const bool user_text_is_url = user_text_ == current_query_text_;
+ const bool kCaseInsensitve = false;
+ if (!user_text_.empty() && !user_text_is_url &&
+ !StartsWith(result, user_text_, kCaseInsensitve))
+ // This suggestion isn't relevant for the current prefix.
+ return;
+ const int kRelevance = 1999;
+ AutocompleteMatch match(this, kRelevance, false,
+ AutocompleteMatch::SEARCH_ZEROSUGGEST);
+ match.contents = result;
+ match.fill_into_edit = result;
+ if (!user_text_is_url && user_text_ != result)
+ match.inline_autocomplete_offset = user_text_.length();
+
+ // Build a URL for this query using the default search provider.
+ const TemplateURLRef& search_url = search_provider->url_ref();
+ DCHECK(search_url.SupportsReplacement());
+ match.search_terms_args.reset(
+ new TemplateURLRef::SearchTermsArgs(result));
+ match.search_terms_args->original_query = string16();
+ match.search_terms_args->accepted_suggestion = result_index;
+ match.destination_url =
+ GURL(search_url.ReplaceSearchTerms(*match.search_terms_args.get()));
+
+ if (user_text_.empty() || user_text_is_url || user_text_ == result) {
+ match.contents_class.push_back(
+ ACMatchClassification(0, ACMatchClassification::NONE));
+ } else {
+ // Style to look like normal search suggestions.
+ match.contents_class.push_back(
+ ACMatchClassification(0, ACMatchClassification::DIM));
+ match.contents_class.push_back(
+ ACMatchClassification(user_text_.length(), ACMatchClassification::NONE));
+ }
+ match.transition = content::PAGE_TRANSITION_GENERATED;
+
+ matches_.push_back(match);
+}

Powered by Google App Engine
This is Rietveld 408576698