1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/search/suggestions/suggestions_source.h" 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <vector> 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/barrier_closure.h" 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/base64.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/bind.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/ref_counted_memory.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/string16.h" 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/strings/string_piece.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/string_util.h" 176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/stringprintf.h" 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/time/time.h" 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/search/suggestions/suggestions_service_factory.h" 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/common/url_constants.h" 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/suggestions/suggestions_service.h" 2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/suggestions/suggestions_utils.h" 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/escape.h" 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/base/l10n/time_format.h" 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h" 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/image/image_skia.h" 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "url/gurl.h" 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace suggestions { 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace { 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kHtmlHeader[] = 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) "<!DOCTYPE html>\n<html>\n<head>\n<title>Suggestions</title>\n" 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) "<meta charset=\"utf-8\">\n" 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) "<style type=\"text/css\">\nli {white-space: nowrap;}\n</style>\n"; 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kHtmlBody[] = "</head>\n<body>\n"; 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kHtmlFooter[] = "</body>\n</html>\n"; 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Fills |output| with the HTML needed to display the suggestions. 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RenderOutputHtml(const SuggestionsProfile& profile, 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::map<GURL, std::string>& base64_encoded_pngs, 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string* output) { 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<std::string> out; 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back(kHtmlHeader); 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back(kHtmlBody); 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back("<h1>Suggestions</h1>\n<ul>"); 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int64 now = (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()) 526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) .ToInternalValue(); 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t size = profile.suggestions_size(); 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (size_t i = 0; i < size; ++i) { 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const ChromeSuggestion& suggestion = profile.suggestions(i); 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::TimeDelta remaining_time = base::TimeDelta::FromMicroseconds( 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) suggestion.expiry_ts() - now); 586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::string16 remaining_time_formatted = ui::TimeFormat::Detailed( 596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::TimeFormat::Format::FORMAT_DURATION, 606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::TimeFormat::Length::LENGTH_LONG, 616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) -1, remaining_time); 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string line; 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) line += "<li><a href=\""; 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) line += net::EscapeForHTML(suggestion.url()); 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) line += "\" target=\"_blank\">"; 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) line += net::EscapeForHTML(suggestion.title()); 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::map<GURL, std::string>::const_iterator it = 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base64_encoded_pngs.find(GURL(suggestion.url())); 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (it != base64_encoded_pngs.end()) { 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) line += "<br><img src='"; 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) line += it->second; 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) line += "'>"; 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) line += "</a> Expires in "; 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) line += base::UTF16ToUTF8(remaining_time_formatted); 766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) line += "</li>\n"; 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back(line); 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back("</ul>"); 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back(kHtmlFooter); 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *output = JoinString(out, ""); 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Fills |output| with the HTML needed to display that no suggestions are 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// available. 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RenderOutputHtmlNoSuggestions(std::string* output) { 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<std::string> out; 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back(kHtmlHeader); 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back(kHtmlBody); 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back("<h1>Suggestions</h1>\n"); 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back("<p>You have no suggestions.</p>\n"); 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out.push_back(kHtmlFooter); 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *output = JoinString(out, ""); 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SuggestionsSource::SuggestionsSource(Profile* profile) 99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : profile_(profile), weak_ptr_factory_(this) {} 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SuggestionsSource::~SuggestionsSource() {} 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SuggestionsSource::RequestContext::RequestContext( 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SuggestionsProfile& suggestions_profile_in, 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const content::URLDataSource::GotDataCallback& callback_in) 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : suggestions_profile(suggestions_profile_in), // Copy. 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback(callback_in) // Copy. 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles){} 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SuggestionsSource::RequestContext::~RequestContext() {} 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string SuggestionsSource::GetSource() const { 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return chrome::kChromeUISuggestionsHost; 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void SuggestionsSource::StartDataRequest( 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& path, int render_process_id, int render_frame_id, 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const content::URLDataSource::GotDataCallback& callback) { 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SuggestionsServiceFactory* suggestions_service_factory = 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SuggestionsServiceFactory::GetInstance(); 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SuggestionsService* suggestions_service( 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) suggestions_service_factory->GetForProfile(profile_)); 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!suggestions_service) { 126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) callback.Run(NULL); 127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // Since it's a debugging page, it's fine to specify that sync state is 13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // initialized. 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) suggestions_service->FetchSuggestionsData( 13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) INITIALIZED_ENABLED_HISTORY, 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&SuggestionsSource::OnSuggestionsAvailable, 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), callback)); 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string SuggestionsSource::GetMimeType(const std::string& path) const { 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return "text/html"; 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::MessageLoop* SuggestionsSource::MessageLoopForRequestPath( 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& path) const { 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // This can be accessed from the IO thread. 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return content::URLDataSource::MessageLoopForRequestPath(path); 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void SuggestionsSource::OnSuggestionsAvailable( 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const content::URLDataSource::GotDataCallback& callback, 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const SuggestionsProfile& suggestions_profile) { 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) size_t size = suggestions_profile.suggestions_size(); 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!size) { 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string output; 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RenderOutputHtmlNoSuggestions(&output); 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback.Run(base::RefCountedString::TakeString(&output)); 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RequestContext* context = new RequestContext(suggestions_profile, callback); 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Closure barrier = BarrierClosure( 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size, base::Bind(&SuggestionsSource::OnThumbnailsFetched, 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), context)); 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 0; i < size; ++i) { 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i); 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Fetch the thumbnail for this URL (exercising the fetcher). After all 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // fetches are done, including NULL callbacks for unavailable thumbnails, 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // SuggestionsSource::OnThumbnailsFetched will be called. 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SuggestionsService* suggestions_service( 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SuggestionsServiceFactory::GetForProfile(profile_)); 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) suggestions_service->GetPageThumbnail( 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GURL(suggestion.url()), 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&SuggestionsSource::OnThumbnailAvailable, 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), context, barrier)); 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SuggestionsSource::OnThumbnailsFetched(RequestContext* context) { 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<RequestContext> context_deleter(context); 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string output; 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RenderOutputHtml(context->suggestions_profile, context->base64_encoded_pngs, 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &output); 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) context->callback.Run(base::RefCountedString::TakeString(&output)); 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SuggestionsSource::OnThumbnailAvailable(RequestContext* context, 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Closure barrier, 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const GURL& url, 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkBitmap* bitmap) { 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (bitmap) { 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<unsigned char> output; 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &output); 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string encoded_output; 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Base64Encode(std::string(output.begin(), output.end()), 195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &encoded_output); 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) context->base64_encoded_pngs[url] = "data:image/png;base64,"; 197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) context->base64_encoded_pngs[url] += encoded_output; 198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) barrier.Run(); 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace suggestions 203