Index: chrome/browser/ui/web_applications/hosted_app_tab_helper.cc |
diff --git a/chrome/browser/ui/web_applications/hosted_app_tab_helper.cc b/chrome/browser/ui/web_applications/hosted_app_tab_helper.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f08ea215557b324016c0f570f029d8e0f17e048b |
--- /dev/null |
+++ b/chrome/browser/ui/web_applications/hosted_app_tab_helper.cc |
@@ -0,0 +1,179 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ui/web_applications/hosted_app_tab_helper.h" |
+ |
+#include "base/strings/utf_string_conversions.h" |
+#include "chrome/browser/extensions/crx_installer.h" |
+#include "chrome/browser/favicon/favicon_tab_helper.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/ui/web_applications/hosted_app_tab_helper_delegate.h" |
+#include "chrome/common/web_application_info.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/common/favicon_url.h" |
+ |
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(HostedAppTabHelper); |
+ |
+HostedAppTabHelper::HostedAppTabHelper(content::WebContents* web_contents) |
+ : content::WebContentsObserver(web_contents), |
+ fetch_icons_immediately_(false), |
+ delegate_(NULL) { |
+} |
+ |
+HostedAppTabHelper::~HostedAppTabHelper() { |
+} |
+ |
+void HostedAppTabHelper::CreateHostedApp( |
+ const WebApplicationInfo& web_app_info) { |
+ // If a hosted app creation request is already pending, ignore subsequent |
+ // requests. |
+ if (web_app_info_) |
+ return; |
+ |
+ web_app_info_.reset(new WebApplicationInfo(web_app_info)); |
+ |
+ // It's possible for |favicon_url_candidates_| to be populated after this is |
+ // called. DidUpdateFaviconURL() will resume the app creation process in this |
+ // case. |
+ if (!favicon_url_candidates_) |
+ return; |
+ |
+ FetchIconsIfNecessaryForCreateHostedApp(); |
+} |
+ |
+void HostedAppTabHelper::SetDelegate(HostedAppTabHelperDelegate* delegate) { |
+ delegate_ = delegate; |
+#if defined(OS_WIN) |
+ // On Windows the icons are needed for the window icon which should be fetched |
+ // as soon as we have the favicon URLs. |
+ fetch_icons_immediately_ = true; |
+#endif |
+} |
+ |
+void HostedAppTabHelper::FetchIcons() { |
+ for (std::set<GURL>::const_iterator it = favicon_url_candidates_->begin(); |
+ it != favicon_url_candidates_->end(); ++it) |
+ in_progress_requests_.insert(DownloadImage(*it)); |
+ |
+} |
+ |
+void HostedAppTabHelper::FetchIconsIfNecessaryForCreateHostedApp() { |
+ // If the delegate doesn't need the window icon, we wouldn't have fetched the |
+ // icons yet. |
+ if (!fetch_icons_immediately_) |
+ FetchIcons(); |
+ |
+ // If there are extra icon URLs in the WebApplicationInfo, download them. |
+ for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it = |
+ web_app_info_->icons.begin(); it != web_app_info_->icons.end(); |
+ ++it) { |
+ if (it->url.is_valid() && favicon_url_candidates_->count(it->url) == 0) |
+ in_progress_requests_.insert(DownloadImage(it->url)); |
+ } |
+ |
+ // If no downloads are pending, we can proceed directly to creating the hosted |
+ // app. |
+ if (in_progress_requests_.empty()) |
+ FinishCreateHostedApp(); |
+} |
+ |
+void HostedAppTabHelper::FinishCreateHostedApp() { |
+ if (web_app_info_->app_url.is_empty()) |
+ web_app_info_->app_url = web_contents()->GetURL(); |
+ |
+ if (web_app_info_->title.empty()) |
+ web_app_info_->title = web_contents()->GetTitle(); |
+ if (web_app_info_->title.empty()) |
+ web_app_info_->title = UTF8ToUTF16(web_app_info_->app_url.spec()); |
+ |
+ web_app_info_->urls.push_back(web_app_info_->app_url); |
+ web_app_info_->is_bookmark_app = true; |
+ |
+ // Add the downloaded icons. |
+ for (gfx::ImageFamily::const_iterator it = image_family_.begin(); |
+ it != image_family_.end(); ++it) { |
+ if (!it->IsEmpty()) { |
+ WebApplicationInfo::IconInfo icon_info; |
+ icon_info.data = it->AsBitmap(); |
+ icon_info.width = icon_info.data.width(); |
+ icon_info.height = icon_info.data.height(); |
+ web_app_info_->icons.push_back(icon_info); |
+ } |
+ } |
+ |
+ Profile* profile = |
+ Profile::FromBrowserContext(web_contents()->GetBrowserContext()); |
+ scoped_refptr<extensions::CrxInstaller> installer( |
+ extensions::CrxInstaller::CreateSilent(profile->GetExtensionService())); |
+ installer->set_error_on_unsupported_requirements(true); |
+ installer->InstallWebApp(*web_app_info_); |
+ |
+ web_app_info_.reset(); |
+} |
+ |
+void HostedAppTabHelper::DidDownloadFavicon( |
+ int id, |
+ int http_status_code, |
+ const GURL& image_url, |
+ const std::vector<SkBitmap>& bitmaps, |
+ const std::vector<gfx::Size>& original_bitmap_sizes) { |
+ // Request canceled by DidUpdateFaviconURL() or DidNavigateMainFrame(). |
+ if (in_progress_requests_.erase(id) == 0) |
+ return; |
+ for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); |
+ it != bitmaps.end(); ++it) { |
+ image_family_.Add(gfx::Image::CreateFrom1xBitmap(*it)); |
+ } |
+ |
+ // Once all requests have been resolved, perform post-download tasks. |
+ if (!in_progress_requests_.empty()) |
+ return; |
+ |
+ if (delegate_) |
+ delegate_->OnWindowIconLoaded(web_contents()); |
+ |
+ if (web_app_info_) |
+ FinishCreateHostedApp(); |
+} |
+ |
+int HostedAppTabHelper::DownloadImage(const GURL& url) { |
+ return web_contents()->DownloadImage( |
+ url, |
+ true, // is_favicon |
+ 0, // no max size |
+ base::Bind(&HostedAppTabHelper::DidDownloadFavicon, |
+ base::Unretained(this))); |
+} |
+ |
+// content::WebContentsObserver overrides: |
+void HostedAppTabHelper::DidNavigateMainFrame( |
+ const content::LoadCommittedDetails& details, |
+ const content::FrameNavigateParams& params) { |
+ // Clear all pending requests. |
+ favicon_url_candidates_.reset(); |
+ in_progress_requests_.clear(); |
+ web_app_info_.reset(); |
+ image_family_.clear(); |
+} |
+ |
+void HostedAppTabHelper::DidUpdateFaviconURL( |
+ int32 page_id, |
+ const std::vector<content::FaviconURL>& candidates) { |
+ in_progress_requests_.clear(); |
+ image_family_.clear(); |
+ favicon_url_candidates_.reset(new std::set<GURL>()); |
+ for (std::vector<content::FaviconURL>::const_iterator it = candidates.begin(); |
+ it != candidates.end(); ++it) { |
+ if (it->icon_type != content::FaviconURL::INVALID_ICON) |
+ favicon_url_candidates_->insert(it->icon_url); |
+ } |
+ |
+ if (fetch_icons_immediately_) |
+ FetchIcons(); |
+ |
+ // If |web_app_info_| is populated, we are in the middle of creating a hosted |
+ // app. Resume this process. |
+ if (web_app_info_) |
+ FetchIconsIfNecessaryForCreateHostedApp(); |
+} |