Vectorize website settings icons in omnibox
[chromium-blink-merge.git] / components / suggestions / image_manager.cc
blob329b4d9f3f2829f5608323ac12195288102b4d1b
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/suggestions/image_manager.h"
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/task_runner_util.h"
10 #include "components/suggestions/image_encoder.h"
11 #include "components/suggestions/image_fetcher.h"
13 using leveldb_proto::ProtoDatabase;
15 namespace {
17 scoped_ptr<SkBitmap> DecodeImage(
18 scoped_refptr<base::RefCountedMemory> encoded_data) {
19 return scoped_ptr<SkBitmap>(suggestions::DecodeJPEGToSkBitmap(
20 encoded_data->front(), encoded_data->size()));
23 } // namespace
25 namespace suggestions {
27 ImageManager::ImageManager() : weak_ptr_factory_(this) {}
29 ImageManager::ImageManager(
30 scoped_ptr<ImageFetcher> image_fetcher,
31 scoped_ptr<ProtoDatabase<ImageData>> database,
32 const base::FilePath& database_dir,
33 scoped_refptr<base::TaskRunner> background_task_runner)
34 : image_fetcher_(image_fetcher.Pass()),
35 database_(database.Pass()),
36 background_task_runner_(background_task_runner),
37 database_ready_(false),
38 weak_ptr_factory_(this) {
39 image_fetcher_->SetImageFetcherDelegate(this);
40 database_->Init(database_dir, base::Bind(&ImageManager::OnDatabaseInit,
41 weak_ptr_factory_.GetWeakPtr()));
44 ImageManager::~ImageManager() {}
46 ImageManager::ImageCacheRequest::ImageCacheRequest() {}
48 ImageManager::ImageCacheRequest::~ImageCacheRequest() {}
50 void ImageManager::Initialize(const SuggestionsProfile& suggestions) {
51 image_url_map_.clear();
52 for (int i = 0; i < suggestions.suggestions_size(); ++i) {
53 const ChromeSuggestion& suggestion = suggestions.suggestions(i);
54 if (suggestion.has_thumbnail()) {
55 image_url_map_[GURL(suggestion.url())] = GURL(suggestion.thumbnail());
60 void ImageManager::GetImageForURL(
61 const GURL& url,
62 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
63 DCHECK(thread_checker_.CalledOnValidThread());
64 // If |url| is not found in |image_url_map_|, then invoke |callback| with
65 // NULL since there is no associated image for this |url|.
66 GURL image_url;
67 if (!GetImageURL(url, &image_url)) {
68 callback.Run(url, NULL);
69 return;
72 // |database_| can be NULL if something went wrong in initialization.
73 if (database_.get() && !database_ready_) {
74 // Once database is initialized, it will serve pending requests from either
75 // cache or network.
76 QueueCacheRequest(url, image_url, callback);
77 return;
80 ServeFromCacheOrNetwork(url, image_url, callback);
83 void ImageManager::OnImageFetched(const GURL& url, const SkBitmap* bitmap) {
84 if (bitmap) // |bitmap| can be nullptr if image fetch was unsuccessful.
85 SaveImage(url, *bitmap);
88 bool ImageManager::GetImageURL(const GURL& url, GURL* image_url) {
89 DCHECK(image_url);
90 std::map<GURL, GURL>::iterator it = image_url_map_.find(url);
91 if (it == image_url_map_.end()) return false; // Not found.
92 *image_url = it->second;
93 return true;
96 void ImageManager::QueueCacheRequest(
97 const GURL& url, const GURL& image_url,
98 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
99 // To be served when the database has loaded.
100 ImageCacheRequestMap::iterator it = pending_cache_requests_.find(url);
101 if (it == pending_cache_requests_.end()) {
102 ImageCacheRequest request;
103 request.url = url;
104 request.image_url = image_url;
105 request.callbacks.push_back(callback);
106 pending_cache_requests_[url] = request;
107 } else {
108 // Request already queued for this url.
109 it->second.callbacks.push_back(callback);
113 void ImageManager::OnCacheImageDecoded(
114 const GURL& url,
115 const GURL& image_url,
116 base::Callback<void(const GURL&, const SkBitmap*)> callback,
117 scoped_ptr<SkBitmap> bitmap) {
118 if (bitmap.get()) {
119 callback.Run(url, bitmap.get());
120 } else {
121 image_fetcher_->StartOrQueueNetworkRequest(url, image_url, callback);
125 scoped_refptr<base::RefCountedMemory> ImageManager::GetEncodedImageFromCache(
126 const GURL& url) {
127 ImageMap::iterator image_iter = image_map_.find(url.spec());
128 if (image_iter != image_map_.end()) {
129 return image_iter->second;
131 return nullptr;
134 void ImageManager::ServeFromCacheOrNetwork(
135 const GURL& url,
136 const GURL& image_url,
137 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
138 scoped_refptr<base::RefCountedMemory> encoded_data =
139 GetEncodedImageFromCache(url);
140 if (encoded_data.get()) {
141 base::PostTaskAndReplyWithResult(
142 background_task_runner_.get(), FROM_HERE,
143 base::Bind(&DecodeImage, encoded_data),
144 base::Bind(&ImageManager::OnCacheImageDecoded,
145 weak_ptr_factory_.GetWeakPtr(), url, image_url, callback));
146 } else {
147 image_fetcher_->StartOrQueueNetworkRequest(url, image_url, callback);
151 void ImageManager::SaveImage(const GURL& url, const SkBitmap& bitmap) {
152 scoped_refptr<base::RefCountedBytes> encoded_data(
153 new base::RefCountedBytes());
154 if (!EncodeSkBitmapToJPEG(bitmap, &encoded_data->data())) {
155 return;
158 // Update the image map.
159 image_map_.insert({url.spec(), encoded_data});
161 if (!database_ready_) return;
163 // Save the resulting bitmap to the database.
164 ImageData data;
165 data.set_url(url.spec());
166 data.set_data(encoded_data->front(), encoded_data->size());
167 scoped_ptr<ProtoDatabase<ImageData>::KeyEntryVector> entries_to_save(
168 new ProtoDatabase<ImageData>::KeyEntryVector());
169 scoped_ptr<std::vector<std::string>> keys_to_remove(
170 new std::vector<std::string>());
171 entries_to_save->push_back(std::make_pair(data.url(), data));
172 database_->UpdateEntries(entries_to_save.Pass(), keys_to_remove.Pass(),
173 base::Bind(&ImageManager::OnDatabaseSave,
174 weak_ptr_factory_.GetWeakPtr()));
177 void ImageManager::OnDatabaseInit(bool success) {
178 if (!success) {
179 DVLOG(1) << "Image database init failed.";
180 database_.reset();
181 ServePendingCacheRequests();
182 return;
184 database_->LoadEntries(base::Bind(&ImageManager::OnDatabaseLoad,
185 weak_ptr_factory_.GetWeakPtr()));
188 void ImageManager::OnDatabaseLoad(bool success,
189 scoped_ptr<ImageDataVector> entries) {
190 if (!success) {
191 DVLOG(1) << "Image database load failed.";
192 database_.reset();
193 ServePendingCacheRequests();
194 return;
196 database_ready_ = true;
198 LoadEntriesInCache(entries.Pass());
199 ServePendingCacheRequests();
202 void ImageManager::OnDatabaseSave(bool success) {
203 if (!success) {
204 DVLOG(1) << "Image database save failed.";
205 database_.reset();
206 database_ready_ = false;
210 void ImageManager::LoadEntriesInCache(scoped_ptr<ImageDataVector> entries) {
211 for (ImageDataVector::iterator it = entries->begin(); it != entries->end();
212 ++it) {
213 std::vector<unsigned char> encoded_data(it->data().begin(),
214 it->data().end());
216 image_map_.insert(
217 {it->url(), base::RefCountedBytes::TakeVector(&encoded_data)});
221 void ImageManager::ServePendingCacheRequests() {
222 for (ImageCacheRequestMap::iterator it = pending_cache_requests_.begin();
223 it != pending_cache_requests_.end(); ++it) {
224 const ImageCacheRequest& request = it->second;
225 for (CallbackVector::const_iterator callback_it = request.callbacks.begin();
226 callback_it != request.callbacks.end(); ++callback_it) {
227 ServeFromCacheOrNetwork(request.url, request.image_url, *callback_it);
232 } // namespace suggestions