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.
5 #include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h"
7 #include "ash/shelf/shelf_constants.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"
18 const int kMaxBitmapSize
= 256;
20 ////////////////////////////////////////////////////////////////////////////////
21 // FaviconRawBitmapHandler fetchs all bitmaps with the 'icon' (or 'shortcut
23 // link tag, storing the one that best matches ash::kShelfSize.
24 // These icon bitmaps are not resized and are not cached beyond the lifetime
25 // of the class. Bitmaps larger than kMaxBitmapSize are ignored.
27 class FaviconRawBitmapHandler
: public content::WebContentsObserver
{
29 FaviconRawBitmapHandler(content::WebContents
* web_contents
,
30 LauncherFaviconLoader::Delegate
* delegate
)
31 : content::WebContentsObserver(web_contents
),
33 weak_ptr_factory_(this) {}
35 ~FaviconRawBitmapHandler() override
{}
37 const SkBitmap
& bitmap() const { return bitmap_
; }
39 bool HasPendingDownloads() const;
41 // content::WebContentObserver implementation.
42 void DidUpdateFaviconURL(
43 const std::vector
<content::FaviconURL
>& candidates
) override
;
46 void DidDownloadFavicon(
49 const GURL
& image_url
,
50 const std::vector
<SkBitmap
>& bitmaps
,
51 const std::vector
<gfx::Size
>& original_bitmap_sizes
);
53 void AddFavicon(const GURL
& image_url
, const SkBitmap
& new_bitmap
);
55 LauncherFaviconLoader::Delegate
* delegate_
;
57 typedef std::set
<GURL
> UrlSet
;
58 // Map of pending download urls.
59 UrlSet pending_requests_
;
60 // Map of processed urls.
61 UrlSet processed_requests_
;
62 // Current bitmap and source url.
66 base::WeakPtrFactory
<FaviconRawBitmapHandler
> weak_ptr_factory_
;
68 DISALLOW_COPY_AND_ASSIGN(FaviconRawBitmapHandler
);
71 void FaviconRawBitmapHandler::DidUpdateFaviconURL(
72 const std::vector
<content::FaviconURL
>& candidates
) {
73 // This function receives a complete list of faviocn urls for the page.
74 // It may get called multiple times with the same list, and will also get
75 // called any time an item is added or removed. As such, we track processed
76 // and pending urls, but only until they are removed from the list.
77 UrlSet new_pending
, new_processed
;
78 // Create a map of valid favicon urls.
80 std::vector
<content::FaviconURL
>::const_iterator iter
;
81 for (iter
= candidates
.begin(); iter
!= candidates
.end(); ++iter
) {
82 if (iter
->icon_type
!= content::FaviconURL::FAVICON
)
84 const GURL
& url
= iter
->icon_url
;
87 // Preserve matching pending requests amd processed requests.
88 if (pending_requests_
.find(url
) != pending_requests_
.end())
89 new_pending
.insert(url
);
90 if (processed_requests_
.find(url
) != processed_requests_
.end())
91 new_processed
.insert(url
);
93 pending_requests_
= new_pending
;
94 processed_requests_
= new_processed
;
95 // Reset bitmap_ if no longer valid (i.e. not in the list of urls).
96 if (urls
.find(bitmap_url_
) == urls
.end()) {
100 // Request any new urls.
101 for (std::set
<GURL
>::iterator iter
= urls
.begin();
102 iter
!= urls
.end(); ++iter
) {
103 if (processed_requests_
.find(*iter
) != processed_requests_
.end())
104 continue; // Skip already processed downloads.
105 if (pending_requests_
.find(*iter
) != pending_requests_
.end())
106 continue; // Skip already pending downloads.
107 pending_requests_
.insert(*iter
);
108 web_contents()->DownloadImage(
110 true, // is a favicon
111 0, // no maximum size
112 false, // normal cache policy
113 base::Bind(&FaviconRawBitmapHandler::DidDownloadFavicon
,
114 weak_ptr_factory_
.GetWeakPtr()));
118 bool FaviconRawBitmapHandler::HasPendingDownloads() const {
119 return !pending_requests_
.empty();
122 void FaviconRawBitmapHandler::DidDownloadFavicon(
124 int http_status_code
,
125 const GURL
& image_url
,
126 const std::vector
<SkBitmap
>& bitmaps
,
127 const std::vector
<gfx::Size
>& original_bitmap_sizes
) {
128 UrlSet::iterator iter
= pending_requests_
.find(image_url
);
129 if (iter
== pending_requests_
.end()) {
130 // Updates are received for all downloads; ignore unrequested urls.
133 pending_requests_
.erase(iter
);
135 // Favicon bitmaps are ordered by decreasing width.
136 if (!bitmaps
.empty())
137 AddFavicon(image_url
, bitmaps
[0]);
140 void FaviconRawBitmapHandler::AddFavicon(const GURL
& image_url
,
141 const SkBitmap
& new_bitmap
) {
142 processed_requests_
.insert(image_url
);
143 if (new_bitmap
.height() > kMaxBitmapSize
||
144 new_bitmap
.width() > kMaxBitmapSize
)
146 if (new_bitmap
.height() < ash::kShelfSize
)
148 if (!bitmap_
.isNull()) {
149 // We want the smallest icon that is large enough.
150 if (new_bitmap
.height() > bitmap_
.height())
153 bitmap_url_
= image_url
;
154 bitmap_
= new_bitmap
;
155 delegate_
->FaviconUpdated();
158 } // namespace internal
160 ////////////////////////////////////////////////////////////////////////////////
162 LauncherFaviconLoader::LauncherFaviconLoader(Delegate
* delegate
,
163 content::WebContents
* web_contents
)
164 : web_contents_(web_contents
) {
165 favicon_handler_
.reset(
166 new internal::FaviconRawBitmapHandler(web_contents
, delegate
));
169 LauncherFaviconLoader::~LauncherFaviconLoader() {
172 SkBitmap
LauncherFaviconLoader::GetFavicon() const {
173 return favicon_handler_
->bitmap();
176 bool LauncherFaviconLoader::HasPendingDownloads() const {
177 return favicon_handler_
->HasPendingDownloads();