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 // FaviconBitmapHandler fetchs all bitmaps with the 'icon' (or 'shortcut icon')
22 // link tag, storing the one that best matches ash::kShelfPreferredSize.
23 // These icon bitmaps are not resized and are not cached beyond the lifetime
24 // of the class. Bitmaps larger than kMaxBitmapSize are ignored.
26 class FaviconBitmapHandler
: public content::WebContentsObserver
{
28 FaviconBitmapHandler(content::WebContents
* web_contents
,
29 LauncherFaviconLoader::Delegate
* delegate
)
30 : content::WebContentsObserver(web_contents
),
32 web_contents_(web_contents
),
33 weak_ptr_factory_(this) {
36 virtual ~FaviconBitmapHandler() {}
38 const SkBitmap
& bitmap() const { return bitmap_
; }
40 bool HasPendingDownloads() const;
42 // content::WebContentObserver implementation.
43 virtual void DidUpdateFaviconURL(
45 const std::vector
<content::FaviconURL
>& candidates
) OVERRIDE
;
48 void DidDownloadFavicon(
51 const GURL
& image_url
,
52 const std::vector
<SkBitmap
>& bitmaps
,
53 const std::vector
<gfx::Size
>& original_bitmap_sizes
);
55 void AddFavicon(const GURL
& image_url
, const SkBitmap
& new_bitmap
);
57 LauncherFaviconLoader::Delegate
* delegate_
;
59 content::WebContents
* web_contents_
;
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.
70 base::WeakPtrFactory
<FaviconBitmapHandler
> weak_ptr_factory_
;
72 DISALLOW_COPY_AND_ASSIGN(FaviconBitmapHandler
);
75 void FaviconBitmapHandler::DidUpdateFaviconURL(
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.
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
)
89 const GURL
& url
= iter
->icon_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
);
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();
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(
115 true, // is a favicon
116 0, // no maximum size
117 base::Bind(&FaviconBitmapHandler::DidDownloadFavicon
,
118 weak_ptr_factory_
.GetWeakPtr()));
122 bool FaviconBitmapHandler::HasPendingDownloads() const {
123 return !pending_requests_
.empty();
126 void FaviconBitmapHandler::DidDownloadFavicon(
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.
137 pending_requests_
.erase(iter
);
139 // Favicon bitmaps are ordered by decreasing width.
140 if (!bitmaps
.empty())
141 AddFavicon(image_url
, bitmaps
[0]);
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
)
150 if (new_bitmap
.height() < ash::kShelfPreferredSize
)
152 if (!bitmap_
.isNull()) {
153 // We want the smallest icon that is large enough.
154 if (new_bitmap
.height() > bitmap_
.height())
157 bitmap_url_
= image_url
;
158 bitmap_
= new_bitmap
;
159 delegate_
->FaviconUpdated();
162 } // namespace internal
164 ////////////////////////////////////////////////////////////////////////////////
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
));
173 LauncherFaviconLoader::~LauncherFaviconLoader() {
176 SkBitmap
LauncherFaviconLoader::GetFavicon() const {
177 return favicon_handler_
->bitmap();
180 bool LauncherFaviconLoader::HasPendingDownloads() const {
181 return favicon_handler_
->HasPendingDownloads();