1 // Copyright (c) 2006-2008 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/web_app.h"
7 #include "base/gfx/png_decoder.h"
8 #include "chrome/browser/profile.h"
9 #include "chrome/browser/render_view_host.h"
10 #include "chrome/browser/web_contents.h"
11 #include "chrome/common/gfx/favicon_size.h"
12 #include "net/base/base64.h"
13 #include "net/base/data_url.h"
17 static const char kPNGImageMimeType
[] = "image/png";
19 static std::set
<GURL
> ExtractImageURLs(const GearsShortcutData
& data
) {
20 std::set
<GURL
> image_urls
;
21 for (size_t i
= 0; i
< arraysize(data
.icons
); ++i
) {
22 if (data
.icons
[i
].url
) {
23 GURL
image_url(data
.icons
[i
].url
);
24 if (image_url
.is_valid())
25 image_urls
.insert(image_url
);
33 static SkBitmap
DecodePNGEncodedURL(const GURL
& url
) {
34 std::string mime_type
, charset
, data
;
35 if (!url
.SchemeIs("data") ||
36 !net::DataURL::Parse(url
, &mime_type
, &charset
, &data
) ||
37 mime_type
!= kPNGImageMimeType
) {
42 std::vector
<unsigned char> v_data
;
43 v_data
.resize(data
.size(), 0);
44 memcpy(&v_data
.front(), data
.c_str(), data
.size());
45 PNGDecoder::Decode(&v_data
, &image
);
51 // WebApp ----------------------------------------------------------------------
53 WebApp::WebApp(Profile
* profile
,
55 const std::wstring
& name
)
56 : web_contents_(NULL
),
60 loaded_images_from_web_data_(false),
61 image_load_handle_(0),
62 download_images_(false) {
65 WebApp::WebApp(Profile
* profile
,
66 const GearsShortcutData
& shortcut
)
67 : web_contents_(NULL
),
70 name_(shortcut
.name
? UTF8ToWide(shortcut
.name
) : std::wstring()),
71 loaded_images_from_web_data_(false),
72 image_load_handle_(0),
73 image_urls_(ExtractImageURLs(shortcut
)),
74 download_images_(!image_urls_
.empty()) {
75 ExtractPNGEncodedURLs();
76 // If the image urls are all data encoded urls and at least one is favicon
77 // sized, then no need to load/store in web data.
78 loaded_images_from_web_data_
= (GetFavIconIterator() != images_
.end() &&
83 if (image_load_handle_
) {
84 WebDataService
* service
=
85 profile_
->GetWebDataService(Profile::EXPLICIT_ACCESS
);
87 service
->CancelRequest(image_load_handle_
);
91 void WebApp::SetImage(const GURL
& image_url
, const SkBitmap
& image
) {
92 std::set
<GURL
>::iterator i
= image_urls_
.find(image_url
);
93 if (i
== image_urls_
.end())
94 return; // We didn't request the url.
96 if (image
.width() == 0 || image
.height() == 0) {
97 // Assume there was an error downloading. By ignoring this we ensure we
98 // attempt to download the image next time user launches the app.
102 image_urls_
.erase(i
);
104 WebDataService
* service
=
105 profile_
->GetWebDataService(Profile::EXPLICIT_ACCESS
);
107 if (!image
.isNull()) {
108 if (image
.width() == kFavIconSize
&& image
.height() == kFavIconSize
) {
109 Images::iterator fav_icon_i
= GetFavIconIterator();
110 if (fav_icon_i
!= images_
.end())
111 images_
.erase(fav_icon_i
); // Only allow one favicon.
113 images_
.push_back(image
);
116 service
->SetWebAppImage(url_
, image
);
119 if (service
&& image_urls_
.empty())
120 service
->SetWebAppHasAllImages(url_
, true);
123 const WebApp::Images
& WebApp::GetImages() {
124 LoadImagesFromWebData();
129 SkBitmap
WebApp::GetFavIcon() {
133 Images::iterator fav_icon_i
= GetFavIconIterator();
134 return (fav_icon_i
== images_
.end()) ? SkBitmap() : *fav_icon_i
;
137 void WebApp::SetWebContents(WebContents
* host
) {
138 web_contents_
= host
;
140 if (host
&& loaded_images_from_web_data_
&& image_load_handle_
== 0 &&
141 !image_urls_
.empty()) {
142 // We haven't downloaded all the images and got a new WebContents. Download
143 // the images from it.
144 DownloadImagesFromSite();
148 void WebApp::AddObserver(Observer
* obs
) {
149 observer_list_
.AddObserver(obs
);
152 void WebApp::RemoveObserver(Observer
* obs
) {
153 observer_list_
.RemoveObserver(obs
);
156 void WebApp::LoadImagesFromWebData() {
157 if (loaded_images_from_web_data_
)
160 loaded_images_from_web_data_
= true;
161 WebDataService
* service
=
162 profile_
->GetWebDataService(Profile::EXPLICIT_ACCESS
);
164 image_load_handle_
= service
->GetWebAppImages(url_
, this);
167 void WebApp::OnWebDataServiceRequestDone(WebDataService::Handle h
,
168 const WDTypedResult
* r
) {
169 image_load_handle_
= 0;
172 // Results are null if the database went away.
176 WDAppImagesResult result
= reinterpret_cast<
177 const WDResult
<WDAppImagesResult
>*>(r
)->GetValue();
178 images_
.insert(images_
.end(), result
.images
.begin(), result
.images
.end());
180 if (!result
.has_all_images
) {
181 // Not all of the images for the app have been downloaded yet; download them
183 DownloadImagesFromSite();
185 // We have all the images. Clear image_urls_ to indicate we've got all the
190 if (GetFavIconIterator() == images_
.end()) {
191 // No favicon. Request one from the history db.
192 LoadFavIconFromHistory();
195 if (!images_
.empty())
199 void WebApp::OnFavIconFromHistory(HistoryService::Handle handle
,
201 scoped_refptr
<RefCountedBytes
> data
,
204 // Make sure we still don't have a favicon.
205 if (GetFavIconIterator() != images_
.end() || !data
|| data
->data
.empty())
209 if (PNGDecoder::Decode(&data
->data
, &fav_icon
)) {
210 images_
.push_back(fav_icon
);
215 void WebApp::LoadFavIconFromHistory() {
216 HistoryService
* service
=
217 profile_
->GetHistoryService(Profile::EXPLICIT_ACCESS
);
221 service
->GetFavIconForURL(url_
, &request_consumer_
,
222 NewCallback(this, &WebApp::OnFavIconFromHistory
));
225 void WebApp::DownloadImagesFromSite() {
226 if (!download_images_
)
229 RenderViewHost
* rvh
=
230 web_contents_
? web_contents_
->render_view_host() : NULL
;
234 // Copy off the images to load as we may need to mutate image_urls_ while
236 std::set
<GURL
> image_urls
= image_urls_
;
237 for (std::set
<GURL
>::iterator i
= image_urls
.begin(); i
!= image_urls
.end();
239 const GURL image_url
= *i
;
240 SkBitmap data_image
= DecodePNGEncodedURL(image_url
);
241 if (!data_image
.isNull())
242 SetImage(image_url
, data_image
);
244 rvh
->DownloadImage(image_url
, 0); // Download the image via the renderer.
247 if (image_urls_
.empty()) {
248 // We got all the images immediately, notifiy the web db.
249 WebDataService
* service
=
250 profile_
->GetWebDataService(Profile::EXPLICIT_ACCESS
);
252 service
->SetWebAppHasAllImages(url_
, true);
256 WebApp::Images::iterator
WebApp::GetFavIconIterator() {
257 for (Images::iterator i
= images_
.begin(); i
!= images_
.end(); ++i
) {
258 if (i
->width() == kFavIconSize
&& i
->height() == kFavIconSize
)
261 return images_
.end();
264 void WebApp::ExtractPNGEncodedURLs() {
265 for (std::set
<GURL
>::iterator i
= image_urls_
.begin();
266 i
!= image_urls_
.end();) {
267 const GURL image_url
= *i
;
268 SkBitmap data_image
= DecodePNGEncodedURL(image_url
);
269 if (!data_image
.isNull()) {
270 i
= image_urls_
.erase(i
);
271 images_
.push_back(data_image
);
278 void WebApp::NotifyObservers() {
279 FOR_EACH_OBSERVER(Observer
, observer_list_
, WebAppImagesChanged(this));