ozone: fix HDPMLegacy - do the PF after overlays, also clear old overlays
[chromium-blink-merge.git] / components / enhanced_bookmarks / bookmark_image_service.cc
blobc2c019e7677ac4c38038a0433dfd5e63ae3db131
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/enhanced_bookmarks/bookmark_image_service.h"
7 #include "base/single_thread_task_runner.h"
8 #include "base/task_runner_util.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "components/bookmarks/browser/bookmark_model.h"
12 #include "components/bookmarks/browser/bookmark_model_observer.h"
13 #include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
14 #include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
15 #include "components/enhanced_bookmarks/image_store_util.h"
16 #include "components/enhanced_bookmarks/persistent_image_store.h"
18 using bookmarks::BookmarkModel;
20 namespace {
22 const char kSequenceToken[] = "BookmarkImagesSequenceToken";
24 void ConstructPersistentImageStore(PersistentImageStore* store,
25 const base::FilePath& path) {
26 DCHECK(store);
27 new (store) PersistentImageStore(path);
30 void DeleteImageStore(ImageStore* store) {
31 DCHECK(store);
32 delete store;
35 void RetrieveImageFromStoreRelay(
36 ImageStore* store,
37 const GURL& page_url,
38 enhanced_bookmarks::BookmarkImageService::ImageCallback callback,
39 scoped_refptr<base::SingleThreadTaskRunner> origin_loop) {
40 origin_loop->PostTask(FROM_HERE, base::Bind(callback, store->Get(page_url)));
43 } // namespace
45 namespace enhanced_bookmarks {
46 BookmarkImageService::BookmarkImageService(
47 scoped_ptr<ImageStore> store,
48 EnhancedBookmarkModel* enhanced_bookmark_model,
49 scoped_refptr<base::SequencedWorkerPool> pool)
50 : enhanced_bookmark_model_(enhanced_bookmark_model),
51 store_(store.Pass()),
52 pool_(pool) {
53 DCHECK(CalledOnValidThread());
54 enhanced_bookmark_model_->bookmark_model()->AddObserver(this);
57 BookmarkImageService::BookmarkImageService(
58 const base::FilePath& path,
59 EnhancedBookmarkModel* enhanced_bookmark_model,
60 scoped_refptr<base::SequencedWorkerPool> pool)
61 : enhanced_bookmark_model_(enhanced_bookmark_model), pool_(pool) {
62 DCHECK(CalledOnValidThread());
63 // PersistentImageStore has to be constructed in the thread it will be used,
64 // so we are posting the construction to the thread. However, we first
65 // allocate memory and keep here. The reason is that, before
66 // PersistentImageStore construction is done, it's possible that
67 // another member function, that posts store_ to the thread, is called.
68 // Although the construction might not be finished yet, we still want to post
69 // the task since it's guaranteed to be constructed by the time it is used, by
70 // the sequential thread task pool.
72 // Other alternatives:
73 // - Using a lock or WaitableEvent for PersistentImageStore construction.
74 // But waiting on UI thread is discouraged.
75 // - Posting the current BookmarkImageService instance instead of store_.
76 // But this will require using a weak pointer and can potentially block
77 // destroying BookmarkImageService.
78 PersistentImageStore* store =
79 (PersistentImageStore*)::operator new(sizeof(PersistentImageStore));
80 store_.reset(store);
81 pool_->PostNamedSequencedWorkerTask(
82 kSequenceToken,
83 FROM_HERE,
84 base::Bind(&ConstructPersistentImageStore, store, path));
87 BookmarkImageService::~BookmarkImageService() {
88 DCHECK(CalledOnValidThread());
89 pool_->PostNamedSequencedWorkerTask(
90 kSequenceToken,
91 FROM_HERE,
92 base::Bind(&DeleteImageStore, store_.release()));
95 void BookmarkImageService::Shutdown() {
96 DCHECK(CalledOnValidThread());
97 enhanced_bookmark_model_->bookmark_model()->RemoveObserver(this);
98 enhanced_bookmark_model_ = NULL;
101 void BookmarkImageService::SalientImageForUrl(const GURL& page_url,
102 ImageCallback callback) {
103 DCHECK(CalledOnValidThread());
104 SalientImageForUrl(page_url, true, callback);
107 void BookmarkImageService::RetrieveImageFromStore(const GURL& page_url,
108 ImageCallback callback) {
109 DCHECK(CalledOnValidThread());
110 pool_->PostSequencedWorkerTaskWithShutdownBehavior(
111 pool_->GetNamedSequenceToken(kSequenceToken),
112 FROM_HERE,
113 base::Bind(&RetrieveImageFromStoreRelay,
114 base::Unretained(store_.get()),
115 page_url,
116 callback,
117 base::ThreadTaskRunnerHandle::Get()),
118 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
121 void BookmarkImageService::RetrieveSalientImageForPageUrl(
122 const GURL& page_url) {
123 DCHECK(CalledOnValidThread());
124 if (IsPageUrlInProgress(page_url))
125 return; // A request for this URL is already in progress.
127 in_progress_page_urls_.insert(page_url);
129 const BookmarkNode* bookmark =
130 enhanced_bookmark_model_->bookmark_model()
131 ->GetMostRecentlyAddedUserNodeForURL(page_url);
132 GURL image_url;
133 if (bookmark) {
134 int width;
135 int height;
136 enhanced_bookmark_model_->GetThumbnailImage(
137 bookmark, &image_url, &width, &height);
140 RetrieveSalientImage(
141 page_url,
142 image_url,
144 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
145 false);
148 void BookmarkImageService::FetchCallback(const GURL& page_url,
149 ImageCallback original_callback,
150 const ImageRecord& record) {
151 DCHECK(CalledOnValidThread());
152 if (!record.image.IsEmpty() || !record.url.is_empty()) {
153 // Either the record was in the store or there is no image in the store, but
154 // an URL for a record is present, indicating that a previous attempt to
155 // download the image failed. Just return the record.
156 original_callback.Run(record);
157 } else {
158 // There is no record in the store, and no previous attempts to retrieve
159 // one. Start a request to retrieve a salient image if there is an image
160 // url set on a bookmark, and then enqueue the request for the record to
161 // be triggered when the retrieval is finished.
162 RetrieveSalientImageForPageUrl(page_url);
163 SalientImageForUrl(page_url, false, original_callback);
167 void BookmarkImageService::SalientImageForUrl(const GURL& page_url,
168 bool fetch_from_bookmark,
169 ImageCallback callback) {
170 DCHECK(CalledOnValidThread());
172 // If the request is done while the image is currently being retrieved, just
173 // store the appropriate callbacks to call once the image is retrieved.
174 if (IsPageUrlInProgress(page_url)) {
175 callbacks_[page_url].push_back(callback);
176 return;
179 if (!fetch_from_bookmark) {
180 RetrieveImageFromStore(page_url, callback);
181 } else {
182 RetrieveImageFromStore(page_url,
183 base::Bind(&BookmarkImageService::FetchCallback,
184 base::Unretained(this),
185 page_url,
186 callback));
190 void BookmarkImageService::ProcessNewImage(const GURL& page_url,
191 bool update_bookmarks,
192 const gfx::Image& image,
193 const GURL& image_url) {
194 DCHECK(CalledOnValidThread());
195 PostTaskToStoreImage(image, image_url, page_url);
196 if (update_bookmarks && image_url.is_valid()) {
197 const BookmarkNode* bookmark =
198 enhanced_bookmark_model_->bookmark_model()
199 ->GetMostRecentlyAddedUserNodeForURL(page_url);
200 if (bookmark) {
201 const gfx::Size& size = image.Size();
202 bool result = enhanced_bookmark_model_->SetOriginalImage(
203 bookmark, image_url, size.width(), size.height());
204 DCHECK(result);
209 bool BookmarkImageService::IsPageUrlInProgress(const GURL& page_url) {
210 DCHECK(CalledOnValidThread());
211 return in_progress_page_urls_.find(page_url) != in_progress_page_urls_.end();
214 ImageRecord BookmarkImageService::StoreImage(const gfx::Image& image,
215 const GURL& image_url,
216 const GURL& page_url) {
217 ImageRecord image_info(image, image_url, SK_ColorBLACK);
218 if (!image.IsEmpty()) {
219 image_info.dominant_color = DominantColorForImage(image);
220 // TODO(lpromero): this should be saved all the time, even when there is an
221 // empty image. http://crbug.com/451450
222 pool_->PostNamedSequencedWorkerTask(
223 kSequenceToken, FROM_HERE,
224 base::Bind(&ImageStore::Insert, base::Unretained(store_.get()),
225 page_url, image_info));
227 return image_info;
230 void BookmarkImageService::PostTaskToStoreImage(const gfx::Image& image,
231 const GURL& image_url,
232 const GURL& page_url) {
233 DCHECK(CalledOnValidThread());
235 base::Callback<ImageRecord(void)> task =
236 base::Bind(&BookmarkImageService::StoreImage, base::Unretained(this),
237 image, image_url, page_url);
238 base::Callback<void(const ImageRecord&)> reply =
239 base::Bind(&BookmarkImageService::OnStoreImagePosted,
240 base::Unretained(this), page_url);
242 base::PostTaskAndReplyWithResult(pool_.get(), FROM_HERE, task, reply);
245 void BookmarkImageService::OnStoreImagePosted(const GURL& page_url,
246 const ImageRecord& image) {
247 DCHECK(CalledOnValidThread());
248 in_progress_page_urls_.erase(page_url);
249 ProcessRequests(page_url, image);
252 void BookmarkImageService::RemoveImageForUrl(const GURL& page_url) {
253 DCHECK(CalledOnValidThread());
254 pool_->PostNamedSequencedWorkerTask(
255 kSequenceToken,
256 FROM_HERE,
257 base::Bind(&ImageStore::Erase, base::Unretained(store_.get()), page_url));
258 in_progress_page_urls_.erase(page_url);
259 ProcessRequests(page_url, ImageRecord());
262 void BookmarkImageService::ChangeImageURL(const GURL& from, const GURL& to) {
263 DCHECK(CalledOnValidThread());
264 pool_->PostNamedSequencedWorkerTask(kSequenceToken,
265 FROM_HERE,
266 base::Bind(&ImageStore::ChangeImageURL,
267 base::Unretained(store_.get()),
268 from,
269 to));
270 in_progress_page_urls_.erase(from);
271 ProcessRequests(from, ImageRecord());
274 void BookmarkImageService::ClearAll() {
275 DCHECK(CalledOnValidThread());
276 // Clears and executes callbacks.
277 pool_->PostNamedSequencedWorkerTask(
278 kSequenceToken,
279 FROM_HERE,
280 base::Bind(&ImageStore::ClearAll, base::Unretained(store_.get())));
282 for (std::map<const GURL, std::vector<ImageCallback>>::const_iterator it =
283 callbacks_.begin();
284 it != callbacks_.end(); ++it) {
285 ProcessRequests(it->first, ImageRecord());
288 in_progress_page_urls_.erase(in_progress_page_urls_.begin(),
289 in_progress_page_urls_.end());
292 void BookmarkImageService::ProcessRequests(const GURL& page_url,
293 const ImageRecord& record) {
294 DCHECK(CalledOnValidThread());
296 std::vector<ImageCallback> callbacks = callbacks_[page_url];
297 for (std::vector<ImageCallback>::const_iterator it = callbacks.begin();
298 it != callbacks.end(); ++it) {
299 it->Run(record);
302 callbacks_.erase(page_url);
305 // BookmarkModelObserver methods.
307 void BookmarkImageService::BookmarkNodeRemoved(
308 BookmarkModel* model,
309 const BookmarkNode* parent,
310 int old_index,
311 const BookmarkNode* node,
312 const std::set<GURL>& removed_urls) {
313 DCHECK(CalledOnValidThread());
314 for (std::set<GURL>::const_iterator iter = removed_urls.begin();
315 iter != removed_urls.end();
316 ++iter) {
317 RemoveImageForUrl(*iter);
321 void BookmarkImageService::BookmarkModelLoaded(BookmarkModel* model,
322 bool ids_reassigned) {
325 void BookmarkImageService::BookmarkNodeMoved(BookmarkModel* model,
326 const BookmarkNode* old_parent,
327 int old_index,
328 const BookmarkNode* new_parent,
329 int new_index) {
332 void BookmarkImageService::BookmarkNodeAdded(BookmarkModel* model,
333 const BookmarkNode* parent,
334 int index) {
337 void BookmarkImageService::OnWillChangeBookmarkNode(BookmarkModel* model,
338 const BookmarkNode* node) {
339 DCHECK(CalledOnValidThread());
340 if (node->is_url())
341 previous_url_ = node->url();
344 void BookmarkImageService::BookmarkNodeChanged(BookmarkModel* model,
345 const BookmarkNode* node) {
346 DCHECK(CalledOnValidThread());
347 if (node->is_url() && previous_url_ != node->url())
348 ChangeImageURL(previous_url_, node->url());
351 void BookmarkImageService::BookmarkNodeFaviconChanged(
352 BookmarkModel* model,
353 const BookmarkNode* node) {
356 void BookmarkImageService::BookmarkNodeChildrenReordered(
357 BookmarkModel* model,
358 const BookmarkNode* node) {
361 void BookmarkImageService::BookmarkAllUserNodesRemoved(
362 BookmarkModel* model,
363 const std::set<GURL>& removed_urls) {
364 ClearAll();
367 } // namespace enhanced_bookmarks