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#ifndef COMPONENTS_ENHANCED_BOOKMARKS_BOOKMARK_IMAGE_SERVICE_H_
5#define COMPONENTS_ENHANCED_BOOKMARKS_BOOKMARK_IMAGE_SERVICE_H_
6
7#include "base/files/file_path.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/memory/singleton.h"
10#include "components/bookmarks/browser/bookmark_model_observer.h"
11#include "components/enhanced_bookmarks/image_store.h"
12#include "components/keyed_service/core/keyed_service.h"
13#include "net/url_request/url_request.h"
14#include "url/gurl.h"
15
16namespace base {
17class SingleThreadTaskRunner;
18}
19class BookmarkNode;
20
21namespace enhanced_bookmarks {
22
23class EnhancedBookmarkModel;
24
25// The BookmarkImageService stores salient images for bookmarks.
26class BookmarkImageService : public KeyedService,
27                             public BookmarkModelObserver,
28                             public base::NonThreadSafe {
29 public:
30  BookmarkImageService(const base::FilePath& path,
31                       EnhancedBookmarkModel* enhanced_bookmark_model,
32                       scoped_refptr<base::SequencedWorkerPool> pool);
33  BookmarkImageService(scoped_ptr<ImageStore> store,
34                       EnhancedBookmarkModel* enhanced_bookmark_model,
35                       scoped_refptr<base::SequencedWorkerPool> pool);
36
37  virtual ~BookmarkImageService();
38
39  typedef base::Callback<void(const gfx::Image&, const GURL& url)> Callback;
40
41  // KeyedService:
42  virtual void Shutdown() OVERRIDE;
43
44  // Returns a salient image for a URL. This may trigger a network request for
45  // the image if the image was not retrieved before and if a bookmark node has
46  // a URL for this salient image available.  The image (which may be empty) is
47  // sent via the callback. The callback may be called synchronously if it is
48  // possible. The callback is always triggered on the main thread.
49  void SalientImageForUrl(const GURL& page_url, Callback callback);
50
51  // BookmarkModelObserver methods.
52  virtual void BookmarkNodeRemoved(BookmarkModel* model,
53                                   const BookmarkNode* parent,
54                                   int old_index,
55                                   const BookmarkNode* node,
56                                   const std::set<GURL>& removed_urls) OVERRIDE;
57  virtual void BookmarkModelLoaded(BookmarkModel* model,
58                                   bool ids_reassigned) OVERRIDE;
59  virtual void BookmarkNodeMoved(BookmarkModel* model,
60                                 const BookmarkNode* old_parent,
61                                 int old_index,
62                                 const BookmarkNode* new_parent,
63                                 int new_index) OVERRIDE;
64  virtual void BookmarkNodeAdded(BookmarkModel* model,
65                                 const BookmarkNode* parent,
66                                 int index) OVERRIDE;
67  virtual void OnWillChangeBookmarkNode(BookmarkModel* model,
68                                        const BookmarkNode* node) OVERRIDE;
69  virtual void BookmarkNodeChanged(BookmarkModel* model,
70                                   const BookmarkNode* node) OVERRIDE;
71  virtual void BookmarkNodeFaviconChanged(BookmarkModel* model,
72                                          const BookmarkNode* node) OVERRIDE;
73  virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
74                                             const BookmarkNode* node) OVERRIDE;
75  virtual void BookmarkAllUserNodesRemoved(
76      BookmarkModel* model,
77      const std::set<GURL>& removed_urls) OVERRIDE;
78
79 protected:
80  // Returns true if the image for the page_url is currently being fetched.
81  bool IsPageUrlInProgress(const GURL& page_url);
82
83  // Once an image has been retrieved, store the image and notify all the
84  // consumers that were waiting on it.
85  void ProcessNewImage(const GURL& page_url,
86                       bool update_bookmarks,
87                       const gfx::Image& image,
88                       const GURL& image_url);
89
90  // Sets a new image for a bookmark. If the given page_url is bookmarked and
91  // the image is retrieved from the image_url, then the image is locally
92  // stored. If update_bookmark is true the URL is also added to the bookmark.
93  // This is the only method subclass needs to implement.
94  virtual void RetrieveSalientImage(
95      const GURL& page_url,
96      const GURL& image_url,
97      const std::string& referrer,
98      net::URLRequest::ReferrerPolicy referrer_policy,
99      bool update_bookmark) = 0;
100
101  // Retrieves a salient image for a given page_url by downloading the image in
102  // one of the bookmark.
103  virtual void RetrieveSalientImageForPageUrl(const GURL& page_url);
104
105  // PageUrls currently in the progress of being retrieved.
106  std::set<GURL> in_progress_page_urls_;
107
108  // Cached pointer to the bookmark model.
109  EnhancedBookmarkModel* enhanced_bookmark_model_;
110
111 private:
112  // Same as SalientImageForUrl(const GURL&, Callback) but can prevent the
113  // network request if fetch_from_bookmark is false.
114  void SalientImageForUrl(const GURL& page_url,
115                          bool fetch_from_bookmark,
116                          Callback stack_callback);
117
118  // Processes the requests that have been waiting on an image.
119  void ProcessRequests(const GURL& page_url,
120                       const gfx::Image& image,
121                       const GURL& image_url);
122
123  // Once an image is retrieved this method updates the store with it.
124  void StoreImage(const gfx::Image& image,
125                  const GURL& image_url,
126                  const GURL& page_url);
127
128  // Called when retrieving an image from the image store fails, to trigger
129  // retrieving the image from the url stored in the bookmark (if any).
130  void FetchCallback(const GURL& page_url,
131                     Callback original_callback,
132                     const gfx::Image& image,
133                     const GURL& image_url);
134
135  // Remove the image stored for this bookmark (if it exists). Called when a
136  // bookmark is deleted.
137  void RemoveImageForUrl(const GURL& url);
138
139  // Moves an image from one url to another.
140  void ChangeImageURL(const GURL& from, const GURL& to);
141
142  // Removes all the entries in the image service.
143  void ClearAll();
144
145  // The image store can only be accessed from the blocking pool.
146  // RetrieveImageFromStore starts a request to retrieve the image and returns
147  // the result via a callback. RetrieveImageFromStore must be called on the
148  // main thread and the callback will be called on the main thread as well. The
149  // callback will always be called. The returned image is nil if the image is
150  // not present in the store.
151  void RetrieveImageFromStore(const GURL& page_url,
152                              BookmarkImageService::Callback callback);
153
154  // Maps a pageUrl to an image.
155  scoped_ptr<ImageStore> store_;
156
157  // All the callbacks waiting for a particular image.
158  std::map<const GURL, std::vector<Callback> > callbacks_;
159
160  // When a bookmark is changed, two messages are received on the
161  // bookmarkModelObserver, one with the old state, one with the new. The url
162  // before the change is saved in this instance variable.
163  GURL previous_url_;
164
165  // The worker pool to enqueue the store requests onto.
166  scoped_refptr<base::SequencedWorkerPool> pool_;
167  DISALLOW_COPY_AND_ASSIGN(BookmarkImageService);
168};
169
170}  // namespace enhanced_bookmarks
171
172#endif  // COMPONENTS_ENHANCED_BOOKMARKS_BOOKMARK_IMAGE_SERVICE_H_
173