Fixing build: GetViewContainer changed name from under me. :)
[chromium-blink-merge.git] / chrome / browser / web_app.cc
blob506a94f109b719871fcafc8e390c685c32bcc181
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"
15 namespace {
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);
26 else
27 NOTREACHED();
30 return image_urls;
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) {
38 return SkBitmap();
41 SkBitmap image;
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);
46 return image;
49 } // namespace
51 // WebApp ----------------------------------------------------------------------
53 WebApp::WebApp(Profile* profile,
54 const GURL& url,
55 const std::wstring& name)
56 : web_contents_(NULL),
57 profile_(profile),
58 url_(url),
59 name_(name),
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),
68 profile_(profile),
69 url_(shortcut.url),
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() &&
79 image_urls_.empty());
82 WebApp::~WebApp() {
83 if (image_load_handle_) {
84 WebDataService* service =
85 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
86 if (service)
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.
99 return;
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);
114 NotifyObservers();
115 if (service)
116 service->SetWebAppImage(url_, image);
119 if (service && image_urls_.empty())
120 service->SetWebAppHasAllImages(url_, true);
123 const WebApp::Images& WebApp::GetImages() {
124 LoadImagesFromWebData();
126 return images_;
129 SkBitmap WebApp::GetFavIcon() {
130 // Force a load.
131 GetImages();
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_)
158 return;
160 loaded_images_from_web_data_ = true;
161 WebDataService* service =
162 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
163 if (service)
164 image_load_handle_ = service->GetWebAppImages(url_, this);
167 void WebApp::OnWebDataServiceRequestDone(WebDataService::Handle h,
168 const WDTypedResult* r) {
169 image_load_handle_ = 0;
171 if (!r) {
172 // Results are null if the database went away.
173 return;
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
182 // now.
183 DownloadImagesFromSite();
184 } else {
185 // We have all the images. Clear image_urls_ to indicate we've got all the
186 // images.
187 image_urls_.clear();
190 if (GetFavIconIterator() == images_.end()) {
191 // No favicon. Request one from the history db.
192 LoadFavIconFromHistory();
195 if (!images_.empty())
196 NotifyObservers();
199 void WebApp::OnFavIconFromHistory(HistoryService::Handle handle,
200 bool know_favicon,
201 scoped_refptr<RefCountedBytes> data,
202 bool expired,
203 GURL icon_url) {
204 // Make sure we still don't have a favicon.
205 if (GetFavIconIterator() != images_.end() || !data || data->data.empty())
206 return;
208 SkBitmap fav_icon;
209 if (PNGDecoder::Decode(&data->data, &fav_icon)) {
210 images_.push_back(fav_icon);
211 NotifyObservers();
215 void WebApp::LoadFavIconFromHistory() {
216 HistoryService* service =
217 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
218 if (!service)
219 return;
221 service->GetFavIconForURL(url_, &request_consumer_,
222 NewCallback(this, &WebApp::OnFavIconFromHistory));
225 void WebApp::DownloadImagesFromSite() {
226 if (!download_images_)
227 return;
229 RenderViewHost* rvh =
230 web_contents_ ? web_contents_->render_view_host() : NULL;
231 if (!rvh)
232 return;
234 // Copy off the images to load as we may need to mutate image_urls_ while
235 // iterating.
236 std::set<GURL> image_urls = image_urls_;
237 for (std::set<GURL>::iterator i = image_urls.begin(); i != image_urls.end();
238 ++i) {
239 const GURL image_url = *i;
240 SkBitmap data_image = DecodePNGEncodedURL(image_url);
241 if (!data_image.isNull())
242 SetImage(image_url, data_image);
243 else if (rvh)
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);
251 if (service)
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)
259 return i;
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);
272 } else {
273 ++i;
278 void WebApp::NotifyObservers() {
279 FOR_EACH_OBSERVER(Observer, observer_list_, WebAppImagesChanged(this));