BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / components / suggestions / image_manager.cc
blobfae4f960c05b187492212c1dcf9011165e547583
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::AddImageURL(const GURL& url, const GURL& image_url) {
61 DCHECK(thread_checker_.CalledOnValidThread());
62 image_url_map_[url] = image_url;
65 void ImageManager::GetImageForURL(
66 const GURL& url,
67 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
68 DCHECK(thread_checker_.CalledOnValidThread());
69 // If |url| is not found in |image_url_map_|, then invoke |callback| with
70 // NULL since there is no associated image for this |url|.
71 GURL image_url;
72 if (!GetImageURL(url, &image_url)) {
73 callback.Run(url, NULL);
74 return;
77 // |database_| can be NULL if something went wrong in initialization.
78 if (database_.get() && !database_ready_) {
79 // Once database is initialized, it will serve pending requests from either
80 // cache or network.
81 QueueCacheRequest(url, image_url, callback);
82 return;
85 ServeFromCacheOrNetwork(url, image_url, callback);
88 void ImageManager::OnImageFetched(const GURL& url, const SkBitmap* bitmap) {
89 if (bitmap) // |bitmap| can be nullptr if image fetch was unsuccessful.
90 SaveImage(url, *bitmap);
93 bool ImageManager::GetImageURL(const GURL& url, GURL* image_url) {
94 DCHECK(image_url);
95 std::map<GURL, GURL>::iterator it = image_url_map_.find(url);
96 if (it == image_url_map_.end()) return false; // Not found.
97 *image_url = it->second;
98 return true;
101 void ImageManager::QueueCacheRequest(
102 const GURL& url, const GURL& image_url,
103 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
104 // To be served when the database has loaded.
105 ImageCacheRequestMap::iterator it = pending_cache_requests_.find(url);
106 if (it == pending_cache_requests_.end()) {
107 ImageCacheRequest request;
108 request.url = url;
109 request.image_url = image_url;
110 request.callbacks.push_back(callback);
111 pending_cache_requests_[url] = request;
112 } else {
113 // Request already queued for this url.
114 it->second.callbacks.push_back(callback);
118 void ImageManager::OnCacheImageDecoded(
119 const GURL& url,
120 const GURL& image_url,
121 base::Callback<void(const GURL&, const SkBitmap*)> callback,
122 scoped_ptr<SkBitmap> bitmap) {
123 if (bitmap.get()) {
124 callback.Run(url, bitmap.get());
125 } else {
126 image_fetcher_->StartOrQueueNetworkRequest(url, image_url, callback);
130 scoped_refptr<base::RefCountedMemory> ImageManager::GetEncodedImageFromCache(
131 const GURL& url) {
132 ImageMap::iterator image_iter = image_map_.find(url.spec());
133 if (image_iter != image_map_.end()) {
134 return image_iter->second;
136 return nullptr;
139 void ImageManager::ServeFromCacheOrNetwork(
140 const GURL& url,
141 const GURL& image_url,
142 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
143 scoped_refptr<base::RefCountedMemory> encoded_data =
144 GetEncodedImageFromCache(url);
145 if (encoded_data.get()) {
146 base::PostTaskAndReplyWithResult(
147 background_task_runner_.get(), FROM_HERE,
148 base::Bind(&DecodeImage, encoded_data),
149 base::Bind(&ImageManager::OnCacheImageDecoded,
150 weak_ptr_factory_.GetWeakPtr(), url, image_url, callback));
151 } else {
152 image_fetcher_->StartOrQueueNetworkRequest(url, image_url, callback);
156 void ImageManager::SaveImage(const GURL& url, const SkBitmap& bitmap) {
157 scoped_refptr<base::RefCountedBytes> encoded_data(
158 new base::RefCountedBytes());
159 if (!EncodeSkBitmapToJPEG(bitmap, &encoded_data->data())) {
160 return;
163 // Update the image map.
164 image_map_.insert({url.spec(), encoded_data});
166 if (!database_ready_) return;
168 // Save the resulting bitmap to the database.
169 ImageData data;
170 data.set_url(url.spec());
171 data.set_data(encoded_data->front(), encoded_data->size());
172 scoped_ptr<ProtoDatabase<ImageData>::KeyEntryVector> entries_to_save(
173 new ProtoDatabase<ImageData>::KeyEntryVector());
174 scoped_ptr<std::vector<std::string>> keys_to_remove(
175 new std::vector<std::string>());
176 entries_to_save->push_back(std::make_pair(data.url(), data));
177 database_->UpdateEntries(entries_to_save.Pass(), keys_to_remove.Pass(),
178 base::Bind(&ImageManager::OnDatabaseSave,
179 weak_ptr_factory_.GetWeakPtr()));
182 void ImageManager::OnDatabaseInit(bool success) {
183 if (!success) {
184 DVLOG(1) << "Image database init failed.";
185 database_.reset();
186 ServePendingCacheRequests();
187 return;
189 database_->LoadEntries(base::Bind(&ImageManager::OnDatabaseLoad,
190 weak_ptr_factory_.GetWeakPtr()));
193 void ImageManager::OnDatabaseLoad(bool success,
194 scoped_ptr<ImageDataVector> entries) {
195 if (!success) {
196 DVLOG(1) << "Image database load failed.";
197 database_.reset();
198 ServePendingCacheRequests();
199 return;
201 database_ready_ = true;
203 LoadEntriesInCache(entries.Pass());
204 ServePendingCacheRequests();
207 void ImageManager::OnDatabaseSave(bool success) {
208 if (!success) {
209 DVLOG(1) << "Image database save failed.";
210 database_.reset();
211 database_ready_ = false;
215 void ImageManager::LoadEntriesInCache(scoped_ptr<ImageDataVector> entries) {
216 for (ImageDataVector::iterator it = entries->begin(); it != entries->end();
217 ++it) {
218 std::vector<unsigned char> encoded_data(it->data().begin(),
219 it->data().end());
221 image_map_.insert(
222 {it->url(), base::RefCountedBytes::TakeVector(&encoded_data)});
226 void ImageManager::ServePendingCacheRequests() {
227 for (ImageCacheRequestMap::iterator it = pending_cache_requests_.begin();
228 it != pending_cache_requests_.end(); ++it) {
229 const ImageCacheRequest& request = it->second;
230 for (CallbackVector::const_iterator callback_it = request.callbacks.begin();
231 callback_it != request.callbacks.end(); ++callback_it) {
232 ServeFromCacheOrNetwork(request.url, request.image_url, *callback_it);
237 } // namespace suggestions