ProjectingObserverChromeos: Drop DBusThreadManager dependency for better testing.
[chromium-blink-merge.git] / components / suggestions / image_manager.cc
blob9e4338127d35e4fcce065d010f06a66a5fe01ecb
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 "components/suggestions/image_fetcher.h"
9 #include "ui/gfx/codec/jpeg_codec.h"
11 using leveldb_proto::ProtoDatabase;
13 namespace {
15 // From JPEG-encoded bytes to SkBitmap.
16 SkBitmap* DecodeImage(const std::vector<unsigned char>& encoded_data) {
17 return gfx::JPEGCodec::Decode(&encoded_data[0], encoded_data.size());
20 } // namespace
22 namespace suggestions {
24 ImageManager::ImageManager() : weak_ptr_factory_(this) {}
26 ImageManager::ImageManager(scoped_ptr<ImageFetcher> image_fetcher,
27 scoped_ptr<ProtoDatabase<ImageData> > database,
28 const base::FilePath& database_dir)
29 : image_fetcher_(image_fetcher.Pass()),
30 database_(database.Pass()),
31 database_ready_(false),
32 weak_ptr_factory_(this) {
33 image_fetcher_->SetImageFetcherDelegate(this);
34 database_->Init(database_dir, base::Bind(&ImageManager::OnDatabaseInit,
35 weak_ptr_factory_.GetWeakPtr()));
38 ImageManager::~ImageManager() {}
40 ImageManager::ImageCacheRequest::ImageCacheRequest() {}
42 ImageManager::ImageCacheRequest::~ImageCacheRequest() {}
44 void ImageManager::Initialize(const SuggestionsProfile& suggestions) {
45 image_url_map_.clear();
46 for (int i = 0; i < suggestions.suggestions_size(); ++i) {
47 const ChromeSuggestion& suggestion = suggestions.suggestions(i);
48 if (suggestion.has_thumbnail()) {
49 image_url_map_[GURL(suggestion.url())] = GURL(suggestion.thumbnail());
54 void ImageManager::GetImageForURL(
55 const GURL& url,
56 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
57 DCHECK(thread_checker_.CalledOnValidThread());
58 // If |url| is not found in |image_url_map_|, then invoke |callback| with
59 // NULL since there is no associated image for this |url|.
60 GURL image_url;
61 if (!GetImageURL(url, &image_url)) {
62 callback.Run(url, NULL);
63 return;
66 // |database_| can be NULL if something went wrong in initialization.
67 if (database_.get() && !database_ready_) {
68 // Once database is initialized, it will serve pending requests from either
69 // cache or network.
70 QueueCacheRequest(url, image_url, callback);
71 return;
74 ServeFromCacheOrNetwork(url, image_url, callback);
77 void ImageManager::OnImageFetched(const GURL& url, const SkBitmap* bitmap) {
78 SaveImage(url, *bitmap);
81 bool ImageManager::GetImageURL(const GURL& url, GURL* image_url) {
82 std::map<GURL, GURL>::iterator it = image_url_map_.find(url);
83 if (it == image_url_map_.end()) return false; // Not found.
84 *image_url = it->second;
85 return true;
88 void ImageManager::QueueCacheRequest(
89 const GURL& url, const GURL& image_url,
90 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
91 // To be served when the database has loaded.
92 ImageCacheRequestMap::iterator it = pending_cache_requests_.find(url);
93 if (it == pending_cache_requests_.end()) {
94 ImageCacheRequest request;
95 request.url = url;
96 request.image_url = image_url;
97 request.callbacks.push_back(callback);
98 pending_cache_requests_[url] = request;
99 } else {
100 // Request already queued for this url.
101 it->second.callbacks.push_back(callback);
105 void ImageManager::ServeFromCacheOrNetwork(
106 const GURL& url, const GURL& image_url,
107 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
108 // If there is a image available in memory, return it.
109 if (!ServeFromCache(url, callback)) {
110 image_fetcher_->StartOrQueueNetworkRequest(url, image_url, callback);
114 bool ImageManager::ServeFromCache(
115 const GURL& url,
116 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
117 SkBitmap* bitmap = GetBitmapFromCache(url);
118 if (bitmap) {
119 callback.Run(url, bitmap);
120 return true;
122 return false;
125 SkBitmap* ImageManager::GetBitmapFromCache(const GURL& url) {
126 ImageMap::iterator image_iter = image_map_.find(url.spec());
127 if (image_iter != image_map_.end()) {
128 return &image_iter->second;
130 return NULL;
133 void ImageManager::SaveImage(const GURL& url, const SkBitmap& bitmap) {
134 // Update the image map.
135 image_map_.insert(std::make_pair(url.spec(), bitmap));
137 if (!database_ready_) return;
139 // Attempt to save a JPEG representation to the database. If not successful,
140 // the fetched bitmap will still be inserted in the cache, above.
141 std::vector<unsigned char> encoded_data;
142 if (EncodeImage(bitmap, &encoded_data)) {
143 // Save the resulting bitmap to the database.
144 ImageData data;
145 data.set_url(url.spec());
146 data.set_data(std::string(encoded_data.begin(), encoded_data.end()));
147 scoped_ptr<ProtoDatabase<ImageData>::KeyEntryVector> entries_to_save(
148 new ProtoDatabase<ImageData>::KeyEntryVector());
149 scoped_ptr<std::vector<std::string> > keys_to_remove(
150 new std::vector<std::string>());
151 entries_to_save->push_back(std::make_pair(data.url(), data));
152 database_->UpdateEntries(entries_to_save.Pass(), keys_to_remove.Pass(),
153 base::Bind(&ImageManager::OnDatabaseSave,
154 weak_ptr_factory_.GetWeakPtr()));
158 void ImageManager::OnDatabaseInit(bool success) {
159 if (!success) {
160 DVLOG(1) << "Image database init failed.";
161 database_.reset();
162 ServePendingCacheRequests();
163 return;
165 database_->LoadEntries(base::Bind(&ImageManager::OnDatabaseLoad,
166 weak_ptr_factory_.GetWeakPtr()));
169 void ImageManager::OnDatabaseLoad(bool success,
170 scoped_ptr<ImageDataVector> entries) {
171 if (!success) {
172 DVLOG(1) << "Image database load failed.";
173 database_.reset();
174 ServePendingCacheRequests();
175 return;
177 database_ready_ = true;
179 LoadEntriesInCache(entries.Pass());
180 ServePendingCacheRequests();
183 void ImageManager::OnDatabaseSave(bool success) {
184 if (!success) {
185 DVLOG(1) << "Image database save failed.";
186 database_.reset();
187 database_ready_ = false;
191 void ImageManager::LoadEntriesInCache(scoped_ptr<ImageDataVector> entries) {
192 for (ImageDataVector::iterator it = entries->begin(); it != entries->end();
193 ++it) {
194 std::vector<unsigned char> encoded_data(it->data().begin(),
195 it->data().end());
197 scoped_ptr<SkBitmap> bitmap(DecodeImage(encoded_data));
198 if (bitmap.get()) {
199 image_map_.insert(std::make_pair(it->url(), *bitmap));
204 void ImageManager::ServePendingCacheRequests() {
205 for (ImageCacheRequestMap::iterator it = pending_cache_requests_.begin();
206 it != pending_cache_requests_.end(); ++it) {
207 const ImageCacheRequest& request = it->second;
208 for (CallbackVector::const_iterator callback_it = request.callbacks.begin();
209 callback_it != request.callbacks.end(); ++callback_it) {
210 ServeFromCacheOrNetwork(request.url, request.image_url, *callback_it);
215 // static
216 bool ImageManager::EncodeImage(const SkBitmap& bitmap,
217 std::vector<unsigned char>* dest) {
218 SkAutoLockPixels bitmap_lock(bitmap);
219 if (!bitmap.readyToDraw() || bitmap.isNull()) {
220 return false;
222 return gfx::JPEGCodec::Encode(
223 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
224 gfx::JPEGCodec::FORMAT_SkBitmap, bitmap.width(), bitmap.height(),
225 bitmap.rowBytes(), 100, dest);
228 } // namespace suggestions