- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / launcher / launcher_favicon_loader.cc
1 // Copyright (c) 2012 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
5 #include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h"
6
7 #include "ash/launcher/launcher_types.h"
8 #include "base/logging.h"
9 #include "base/memory/weak_ptr.h"
10 #include "content/public/browser/render_view_host.h"
11 #include "content/public/browser/web_contents.h"
12 #include "content/public/browser/web_contents_observer.h"
13 #include "third_party/skia/include/core/SkBitmap.h"
14 #include "url/gurl.h"
15
16 namespace internal {
17
18 const int kMaxBitmapSize = 256;
19
20 ////////////////////////////////////////////////////////////////////////////////
21 // FaviconBitmapHandler fetchs all bitmaps with the 'icon' (or 'shortcut icon')
22 // link tag, storing the one that best matches ash::kLauncherPreferredSize.
23 // These icon bitmaps are not resized and are not cached beyond the lifetime
24 // of the class. Bitmaps larger than kMaxBitmapSize are ignored.
25
26 class FaviconBitmapHandler : public content::WebContentsObserver {
27  public:
28   FaviconBitmapHandler(content::WebContents* web_contents,
29                        LauncherFaviconLoader::Delegate* delegate)
30       : content::WebContentsObserver(web_contents),
31         delegate_(delegate),
32         web_contents_(web_contents),
33         weak_ptr_factory_(this) {
34   }
35
36   virtual ~FaviconBitmapHandler() {}
37
38   const SkBitmap& bitmap() const { return bitmap_; }
39
40   bool HasPendingDownloads() const;
41
42   // content::WebContentObserver implementation.
43   virtual void DidUpdateFaviconURL(
44     int32 page_id,
45     const std::vector<content::FaviconURL>& candidates) OVERRIDE;
46
47  private:
48   void DidDownloadFavicon(
49       int id,
50       int http_status_code,
51       const GURL& image_url,
52       const std::vector<SkBitmap>& bitmaps,
53       const std::vector<gfx::Size>& original_bitmap_sizes);
54
55   void AddFavicon(const GURL& image_url, const SkBitmap& new_bitmap);
56
57   LauncherFaviconLoader::Delegate* delegate_;
58
59   content::WebContents* web_contents_;
60
61   typedef std::set<GURL> UrlSet;
62   // Map of pending download urls.
63   UrlSet pending_requests_;
64   // Map of processed urls.
65   UrlSet processed_requests_;
66   // Current bitmap and source url.
67   SkBitmap bitmap_;
68   GURL bitmap_url_;
69
70   base::WeakPtrFactory<FaviconBitmapHandler> weak_ptr_factory_;
71
72   DISALLOW_COPY_AND_ASSIGN(FaviconBitmapHandler);
73 };
74
75 void FaviconBitmapHandler::DidUpdateFaviconURL(
76     int32 page_id,
77     const std::vector<content::FaviconURL>& candidates) {
78   // This function receives a complete list of faviocn urls for the page.
79   // It may get called multiple times with the same list, and will also get
80   // called any time an item is added or removed. As such, we track processed
81   // and pending urls, but only until they are removed from the list.
82   UrlSet new_pending, new_processed;
83   // Create a map of valid favicon urls.
84   std::set<GURL> urls;
85   std::vector<content::FaviconURL>::const_iterator iter;
86   for (iter = candidates.begin(); iter != candidates.end(); ++iter) {
87     if (iter->icon_type != content::FaviconURL::FAVICON)
88       continue;
89     const GURL& url = iter->icon_url;
90     if (url.is_valid())
91       urls.insert(url);
92     // Preserve matching pending requests amd processed requests.
93     if (pending_requests_.find(url) != pending_requests_.end())
94       new_pending.insert(url);
95     if (processed_requests_.find(url) != processed_requests_.end())
96       new_processed.insert(url);
97   }
98   pending_requests_ = new_pending;
99   processed_requests_ = new_processed;
100   // Reset bitmap_ if no longer valid (i.e. not in the list of urls).
101   if (urls.find(bitmap_url_) == urls.end()) {
102     bitmap_url_ = GURL();
103     bitmap_.reset();
104   }
105   // Request any new urls.
106   for (std::set<GURL>::iterator iter = urls.begin();
107        iter != urls.end(); ++iter) {
108     if (processed_requests_.find(*iter) != processed_requests_.end())
109       continue;  // Skip already processed downloads.
110     if (pending_requests_.find(*iter) != pending_requests_.end())
111       continue;  // Skip already pending downloads.
112     pending_requests_.insert(*iter);
113     web_contents_->DownloadImage(
114         *iter,
115         true,  // is a favicon
116         0,     // no maximum size
117         base::Bind(&FaviconBitmapHandler::DidDownloadFavicon,
118                    weak_ptr_factory_.GetWeakPtr()));
119   }
120 }
121
122 bool FaviconBitmapHandler::HasPendingDownloads() const {
123   return !pending_requests_.empty();
124 }
125
126 void FaviconBitmapHandler::DidDownloadFavicon(
127     int id,
128     int http_status_code,
129     const GURL& image_url,
130     const std::vector<SkBitmap>& bitmaps,
131     const std::vector<gfx::Size>& original_bitmap_sizes) {
132   UrlSet::iterator iter = pending_requests_.find(image_url);
133   if (iter == pending_requests_.end()) {
134     // Updates are received for all downloads; ignore unrequested urls.
135     return;
136   }
137   pending_requests_.erase(iter);
138
139   // Favicon bitmaps are ordered by decreasing width.
140   if (!bitmaps.empty())
141     AddFavicon(image_url, bitmaps[0]);
142 }
143
144 void FaviconBitmapHandler::AddFavicon(const GURL& image_url,
145                                       const SkBitmap& new_bitmap) {
146   processed_requests_.insert(image_url);
147   if (new_bitmap.height() > kMaxBitmapSize ||
148       new_bitmap.width() > kMaxBitmapSize)
149     return;
150   if (new_bitmap.height() < ash::kLauncherPreferredSize)
151     return;
152   if (!bitmap_.isNull()) {
153     // We want the smallest icon that is large enough.
154     if (new_bitmap.height() > bitmap_.height())
155       return;
156   }
157   bitmap_url_ = image_url;
158   bitmap_ = new_bitmap;
159   delegate_->FaviconUpdated();
160 }
161
162 }  // namespace internal
163
164 ////////////////////////////////////////////////////////////////////////////////
165
166 LauncherFaviconLoader::LauncherFaviconLoader(Delegate* delegate,
167                                              content::WebContents* web_contents)
168     : web_contents_(web_contents) {
169   favicon_handler_.reset(
170       new internal::FaviconBitmapHandler(web_contents, delegate));
171 }
172
173 LauncherFaviconLoader::~LauncherFaviconLoader() {
174 }
175
176 SkBitmap LauncherFaviconLoader::GetFavicon() const {
177   return favicon_handler_->bitmap();
178 }
179
180 bool LauncherFaviconLoader::HasPendingDownloads() const {
181   return favicon_handler_->HasPendingDownloads();
182 }