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::kShelfSize.
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(
44 const std::vector
<content::FaviconURL
>& candidates
) OVERRIDE
;
47 void DidDownloadFavicon(
50 const GURL
& image_url
,
51 const std::vector
<SkBitmap
>& bitmaps
,
52 const std::vector
<gfx::Size
>& original_bitmap_sizes
);
54 void AddFavicon(const GURL
& image_url
, const SkBitmap
& new_bitmap
);
56 LauncherFaviconLoader::Delegate
* delegate_
;
58 content::WebContents
* web_contents_
;
60 typedef std::set
<GURL
> UrlSet
;
61 // Map of pending download urls.
62 UrlSet pending_requests_
;
63 // Map of processed urls.
64 UrlSet processed_requests_
;
65 // Current bitmap and source url.
69 base::WeakPtrFactory
<FaviconBitmapHandler
> weak_ptr_factory_
;
71 DISALLOW_COPY_AND_ASSIGN(FaviconBitmapHandler
);
74 void FaviconBitmapHandler::DidUpdateFaviconURL(
75 const std::vector
<content::FaviconURL
>& candidates
) {
76 // This function receives a complete list of faviocn urls for the page.
77 // It may get called multiple times with the same list, and will also get
78 // called any time an item is added or removed. As such, we track processed
79 // and pending urls, but only until they are removed from the list.
80 UrlSet new_pending
, new_processed
;
81 // Create a map of valid favicon urls.
83 std::vector
<content::FaviconURL
>::const_iterator iter
;
84 for (iter
= candidates
.begin(); iter
!= candidates
.end(); ++iter
) {
85 if (iter
->icon_type
!= content::FaviconURL::FAVICON
)
87 const GURL
& url
= iter
->icon_url
;
90 // Preserve matching pending requests amd processed requests.
91 if (pending_requests_
.find(url
) != pending_requests_
.end())
92 new_pending
.insert(url
);
93 if (processed_requests_
.find(url
) != processed_requests_
.end())
94 new_processed
.insert(url
);
96 pending_requests_
= new_pending
;
97 processed_requests_
= new_processed
;
98 // Reset bitmap_ if no longer valid (i.e. not in the list of urls).
99 if (urls
.find(bitmap_url_
) == urls
.end()) {
100 bitmap_url_
= GURL();
103 // Request any new urls.
104 for (std::set
<GURL
>::iterator iter
= urls
.begin();
105 iter
!= urls
.end(); ++iter
) {
106 if (processed_requests_
.find(*iter
) != processed_requests_
.end())
107 continue; // Skip already processed downloads.
108 if (pending_requests_
.find(*iter
) != pending_requests_
.end())
109 continue; // Skip already pending downloads.
110 pending_requests_
.insert(*iter
);
111 web_contents_
->DownloadImage(
113 true, // is a favicon
114 0, // no maximum size
115 base::Bind(&FaviconBitmapHandler::DidDownloadFavicon
,
116 weak_ptr_factory_
.GetWeakPtr()));
120 bool FaviconBitmapHandler::HasPendingDownloads() const {
121 return !pending_requests_
.empty();
124 void FaviconBitmapHandler::DidDownloadFavicon(
126 int http_status_code
,
127 const GURL
& image_url
,
128 const std::vector
<SkBitmap
>& bitmaps
,
129 const std::vector
<gfx::Size
>& original_bitmap_sizes
) {
130 UrlSet::iterator iter
= pending_requests_
.find(image_url
);
131 if (iter
== pending_requests_
.end()) {
132 // Updates are received for all downloads; ignore unrequested urls.
135 pending_requests_
.erase(iter
);
137 // Favicon bitmaps are ordered by decreasing width.
138 if (!bitmaps
.empty())
139 AddFavicon(image_url
, bitmaps
[0]);
142 void FaviconBitmapHandler::AddFavicon(const GURL
& image_url
,
143 const SkBitmap
& new_bitmap
) {
144 processed_requests_
.insert(image_url
);
145 if (new_bitmap
.height() > kMaxBitmapSize
||
146 new_bitmap
.width() > kMaxBitmapSize
)
148 if (new_bitmap
.height() < ash::kShelfSize
)
150 if (!bitmap_
.isNull()) {
151 // We want the smallest icon that is large enough.
152 if (new_bitmap
.height() > bitmap_
.height())
155 bitmap_url_
= image_url
;
156 bitmap_
= new_bitmap
;
157 delegate_
->FaviconUpdated();
160 } // namespace internal
162 ////////////////////////////////////////////////////////////////////////////////
164 LauncherFaviconLoader::LauncherFaviconLoader(Delegate
* delegate
,
165 content::WebContents
* web_contents
)
166 : web_contents_(web_contents
) {
167 favicon_handler_
.reset(
168 new internal::FaviconBitmapHandler(web_contents
, delegate
));
171 LauncherFaviconLoader::~LauncherFaviconLoader() {
174 SkBitmap
LauncherFaviconLoader::GetFavicon() const {
175 return favicon_handler_
->bitmap();
178 bool LauncherFaviconLoader::HasPendingDownloads() const {
179 return favicon_handler_
->HasPendingDownloads();