use new api names for SkGraphics
[chromium-blink-merge.git] / components / enhanced_bookmarks / bookmark_image_service.cc
blob066d9f93caedfa85dca7f347577069bf1968f6d6
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.
4 #include "components/enhanced_bookmarks/bookmark_image_service.h"
6 #include "base/single_thread_task_runner.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "components/bookmarks/browser/bookmark_model.h"
10 #include "components/bookmarks/browser/bookmark_model_observer.h"
11 #include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
12 #include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
13 #include "components/enhanced_bookmarks/persistent_image_store.h"
15 namespace {
17 const char kSequenceToken[] = "BookmarkImagesSequenceToken";
19 void ConstructPersistentImageStore(PersistentImageStore* store,
20 const base::FilePath& path) {
21 DCHECK(store);
22 new (store) PersistentImageStore(path);
25 void DeleteImageStore(ImageStore* store) {
26 DCHECK(store);
27 delete store;
30 void RetrieveImageFromStoreRelay(
31 ImageStore* store,
32 const GURL& page_url,
33 enhanced_bookmarks::BookmarkImageService::Callback callback,
34 scoped_refptr<base::SingleThreadTaskRunner> origin_loop) {
35 std::pair<gfx::Image, GURL> image_data = store->Get(page_url);
36 origin_loop->PostTask(
37 FROM_HERE, base::Bind(callback, image_data.first, image_data.second));
40 } // namespace
42 namespace enhanced_bookmarks {
43 BookmarkImageService::BookmarkImageService(
44 scoped_ptr<ImageStore> store,
45 EnhancedBookmarkModel* enhanced_bookmark_model,
46 scoped_refptr<base::SequencedWorkerPool> pool)
47 : enhanced_bookmark_model_(enhanced_bookmark_model),
48 store_(store.Pass()),
49 pool_(pool) {
50 DCHECK(CalledOnValidThread());
51 enhanced_bookmark_model_->bookmark_model()->AddObserver(this);
54 BookmarkImageService::BookmarkImageService(
55 const base::FilePath& path,
56 EnhancedBookmarkModel* enhanced_bookmark_model,
57 scoped_refptr<base::SequencedWorkerPool> pool)
58 : enhanced_bookmark_model_(enhanced_bookmark_model), pool_(pool) {
59 DCHECK(CalledOnValidThread());
60 // PersistentImageStore has to be constructed in the thread it will be used,
61 // so we are posting the construction to the thread. However, we first
62 // allocate memory and keep here. The reason is that, before
63 // PersistentImageStore construction is done, it's possible that
64 // another member function, that posts store_ to the thread, is called.
65 // Although the construction might not be finished yet, we still want to post
66 // the task since it's guaranteed to be constructed by the time it is used, by
67 // the sequential thread task pool.
69 // Other alternatives:
70 // - Using a lock or WaitableEvent for PersistentImageStore construction.
71 // But waiting on UI thread is discouraged.
72 // - Posting the current BookmarkImageService instance instead of store_.
73 // But this will require using a weak pointer and can potentially block
74 // destroying BookmarkImageService.
75 PersistentImageStore* store =
76 (PersistentImageStore*)::operator new(sizeof(PersistentImageStore));
77 store_.reset(store);
78 pool_->PostNamedSequencedWorkerTask(
79 kSequenceToken,
80 FROM_HERE,
81 base::Bind(&ConstructPersistentImageStore, store, path));
84 BookmarkImageService::~BookmarkImageService() {
85 DCHECK(CalledOnValidThread());
86 pool_->PostNamedSequencedWorkerTask(
87 kSequenceToken,
88 FROM_HERE,
89 base::Bind(&DeleteImageStore, store_.release()));
92 void BookmarkImageService::Shutdown() {
93 DCHECK(CalledOnValidThread());
94 enhanced_bookmark_model_->bookmark_model()->RemoveObserver(this);
95 enhanced_bookmark_model_ = NULL;
98 void BookmarkImageService::SalientImageForUrl(const GURL& page_url,
99 Callback callback) {
100 DCHECK(CalledOnValidThread());
101 SalientImageForUrl(page_url, true, callback);
104 void BookmarkImageService::RetrieveImageFromStore(
105 const GURL& page_url,
106 BookmarkImageService::Callback callback) {
107 DCHECK(CalledOnValidThread());
108 pool_->PostSequencedWorkerTaskWithShutdownBehavior(
109 pool_->GetNamedSequenceToken(kSequenceToken),
110 FROM_HERE,
111 base::Bind(&RetrieveImageFromStoreRelay,
112 base::Unretained(store_.get()),
113 page_url,
114 callback,
115 base::ThreadTaskRunnerHandle::Get()),
116 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
119 void BookmarkImageService::RetrieveSalientImageForPageUrl(
120 const GURL& page_url) {
121 DCHECK(CalledOnValidThread());
122 if (IsPageUrlInProgress(page_url))
123 return; // A request for this URL is already in progress.
125 in_progress_page_urls_.insert(page_url);
127 const BookmarkNode* bookmark =
128 enhanced_bookmark_model_->bookmark_model()
129 ->GetMostRecentlyAddedUserNodeForURL(page_url);
130 GURL image_url;
131 if (bookmark) {
132 int width;
133 int height;
134 enhanced_bookmark_model_->GetThumbnailImage(
135 bookmark, &image_url, &width, &height);
138 RetrieveSalientImage(
139 page_url,
140 image_url,
142 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
143 false);
146 void BookmarkImageService::FetchCallback(const GURL& page_url,
147 Callback original_callback,
148 const gfx::Image& image,
149 const GURL& image_url) {
150 DCHECK(CalledOnValidThread());
151 if (!image.IsEmpty() || !image_url.is_empty()) {
152 // Either the image was in the store or there is no image in the store, but
153 // an URL for an image is present, indicating that a previous attempt to
154 // download the image failed. Just return the image.
155 original_callback.Run(image, image_url);
156 } else {
157 // There is no image in the store, and no previous attempts to retrieve
158 // one. Start a request to retrieve a salient image if there is an image
159 // url set on a bookmark, and then enqueue the request for the image to
160 // be triggered when the retrieval is finished.
161 RetrieveSalientImageForPageUrl(page_url);
162 SalientImageForUrl(page_url, false, original_callback);
166 void BookmarkImageService::SalientImageForUrl(const GURL& page_url,
167 bool fetch_from_bookmark,
168 Callback callback) {
169 DCHECK(CalledOnValidThread());
171 // If the request is done while the image is currently being retrieved, just
172 // store the appropriate callbacks to call once the image is retrieved.
173 if (IsPageUrlInProgress(page_url)) {
174 callbacks_[page_url].push_back(callback);
175 return;
178 if (!fetch_from_bookmark) {
179 RetrieveImageFromStore(page_url, callback);
180 } else {
181 RetrieveImageFromStore(page_url,
182 base::Bind(&BookmarkImageService::FetchCallback,
183 base::Unretained(this),
184 page_url,
185 callback));
189 void BookmarkImageService::ProcessNewImage(const GURL& page_url,
190 bool update_bookmarks,
191 const gfx::Image& image,
192 const GURL& image_url) {
193 DCHECK(CalledOnValidThread());
194 StoreImage(image, image_url, page_url);
195 in_progress_page_urls_.erase(page_url);
196 ProcessRequests(page_url, image, image_url);
197 if (update_bookmarks && image_url.is_valid()) {
198 const BookmarkNode* bookmark =
199 enhanced_bookmark_model_->bookmark_model()
200 ->GetMostRecentlyAddedUserNodeForURL(page_url);
201 if (bookmark) {
202 const gfx::Size& size = image.Size();
203 bool result = enhanced_bookmark_model_->SetOriginalImage(
204 bookmark, image_url, size.width(), size.height());
205 DCHECK(result);
210 bool BookmarkImageService::IsPageUrlInProgress(const GURL& page_url) {
211 DCHECK(CalledOnValidThread());
212 return in_progress_page_urls_.find(page_url) != in_progress_page_urls_.end();
215 void BookmarkImageService::StoreImage(const gfx::Image& image,
216 const GURL& image_url,
217 const GURL& page_url) {
218 DCHECK(CalledOnValidThread());
219 if (!image.IsEmpty()) {
220 pool_->PostNamedSequencedWorkerTask(
221 kSequenceToken,
222 FROM_HERE,
223 base::Bind(&ImageStore::Insert,
224 base::Unretained(store_.get()),
225 page_url,
226 image_url,
227 image));
231 void BookmarkImageService::RemoveImageForUrl(const GURL& page_url) {
232 DCHECK(CalledOnValidThread());
233 pool_->PostNamedSequencedWorkerTask(
234 kSequenceToken,
235 FROM_HERE,
236 base::Bind(&ImageStore::Erase, base::Unretained(store_.get()), page_url));
237 in_progress_page_urls_.erase(page_url);
238 ProcessRequests(page_url, gfx::Image(), GURL());
241 void BookmarkImageService::ChangeImageURL(const GURL& from, const GURL& to) {
242 DCHECK(CalledOnValidThread());
243 pool_->PostNamedSequencedWorkerTask(kSequenceToken,
244 FROM_HERE,
245 base::Bind(&ImageStore::ChangeImageURL,
246 base::Unretained(store_.get()),
247 from,
248 to));
249 in_progress_page_urls_.erase(from);
250 ProcessRequests(from, gfx::Image(), GURL());
253 void BookmarkImageService::ClearAll() {
254 DCHECK(CalledOnValidThread());
255 // Clears and executes callbacks.
256 pool_->PostNamedSequencedWorkerTask(
257 kSequenceToken,
258 FROM_HERE,
259 base::Bind(&ImageStore::ClearAll, base::Unretained(store_.get())));
261 for (std::map<const GURL, std::vector<Callback> >::const_iterator it =
262 callbacks_.begin();
263 it != callbacks_.end();
264 ++it) {
265 ProcessRequests(it->first, gfx::Image(), GURL());
268 in_progress_page_urls_.erase(in_progress_page_urls_.begin(),
269 in_progress_page_urls_.end());
272 void BookmarkImageService::ProcessRequests(const GURL& page_url,
273 const gfx::Image& image,
274 const GURL& image_url) {
275 DCHECK(CalledOnValidThread());
277 std::vector<Callback> callbacks = callbacks_[page_url];
278 for (std::vector<Callback>::const_iterator it = callbacks.begin();
279 it != callbacks.end();
280 ++it) {
281 it->Run(image, image_url);
284 callbacks_.erase(page_url);
287 // BookmarkModelObserver methods.
289 void BookmarkImageService::BookmarkNodeRemoved(
290 BookmarkModel* model,
291 const BookmarkNode* parent,
292 int old_index,
293 const BookmarkNode* node,
294 const std::set<GURL>& removed_urls) {
295 DCHECK(CalledOnValidThread());
296 for (std::set<GURL>::const_iterator iter = removed_urls.begin();
297 iter != removed_urls.end();
298 ++iter) {
299 RemoveImageForUrl(*iter);
303 void BookmarkImageService::BookmarkModelLoaded(BookmarkModel* model,
304 bool ids_reassigned) {
307 void BookmarkImageService::BookmarkNodeMoved(BookmarkModel* model,
308 const BookmarkNode* old_parent,
309 int old_index,
310 const BookmarkNode* new_parent,
311 int new_index) {
314 void BookmarkImageService::BookmarkNodeAdded(BookmarkModel* model,
315 const BookmarkNode* parent,
316 int index) {
319 void BookmarkImageService::OnWillChangeBookmarkNode(BookmarkModel* model,
320 const BookmarkNode* node) {
321 DCHECK(CalledOnValidThread());
322 if (node->is_url())
323 previous_url_ = node->url();
326 void BookmarkImageService::BookmarkNodeChanged(BookmarkModel* model,
327 const BookmarkNode* node) {
328 DCHECK(CalledOnValidThread());
329 if (node->is_url() && previous_url_ != node->url())
330 ChangeImageURL(previous_url_, node->url());
333 void BookmarkImageService::BookmarkNodeFaviconChanged(
334 BookmarkModel* model,
335 const BookmarkNode* node) {
338 void BookmarkImageService::BookmarkNodeChildrenReordered(
339 BookmarkModel* model,
340 const BookmarkNode* node) {
343 void BookmarkImageService::BookmarkAllUserNodesRemoved(
344 BookmarkModel* model,
345 const std::set<GURL>& removed_urls) {
346 ClearAll();
349 } // namespace enhanced_bookmarks