OLD | NEW |
---|---|
(Empty) | |
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" | |
5 | |
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_utils.h" | |
12 #include "components/enhanced_bookmarks/metadata_accessor.h" | |
13 #include "components/enhanced_bookmarks/persistent_image_store.h" | |
14 | |
15 namespace { | |
16 | |
17 const char kSequenceToken[] = "BookmarkImagesSequenceToken"; | |
18 | |
19 void ConstructPersistentImageStore(PersistentImageStore* store, | |
20 const base::FilePath& path) { | |
21 DCHECK(store); | |
22 new (store) PersistentImageStore(path); | |
23 } | |
24 | |
25 void DeleteImageStore(ImageStore* store) { | |
26 DCHECK(store); | |
27 delete store; | |
28 } | |
29 | |
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)); | |
38 } | |
39 | |
40 } // namespace | |
41 | |
42 namespace enhanced_bookmarks { | |
43 BookmarkImageService::BookmarkImageService( | |
44 scoped_ptr<ImageStore> store, | |
45 BookmarkModel* bookmark_model, | |
46 scoped_refptr<base::SequencedWorkerPool> pool) | |
47 : bookmark_model_(bookmark_model), store_(store.Pass()), pool_(pool) { | |
48 DCHECK(CalledOnValidThread()); | |
49 bookmark_model_->AddObserver(this); | |
50 } | |
51 | |
52 BookmarkImageService::BookmarkImageService( | |
53 const base::FilePath& path, | |
54 BookmarkModel* bookmark_model, | |
55 scoped_refptr<base::SequencedWorkerPool> pool) | |
56 : bookmark_model_(bookmark_model), pool_(pool) { | |
57 DCHECK(CalledOnValidThread()); | |
58 // PersistentImageStore has to be constructed in the thread it will be used, | |
59 // so we are posting the construction to the thread. However, we first | |
60 // allocate memory and keep here. The reason is that, before | |
61 // PersistentImageStore construction is done, it's possible that | |
62 // another member function, that posts store_ to the thread, is called. | |
63 // Although the construction might not be finished yet, we still want to post | |
64 // the task since it's guaranteed to be constructed by the time it is used, by | |
65 // the sequential thread task pool. | |
66 // | |
67 // Other alternatives: | |
68 // - Using a lock or WaitableEvent for PersistentImageStore construction. | |
69 // But waiting on UI thread is discouraged. | |
70 // - Posting the current BookmarkImageService instance instead of store_. | |
71 // But this will require using a weak pointer and can potentially block | |
72 // destroying BookmarkImageService. | |
73 PersistentImageStore* store = | |
74 (PersistentImageStore*)::operator new(sizeof(PersistentImageStore)); | |
75 store_.reset(store); | |
76 pool_->PostNamedSequencedWorkerTask( | |
77 kSequenceToken, | |
78 FROM_HERE, | |
79 base::Bind(&ConstructPersistentImageStore, store, path)); | |
80 } | |
81 | |
82 BookmarkImageService::~BookmarkImageService() { | |
83 DCHECK(CalledOnValidThread()); | |
84 bookmark_model_->RemoveObserver(this); | |
85 pool_->PostNamedSequencedWorkerTask( | |
86 kSequenceToken, | |
87 FROM_HERE, | |
88 base::Bind(&DeleteImageStore, store_.release())); | |
89 } | |
90 | |
91 void BookmarkImageService::SalientImageForUrl(const GURL& page_url, | |
92 Callback callback) { | |
93 DCHECK(CalledOnValidThread()); | |
94 SalientImageForUrl(page_url, true, callback); | |
95 } | |
96 | |
97 void BookmarkImageService::RetrieveImageFromStore( | |
98 const GURL& page_url, | |
99 BookmarkImageService::Callback callback) { | |
100 DCHECK(CalledOnValidThread()); | |
101 pool_->PostSequencedWorkerTaskWithShutdownBehavior( | |
102 pool_->GetNamedSequenceToken(kSequenceToken), | |
103 FROM_HERE, | |
104 base::Bind(&RetrieveImageFromStoreRelay, | |
105 base::Unretained(store_.get()), | |
106 page_url, | |
107 callback, | |
108 base::ThreadTaskRunnerHandle::Get()), | |
109 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
110 } | |
111 | |
112 void BookmarkImageService::RetrieveSalientImageForPageUrl( | |
113 const GURL& page_url) { | |
114 DCHECK(CalledOnValidThread()); | |
115 if (IsPageUrlInProgress(page_url)) | |
116 return; // A request for this URL is already in progress. | |
117 | |
118 in_progress_page_urls_.insert(page_url); | |
119 | |
120 const BookmarkNode* bookmark = | |
121 bookmark_model_->GetMostRecentlyAddedUserNodeForURL(page_url); | |
122 GURL image_url; | |
123 if (bookmark) { | |
124 int width; | |
125 int height; | |
126 enhanced_bookmarks::ThumbnailImageFromBookmark( | |
127 bookmark, &image_url, &width, &height); | |
128 } | |
129 | |
130 RetrieveSalientImage( | |
131 page_url, | |
132 image_url, | |
133 "", | |
134 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, | |
wtc
2014/08/28 23:45:50
If we're passing a hardcoded value here, does Retr
noyau (Ping after 24h)
2014/08/29 08:44:01
RetrieveSalientImage() is protected and also calle
| |
135 false); | |
136 } | |
137 | |
138 void BookmarkImageService::FetchCallback(const GURL& page_url, | |
139 Callback original_callback, | |
140 const gfx::Image& image, | |
141 const GURL& image_url) { | |
142 DCHECK(CalledOnValidThread()); | |
143 if (!image.IsEmpty() || !image_url.is_empty()) { | |
144 // Either the image was in the store or there is no image in the store, but | |
145 // an URL for an image is present, indicating that a previous attempt to | |
146 // download the image failed. Just return the image. | |
147 original_callback.Run(image, image_url); | |
148 } else { | |
149 // There is no image in the store, and no previous attempts to retrieve | |
150 // one. Start a request to retrieve a salient image if there is an image | |
151 // url set on a bookmark, and then enqueue the request for the image to | |
152 // be triggered when the retrieval is finished. | |
153 RetrieveSalientImageForPageUrl(page_url); | |
154 SalientImageForUrl(page_url, false, original_callback); | |
155 } | |
156 } | |
157 | |
158 void BookmarkImageService::SalientImageForUrl(const GURL& page_url, | |
159 bool fetch_from_bookmark, | |
160 Callback callback) { | |
161 DCHECK(CalledOnValidThread()); | |
162 | |
163 // If the request is done while the image is currently being retrieved, just | |
164 // store the appropriate callbacks to call once the image is retrieved. | |
165 if (IsPageUrlInProgress(page_url)) { | |
166 callbacks_[page_url].push_back(callback); | |
167 return; | |
168 } | |
169 | |
170 if (!fetch_from_bookmark) { | |
171 RetrieveImageFromStore(page_url, callback); | |
172 } else { | |
173 RetrieveImageFromStore(page_url, | |
174 base::Bind(&BookmarkImageService::FetchCallback, | |
175 base::Unretained(this), | |
176 page_url, | |
177 callback)); | |
178 } | |
179 } | |
180 | |
181 void BookmarkImageService::ProcessNewImage(const GURL& page_url, | |
182 bool update_bookmarks, | |
183 const gfx::Image& image, | |
184 const GURL& image_url) { | |
185 DCHECK(CalledOnValidThread()); | |
186 StoreImage(image, image_url, page_url); | |
187 in_progress_page_urls_.erase(page_url); | |
188 ProcessRequests(page_url, image, image_url); | |
189 if (update_bookmarks && image_url.is_valid()) { | |
190 const BookmarkNode* bookmark = | |
191 bookmark_model_->GetMostRecentlyAddedUserNodeForURL(page_url); | |
192 if (bookmark) { | |
193 const gfx::Size& size = image.Size(); | |
194 bool result = enhanced_bookmarks::SetOriginalImageForBookmark( | |
195 bookmark_model_, bookmark, image_url, size.width(), size.height()); | |
196 DCHECK(result); | |
197 } | |
198 } | |
199 } | |
200 | |
201 bool BookmarkImageService::IsPageUrlInProgress(const GURL& page_url) { | |
202 DCHECK(CalledOnValidThread()); | |
203 return in_progress_page_urls_.find(page_url) != in_progress_page_urls_.end(); | |
204 } | |
205 | |
206 void BookmarkImageService::StoreImage(const gfx::Image& image, | |
207 const GURL& image_url, | |
208 const GURL& page_url) { | |
209 DCHECK(CalledOnValidThread()); | |
210 if (!image.IsEmpty()) { | |
211 pool_->PostNamedSequencedWorkerTask( | |
212 kSequenceToken, | |
213 FROM_HERE, | |
214 base::Bind(&ImageStore::Insert, | |
215 base::Unretained(store_.get()), | |
216 page_url, | |
217 image_url, | |
218 image)); | |
219 } | |
220 } | |
221 | |
222 void BookmarkImageService::RemoveImageForUrl(const GURL& page_url) { | |
223 DCHECK(CalledOnValidThread()); | |
224 pool_->PostNamedSequencedWorkerTask( | |
225 kSequenceToken, | |
226 FROM_HERE, | |
227 base::Bind(&ImageStore::Erase, base::Unretained(store_.get()), page_url)); | |
228 in_progress_page_urls_.erase(page_url); | |
229 ProcessRequests(page_url, gfx::Image(), GURL()); | |
230 } | |
231 | |
232 void BookmarkImageService::ChangeImageURL(const GURL& from, const GURL& to) { | |
233 DCHECK(CalledOnValidThread()); | |
234 pool_->PostNamedSequencedWorkerTask(kSequenceToken, | |
235 FROM_HERE, | |
236 base::Bind(&ImageStore::ChangeImageURL, | |
237 base::Unretained(store_.get()), | |
238 from, | |
239 to)); | |
240 in_progress_page_urls_.erase(from); | |
241 ProcessRequests(from, gfx::Image(), GURL()); | |
242 } | |
243 | |
244 void BookmarkImageService::ClearAll() { | |
245 DCHECK(CalledOnValidThread()); | |
246 // Clears and executes callbacks. | |
247 pool_->PostNamedSequencedWorkerTask( | |
248 kSequenceToken, | |
249 FROM_HERE, | |
250 base::Bind(&ImageStore::ClearAll, base::Unretained(store_.get()))); | |
251 | |
252 for (std::map<const GURL, std::vector<Callback> >::const_iterator it = | |
253 callbacks_.begin(); | |
254 it != callbacks_.end(); | |
255 ++it) { | |
256 ProcessRequests(it->first, gfx::Image(), GURL()); | |
257 } | |
258 | |
259 in_progress_page_urls_.erase(in_progress_page_urls_.begin(), | |
260 in_progress_page_urls_.end()); | |
261 } | |
262 | |
263 void BookmarkImageService::ProcessRequests(const GURL& page_url, | |
264 const gfx::Image& image, | |
265 const GURL& image_url) { | |
266 DCHECK(CalledOnValidThread()); | |
267 | |
268 std::vector<Callback> callbacks = callbacks_[page_url]; | |
269 for (std::vector<Callback>::const_iterator it = callbacks.begin(); | |
270 it != callbacks.end(); | |
271 ++it) { | |
272 it->Run(image, image_url); | |
273 } | |
274 | |
275 callbacks_.erase(page_url); | |
276 } | |
277 | |
278 // BookmarkModelObserver methods. | |
279 | |
280 void BookmarkImageService::BookmarkNodeRemoved( | |
281 BookmarkModel* model, | |
282 const BookmarkNode* parent, | |
283 int old_index, | |
284 const BookmarkNode* node, | |
285 const std::set<GURL>& removed_urls) { | |
286 DCHECK(CalledOnValidThread()); | |
287 for (std::set<GURL>::const_iterator iter = removed_urls.begin(); | |
288 iter != removed_urls.end(); | |
289 ++iter) { | |
290 RemoveImageForUrl(*iter); | |
291 } | |
292 } | |
293 | |
294 void BookmarkImageService::BookmarkModelLoaded(BookmarkModel* model, | |
295 bool ids_reassigned) { | |
296 } | |
297 | |
298 void BookmarkImageService::BookmarkNodeMoved(BookmarkModel* model, | |
299 const BookmarkNode* old_parent, | |
300 int old_index, | |
301 const BookmarkNode* new_parent, | |
302 int new_index) { | |
303 } | |
304 | |
305 void BookmarkImageService::BookmarkNodeAdded(BookmarkModel* model, | |
306 const BookmarkNode* parent, | |
307 int index) { | |
308 } | |
309 | |
310 void BookmarkImageService::OnWillChangeBookmarkNode(BookmarkModel* model, | |
311 const BookmarkNode* node) { | |
312 DCHECK(CalledOnValidThread()); | |
313 if (node->is_url()) | |
314 previous_url_ = node->url(); | |
315 } | |
316 | |
317 void BookmarkImageService::BookmarkNodeChanged(BookmarkModel* model, | |
318 const BookmarkNode* node) { | |
319 DCHECK(CalledOnValidThread()); | |
320 if (node->is_url() && previous_url_ != node->url()) | |
321 ChangeImageURL(previous_url_, node->url()); | |
322 } | |
323 | |
324 void BookmarkImageService::BookmarkNodeFaviconChanged( | |
325 BookmarkModel* model, | |
326 const BookmarkNode* node) { | |
327 } | |
328 | |
329 void BookmarkImageService::BookmarkNodeChildrenReordered( | |
330 BookmarkModel* model, | |
331 const BookmarkNode* node) { | |
332 } | |
333 | |
334 void BookmarkImageService::BookmarkAllUserNodesRemoved( | |
335 BookmarkModel* model, | |
336 const std::set<GURL>& removed_urls) { | |
337 ClearAll(); | |
338 } | |
339 | |
340 } // namespace enhanced_bookmarks | |
OLD | NEW |