Android Chromoting: Remove exit-fullscreen button.
[chromium-blink-merge.git] / components / enhanced_bookmarks / bookmark_image_service.cc
blobfb3d688ea3543342a446bc16072efc4c2e67f5b4
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;
19 using bookmarks::BookmarkNode;
21 namespace {
23 const char kSequenceToken[] = "BookmarkImagesSequenceToken";
25 void ConstructPersistentImageStore(PersistentImageStore* store,
26 const base::FilePath& path) {
27 DCHECK(store);
28 new (store) PersistentImageStore(path);
31 void DeleteImageStore(ImageStore* store) {
32 DCHECK(store);
33 delete store;
36 void RetrieveImageFromStoreRelay(
37 ImageStore* store,
38 const GURL& page_url,
39 enhanced_bookmarks::BookmarkImageService::ImageCallback callback,
40 scoped_refptr<base::SingleThreadTaskRunner> origin_loop) {
41 origin_loop->PostTask(FROM_HERE, base::Bind(callback, store->Get(page_url)));
44 } // namespace
46 namespace enhanced_bookmarks {
47 BookmarkImageService::BookmarkImageService(
48 scoped_ptr<ImageStore> store,
49 EnhancedBookmarkModel* enhanced_bookmark_model,
50 scoped_refptr<base::SequencedWorkerPool> pool)
51 : enhanced_bookmark_model_(enhanced_bookmark_model),
52 store_(store.Pass()),
53 pool_(pool) {
54 DCHECK(CalledOnValidThread());
55 enhanced_bookmark_model_->bookmark_model()->AddObserver(this);
58 BookmarkImageService::BookmarkImageService(
59 const base::FilePath& path,
60 EnhancedBookmarkModel* enhanced_bookmark_model,
61 scoped_refptr<base::SequencedWorkerPool> pool)
62 : enhanced_bookmark_model_(enhanced_bookmark_model), pool_(pool) {
63 DCHECK(CalledOnValidThread());
64 // PersistentImageStore has to be constructed in the thread it will be used,
65 // so we are posting the construction to the thread. However, we first
66 // allocate memory and keep here. The reason is that, before
67 // PersistentImageStore construction is done, it's possible that
68 // another member function, that posts store_ to the thread, is called.
69 // Although the construction might not be finished yet, we still want to post
70 // the task since it's guaranteed to be constructed by the time it is used, by
71 // the sequential thread task pool.
73 // Other alternatives:
74 // - Using a lock or WaitableEvent for PersistentImageStore construction.
75 // But waiting on UI thread is discouraged.
76 // - Posting the current BookmarkImageService instance instead of store_.
77 // But this will require using a weak pointer and can potentially block
78 // destroying BookmarkImageService.
79 PersistentImageStore* store =
80 (PersistentImageStore*)::operator new(sizeof(PersistentImageStore));
81 store_.reset(store);
82 pool_->PostNamedSequencedWorkerTask(
83 kSequenceToken,
84 FROM_HERE,
85 base::Bind(&ConstructPersistentImageStore, store, path));
88 BookmarkImageService::~BookmarkImageService() {
89 DCHECK(CalledOnValidThread());
90 pool_->PostNamedSequencedWorkerTask(
91 kSequenceToken,
92 FROM_HERE,
93 base::Bind(&DeleteImageStore, store_.release()));
96 void BookmarkImageService::Shutdown() {
97 DCHECK(CalledOnValidThread());
98 enhanced_bookmark_model_->bookmark_model()->RemoveObserver(this);
99 enhanced_bookmark_model_ = NULL;
102 void BookmarkImageService::SalientImageForUrl(const GURL& page_url,
103 ImageCallback callback) {
104 DCHECK(CalledOnValidThread());
105 SalientImageForUrl(page_url, true, callback);
108 void BookmarkImageService::RetrieveImageFromStore(const GURL& page_url,
109 ImageCallback callback) {
110 DCHECK(CalledOnValidThread());
111 pool_->PostSequencedWorkerTaskWithShutdownBehavior(
112 pool_->GetNamedSequenceToken(kSequenceToken),
113 FROM_HERE,
114 base::Bind(&RetrieveImageFromStoreRelay,
115 base::Unretained(store_.get()),
116 page_url,
117 callback,
118 base::ThreadTaskRunnerHandle::Get()),
119 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
122 void BookmarkImageService::RetrieveSalientImageForPageUrl(
123 const GURL& page_url) {
124 DCHECK(CalledOnValidThread());
125 if (IsPageUrlInProgress(page_url))
126 return; // A request for this URL is already in progress.
128 in_progress_page_urls_.insert(page_url);
130 const BookmarkNode* bookmark =
131 enhanced_bookmark_model_->bookmark_model()
132 ->GetMostRecentlyAddedUserNodeForURL(page_url);
133 GURL image_url;
134 if (bookmark) {
135 int width;
136 int height;
137 enhanced_bookmark_model_->GetThumbnailImage(
138 bookmark, &image_url, &width, &height);
141 RetrieveSalientImage(
142 page_url,
143 image_url,
145 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
146 false);
149 void BookmarkImageService::FetchCallback(const GURL& page_url,
150 ImageCallback original_callback,
151 const ImageRecord& record) {
152 DCHECK(CalledOnValidThread());
153 if (!record.image.IsEmpty() || !record.url.is_empty()) {
154 // Either the record was in the store or there is no image in the store, but
155 // an URL for a record is present, indicating that a previous attempt to
156 // download the image failed. Just return the record.
157 original_callback.Run(record);
158 } else {
159 // There is no record in the store, and no previous attempts to retrieve
160 // one. Start a request to retrieve a salient image if there is an image
161 // url set on a bookmark, and then enqueue the request for the record to
162 // be triggered when the retrieval is finished.
163 RetrieveSalientImageForPageUrl(page_url);
164 SalientImageForUrl(page_url, false, original_callback);
168 void BookmarkImageService::SalientImageForUrl(const GURL& page_url,
169 bool fetch_from_web,
170 ImageCallback callback) {
171 DCHECK(CalledOnValidThread());
173 // If the request is done while the image is currently being retrieved, just
174 // store the appropriate callbacks to call once the image is retrieved.
175 if (IsPageUrlInProgress(page_url)) {
176 callbacks_[page_url].push_back(callback);
177 return;
180 if (!fetch_from_web) {
181 RetrieveImageFromStore(page_url, callback);
182 } else {
183 RetrieveImageFromStore(page_url,
184 base::Bind(&BookmarkImageService::FetchCallback,
185 base::Unretained(this),
186 page_url,
187 callback));
191 void BookmarkImageService::ProcessNewImage(const GURL& page_url,
192 bool update_bookmarks,
193 const GURL& image_url,
194 const gfx::Image& image) {
195 DCHECK(CalledOnValidThread());
196 PostTaskToStoreImage(image, image_url, page_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 ImageRecord BookmarkImageService::ResizeAndStoreImage(const gfx::Image& image,
216 const GURL& image_url,
217 const GURL& page_url) {
218 gfx::Image resized_image = ResizeImage(image);
219 ImageRecord image_info(resized_image, image_url, SK_ColorBLACK);
220 if (!resized_image.IsEmpty()) {
221 image_info.dominant_color = DominantColorForImage(resized_image);
222 // TODO(lpromero): this should be saved all the time, even when there is an
223 // empty image. http://crbug.com/451450
224 pool_->PostNamedSequencedWorkerTask(
225 kSequenceToken, FROM_HERE,
226 base::Bind(&ImageStore::Insert, base::Unretained(store_.get()),
227 page_url, image_info));
229 return image_info;
232 void BookmarkImageService::PostTaskToStoreImage(const gfx::Image& image,
233 const GURL& image_url,
234 const GURL& page_url) {
235 DCHECK(CalledOnValidThread());
237 base::Callback<ImageRecord(void)> task =
238 base::Bind(&BookmarkImageService::ResizeAndStoreImage,
239 base::Unretained(this), image, image_url, page_url);
240 base::Callback<void(const ImageRecord&)> reply =
241 base::Bind(&BookmarkImageService::OnStoreImagePosted,
242 base::Unretained(this), page_url);
244 base::PostTaskAndReplyWithResult(pool_.get(), FROM_HERE, task, reply);
247 void BookmarkImageService::OnStoreImagePosted(const GURL& page_url,
248 const ImageRecord& image) {
249 DCHECK(CalledOnValidThread());
250 in_progress_page_urls_.erase(page_url);
251 ProcessRequests(page_url, image);
254 void BookmarkImageService::RemoveImageForUrl(const GURL& page_url) {
255 DCHECK(CalledOnValidThread());
256 pool_->PostNamedSequencedWorkerTask(
257 kSequenceToken,
258 FROM_HERE,
259 base::Bind(&ImageStore::Erase, base::Unretained(store_.get()), page_url));
260 in_progress_page_urls_.erase(page_url);
261 ProcessRequests(page_url, ImageRecord());
264 void BookmarkImageService::ChangeImageURL(const GURL& from, const GURL& to) {
265 DCHECK(CalledOnValidThread());
266 pool_->PostNamedSequencedWorkerTask(kSequenceToken,
267 FROM_HERE,
268 base::Bind(&ImageStore::ChangeImageURL,
269 base::Unretained(store_.get()),
270 from,
271 to));
272 in_progress_page_urls_.erase(from);
273 ProcessRequests(from, ImageRecord());
276 void BookmarkImageService::ClearAll() {
277 DCHECK(CalledOnValidThread());
278 // Clears and executes callbacks.
279 pool_->PostNamedSequencedWorkerTask(
280 kSequenceToken,
281 FROM_HERE,
282 base::Bind(&ImageStore::ClearAll, base::Unretained(store_.get())));
284 for (std::map<const GURL, std::vector<ImageCallback>>::const_iterator it =
285 callbacks_.begin();
286 it != callbacks_.end(); ++it) {
287 ProcessRequests(it->first, ImageRecord());
290 in_progress_page_urls_.erase(in_progress_page_urls_.begin(),
291 in_progress_page_urls_.end());
294 void BookmarkImageService::ProcessRequests(const GURL& page_url,
295 const ImageRecord& record) {
296 DCHECK(CalledOnValidThread());
298 std::vector<ImageCallback> callbacks = callbacks_[page_url];
299 for (std::vector<ImageCallback>::const_iterator it = callbacks.begin();
300 it != callbacks.end(); ++it) {
301 it->Run(record);
304 callbacks_.erase(page_url);
307 // BookmarkModelObserver methods.
309 void BookmarkImageService::BookmarkNodeRemoved(
310 BookmarkModel* model,
311 const BookmarkNode* parent,
312 int old_index,
313 const BookmarkNode* node,
314 const std::set<GURL>& removed_urls) {
315 DCHECK(CalledOnValidThread());
316 for (std::set<GURL>::const_iterator iter = removed_urls.begin();
317 iter != removed_urls.end();
318 ++iter) {
319 RemoveImageForUrl(*iter);
323 void BookmarkImageService::BookmarkModelLoaded(BookmarkModel* model,
324 bool ids_reassigned) {
327 void BookmarkImageService::BookmarkNodeMoved(BookmarkModel* model,
328 const BookmarkNode* old_parent,
329 int old_index,
330 const BookmarkNode* new_parent,
331 int new_index) {
334 void BookmarkImageService::BookmarkNodeAdded(BookmarkModel* model,
335 const BookmarkNode* parent,
336 int index) {
339 void BookmarkImageService::OnWillChangeBookmarkNode(BookmarkModel* model,
340 const BookmarkNode* node) {
341 DCHECK(CalledOnValidThread());
342 if (node->is_url())
343 previous_url_ = node->url();
346 void BookmarkImageService::BookmarkNodeChanged(BookmarkModel* model,
347 const BookmarkNode* node) {
348 DCHECK(CalledOnValidThread());
349 if (node->is_url() && previous_url_ != node->url())
350 ChangeImageURL(previous_url_, node->url());
353 void BookmarkImageService::BookmarkNodeFaviconChanged(
354 BookmarkModel* model,
355 const BookmarkNode* node) {
358 void BookmarkImageService::BookmarkNodeChildrenReordered(
359 BookmarkModel* model,
360 const BookmarkNode* node) {
363 void BookmarkImageService::BookmarkAllUserNodesRemoved(
364 BookmarkModel* model,
365 const std::set<GURL>& removed_urls) {
366 ClearAll();
369 } // namespace enhanced_bookmarks