// Copyright 2017 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 "components/suggestions/webui/suggestions_source.h" #include "base/barrier_closure.h" #include "base/base64.h" #include "base/bind.h" #include "base/strings/strcat.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "components/suggestions/proto/suggestions.pb.h" #include "net/base/escape.h" #include "ui/base/l10n/time_format.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image_skia.h" namespace suggestions { namespace { const char kHtmlHeader[] = "\n\n
\nRefreshing in the background, reload to see new data.
\n"; return std::string("\n"; } // Returns the HTML needed to display the suggestions. std::string RenderOutputHtml( const std::string& base_url, bool is_refresh, const SuggestionsProfile& profile, const std::mapYou have no suggestions.
\n"); out.push_back(GetRefreshHtml(base_url, is_refresh)); out.push_back(kHtmlFooter); return base::StrCat(out); } } // namespace SuggestionsSource::SuggestionsSource(SuggestionsService* suggestions_service, const std::string& base_url) : suggestions_service_(suggestions_service), base_url_(base_url), weak_ptr_factory_(this) {} SuggestionsSource::~SuggestionsSource() {} SuggestionsSource::RequestContext::RequestContext( bool is_refresh_in, const SuggestionsProfile& suggestions_profile_in, const GotDataCallback& callback_in) : is_refresh(is_refresh_in), suggestions_profile(suggestions_profile_in), // Copy. callback(callback_in) // Copy. {} SuggestionsSource::RequestContext::~RequestContext() {} void SuggestionsSource::StartDataRequest(const std::string& path, const GotDataCallback& callback) { // If this was called as "chrome://suggestions/refresh", we also trigger an // async update of the suggestions. bool is_refresh = (path == kRefreshPath); // |suggestions_service| is null for guest profiles. if (!suggestions_service_) { std::string output = RenderOutputHtmlNoSuggestions(base_url_, is_refresh); callback.Run(base::RefCountedString::TakeString(&output)); return; } if (is_refresh) suggestions_service_->FetchSuggestionsData(); SuggestionsProfile suggestions_profile = suggestions_service_->GetSuggestionsDataFromCache().value_or( SuggestionsProfile()); size_t size = suggestions_profile.suggestions_size(); if (!size) { std::string output = RenderOutputHtmlNoSuggestions(base_url_, is_refresh); callback.Run(base::RefCountedString::TakeString(&output)); } else { RequestContext* context = new RequestContext(is_refresh, suggestions_profile, callback); base::Closure barrier = BarrierClosure( size, base::BindOnce(&SuggestionsSource::OnThumbnailsFetched, weak_ptr_factory_.GetWeakPtr(), context)); for (size_t i = 0; i < size; ++i) { const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i); // Fetch the thumbnail for this URL (exercising the fetcher). After all // fetches are done, including NULL callbacks for unavailable thumbnails, // SuggestionsSource::OnThumbnailsFetched will be called. suggestions_service_->GetPageThumbnail( GURL(suggestion.url()), base::Bind(&SuggestionsSource::OnThumbnailAvailable, weak_ptr_factory_.GetWeakPtr(), context, barrier)); } } } std::string SuggestionsSource::GetMimeType(const std::string& path) const { return "text/html"; } void SuggestionsSource::OnThumbnailsFetched(RequestContext* context) { std::unique_ptr