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 "content/renderer/favicon_helper.h"
8 #include "base/command_line.h"
9 #include "base/message_loop.h"
10 #include "content/common/icon_messages.h"
11 #include "content/public/renderer/render_view.h"
12 #include "net/base/data_url.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
17 #include "ui/base/ui_base_switches.h"
18 #include "ui/gfx/favicon_size.h"
19 #include "ui/gfx/size.h"
20 #include "ui/gfx/skbitmap_operations.h"
21 #include "webkit/glue/image_decoder.h"
22 #include "webkit/glue/multi_resolution_image_resource_fetcher.h"
23 #include "webkit/glue/webkit_glue.h"
25 using WebKit::WebFrame
;
26 using WebKit::WebIconURL
;
27 using WebKit::WebVector
;
29 using WebKit::WebURLRequest
;
30 using webkit_glue::MultiResolutionImageResourceFetcher
;
36 // Based on the definition of chrome::kEnableTouchIcon.
37 #if defined(OS_ANDROID)
47 static FaviconURL::IconType
ToFaviconType(WebIconURL::Type type
) {
49 case WebIconURL::TypeFavicon
:
50 return FaviconURL::FAVICON
;
51 case WebIconURL::TypeTouch
:
52 return FaviconURL::TOUCH_ICON
;
53 case WebIconURL::TypeTouchPrecomposed
:
54 return FaviconURL::TOUCH_PRECOMPOSED_ICON
;
55 case WebIconURL::TypeInvalid
:
56 return FaviconURL::INVALID_ICON
;
58 return FaviconURL::INVALID_ICON
;
61 FaviconHelper::FaviconHelper(RenderView
* render_view
)
62 : RenderViewObserver(render_view
) {
65 void FaviconHelper::DidChangeIcon(WebKit::WebFrame
* frame
,
66 WebKit::WebIconURL::Type icon_type
) {
70 if (!TouchEnabled() && icon_type
!= WebIconURL::TypeFavicon
)
73 WebVector
<WebIconURL
> icon_urls
= frame
->iconURLs(icon_type
);
74 std::vector
<FaviconURL
> urls
;
75 for (size_t i
= 0; i
< icon_urls
.size(); i
++) {
76 urls
.push_back(FaviconURL(icon_urls
[i
].iconURL(),
77 ToFaviconType(icon_urls
[i
].iconType())));
79 SendUpdateFaviconURL(routing_id(), render_view()->GetPageId(), urls
);
82 FaviconHelper::~FaviconHelper() {
85 void FaviconHelper::OnDownloadFavicon(int id
,
86 const GURL
& image_url
,
88 std::vector
<SkBitmap
> result_images
;
89 if (image_url
.SchemeIs("data")) {
90 SkBitmap data_image
= ImageFromDataUrl(image_url
);
91 if (!data_image
.empty())
92 result_images
.push_back(data_image
);
94 if (DownloadFavicon(id
, image_url
, image_size
)) {
95 // Will complete asynchronously via FaviconHelper::DidDownloadFavicon
100 Send(new IconHostMsg_DidDownloadFavicon(routing_id(),
103 result_images
.empty(),
108 bool FaviconHelper::DownloadFavicon(int id
,
109 const GURL
& image_url
,
111 // Make sure webview was not shut down.
112 if (!render_view()->GetWebView())
114 // Create an image resource fetcher and assign it with a call back object.
115 image_fetchers_
.push_back(new MultiResolutionImageResourceFetcher(
116 image_url
, render_view()->GetWebView()->mainFrame(), id
,
117 WebURLRequest::TargetIsFavicon
,
118 base::Bind(&FaviconHelper::DidDownloadFavicon
,
119 base::Unretained(this), image_size
)));
123 void FaviconHelper::DidDownloadFavicon(
125 MultiResolutionImageResourceFetcher
* fetcher
,
126 const std::vector
<SkBitmap
>& images
) {
127 // Notify requester of image download status.
128 Send(new IconHostMsg_DidDownloadFavicon(routing_id(),
130 fetcher
->image_url(),
135 // Remove the image fetcher from our pending list. We're in the callback from
136 // MultiResolutionImageResourceFetcher, best to delay deletion.
137 ImageResourceFetcherList::iterator iter
=
138 std::find(image_fetchers_
.begin(), image_fetchers_
.end(), fetcher
);
139 if (iter
!= image_fetchers_
.end()) {
140 image_fetchers_
.weak_erase(iter
);
141 MessageLoop::current()->DeleteSoon(FROM_HERE
, fetcher
);
145 SkBitmap
FaviconHelper::ImageFromDataUrl(const GURL
& url
) const {
146 std::string mime_type
, char_set
, data
;
147 if (net::DataURL::Parse(url
, &mime_type
, &char_set
, &data
) && !data
.empty()) {
148 // Decode the favicon using WebKit's image decoder.
149 webkit_glue::ImageDecoder
decoder(
150 gfx::Size(gfx::kFaviconSize
, gfx::kFaviconSize
));
151 const unsigned char* src_data
=
152 reinterpret_cast<const unsigned char*>(&data
[0]);
154 return decoder
.Decode(src_data
, data
.size());
159 void FaviconHelper::SendUpdateFaviconURL(int32 routing_id
,
161 const std::vector
<FaviconURL
>& urls
) {
163 Send(new IconHostMsg_UpdateFaviconURL(routing_id
, page_id
, urls
));
166 bool FaviconHelper::OnMessageReceived(const IPC::Message
& message
) {
168 IPC_BEGIN_MESSAGE_MAP(FaviconHelper
, message
)
169 IPC_MESSAGE_HANDLER(IconMsg_DownloadFavicon
, OnDownloadFavicon
)
170 IPC_MESSAGE_UNHANDLED(handled
= false)
171 IPC_END_MESSAGE_MAP()
176 void FaviconHelper::DidStopLoading() {
177 int icon_types
= WebIconURL::TypeFavicon
;
179 icon_types
|= WebIconURL::TypeTouchPrecomposed
| WebIconURL::TypeTouch
;
181 WebVector
<WebIconURL
> icon_urls
=
182 render_view()->GetWebView()->mainFrame()->iconURLs(icon_types
);
183 std::vector
<FaviconURL
> urls
;
184 for (size_t i
= 0; i
< icon_urls
.size(); i
++) {
185 WebURL url
= icon_urls
[i
].iconURL();
187 urls
.push_back(FaviconURL(url
, ToFaviconType(icon_urls
[i
].iconType())));
189 SendUpdateFaviconURL(routing_id(), render_view()->GetPageId(), urls
);
192 } // namespace content