Makes tab contents look for extension whose extent contains the
current url and fetches the smallish icon if the extension is found.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/1576006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43345 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index b56d5b6..de783660 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -955,8 +955,16 @@
}
Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
- std::string host = url.host();
- return GetExtensionById(host, false);
+ return url.scheme() != chrome::kExtensionScheme ? NULL :
+ GetExtensionById(url.host(), false);
+}
+
+Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) {
+ for (size_t i = 0; i < extensions_.size(); ++i) {
+ if (extensions_[i]->web_extent().ContainsURL(url))
+ return extensions_[i];
+ }
+ return NULL;
}
void ExtensionsService::ClearProvidersForTesting() {
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index b56d7bd..88565166 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -250,9 +250,13 @@
// Scan the extension directory and clean up the cruft.
void GarbageCollectExtensions();
- // Lookup an extension by |url|. This uses the host of the URL as the id.
+ // Lookup an extension by |url|.
Extension* GetExtensionByURL(const GURL& url);
+ // If there is an extension for the specified url it is returned. Otherwise
+ // returns the extension whose web extent contains |url|.
+ Extension* GetExtensionByWebExtent(const GURL& url);
+
// Clear all ExternalExtensionProviders.
void ClearProvidersForTesting();
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index dd53dcc..10da50e 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -273,6 +273,8 @@
last_search_case_sensitive_(false),
last_search_prepopulate_text_(NULL),
last_search_result_(),
+ app_extension_(NULL),
+ app_extension_for_current_page_(NULL),
capturing_contents_(false),
is_being_destroyed_(false),
notify_disconnection_(false),
@@ -285,7 +287,6 @@
is_showing_before_unload_dialog_(false),
renderer_preferences_(),
opener_dom_ui_type_(DOMUIFactory::kNoDOMUI),
- app_extension_(NULL),
language_state_(&controller_) {
ClearBlockedContentSettings();
renderer_preferences_util::UpdateFromSystemSettings(
@@ -333,6 +334,14 @@
registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
NotificationService::AllSources());
+ // Listen for extension changes so we can update extension_for_current_page_.
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
+ NotificationService::AllSources());
+
// Keep a global copy of the previous search string (if any).
static string16 global_last_search = string16();
last_search_prepopulate_text_ = &global_last_search;
@@ -483,6 +492,8 @@
DCHECK(!extension || extension->GetFullLaunchURL().is_valid());
app_extension_ = extension;
+ UpdateAppExtensionIcon(app_extension_);
+
NotificationService::current()->Notify(
NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
Source<TabContents>(this),
@@ -786,6 +797,10 @@
favicon_service->SetFaviconOutOfDateForPage(entry.url());
}
+ // The url likely changed, see if there is an extension whose extent contains
+ // the current page.
+ UpdateAppExtensionForCurrentPage();
+
return true;
}
@@ -1543,6 +1558,10 @@
// Clear the cache of forms in AutoFill.
if (autofill_manager_.get())
autofill_manager_->Reset();
+
+ // The url likely changed, see if there is an extension whose extent contains
+ // the current page.
+ UpdateAppExtensionForCurrentPage();
}
void TabContents::DidNavigateAnyFramePostCommit(
@@ -2888,11 +2907,81 @@
break;
}
+ case NotificationType::EXTENSION_LOADED: {
+ if (!app_extension_ && !app_extension_for_current_page_ &&
+ Source<Profile>(source).ptr() == profile()) {
+ UpdateAppExtensionForCurrentPage();
+ if (app_extension_for_current_page_)
+ NotifyNavigationStateChanged(INVALIDATE_TAB);
+ }
+ break;
+ }
+
+ case NotificationType::EXTENSION_UNLOADED:
+ case NotificationType::EXTENSION_UNLOADED_DISABLED: {
+ if (app_extension_for_current_page_ ==
+ Details<Extension>(details).ptr()) {
+ app_extension_for_current_page_ = NULL;
+ UpdateAppExtensionForCurrentPage();
+ NotifyNavigationStateChanged(INVALIDATE_TAB);
+ }
+ break;
+ }
+
default:
NOTREACHED();
}
}
+void TabContents::UpdateAppExtensionIcon(Extension* extension) {
+ app_extension_icon_.reset();
+ if (extension) {
+ app_extension_image_loader_.reset(new ImageLoadingTracker(this));
+ app_extension_image_loader_->LoadImage(
+ extension,
+ extension->GetIconPath(Extension::EXTENSION_ICON_SMALLISH),
+ gfx::Size(Extension::EXTENSION_ICON_SMALLISH,
+ Extension::EXTENSION_ICON_SMALLISH),
+ ImageLoadingTracker::CACHE);
+ } else {
+ app_extension_image_loader_.reset(NULL);
+ }
+}
+
+Extension* TabContents::GetExtensionContaining(const GURL& url) {
+ ExtensionsService* extensions_service = profile()->GetExtensionsService();
+ if (!extensions_service)
+ return NULL;
+
+ Extension* extension = extensions_service->GetExtensionByURL(url);
+ return extension ?
+ extension : extensions_service->GetExtensionByWebExtent(url);
+}
+
+void TabContents::UpdateAppExtensionForCurrentPage() {
+ if (app_extension_) {
+ // Tab has an explicit app extension; nothing to do.
+ return;
+ }
+
+ // Check the current extension before iterating through all extensions.
+ if (app_extension_for_current_page_ &&
+ app_extension_for_current_page_->web_extent().ContainsURL(GetURL())) {
+ return;
+ }
+
+ app_extension_for_current_page_ = GetExtensionContaining(GetURL());
+ UpdateAppExtensionIcon(app_extension_for_current_page_);
+}
+
+void TabContents::OnImageLoaded(SkBitmap* image, ExtensionResource resource,
+ int index) {
+ if (image) {
+ app_extension_icon_ = *image;
+ NotifyNavigationStateChanged(INVALIDATE_TAB);
+ }
+}
+
std::wstring TabContents::GetMessageBoxTitle(const GURL& frame_url,
bool is_alert) {
if (!frame_url.has_host())
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 62547d6..de11dd241 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -19,6 +19,7 @@
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/browser/download/save_package.h"
+#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/browser/fav_icon_helper.h"
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/find_notification_details.h"
@@ -100,14 +101,15 @@
public RenderViewHostDelegate::Resource,
public RenderViewHostManager::Delegate,
public SelectFileDialog::Listener,
- public JavaScriptMessageBoxClient {
+ public JavaScriptMessageBoxClient,
+ public ImageLoadingTracker::Observer {
public:
// Flags passed to the TabContentsDelegate.NavigationStateChanged to tell it
// what has changed. Combine them to update more than one thing.
enum InvalidateTypes {
INVALIDATE_URL = 1 << 0, // The URL has changed.
- INVALIDATE_TAB = 1 << 1, // The favicon, or crashed state
- // changed.
+ INVALIDATE_TAB = 1 << 1, // The favicon, app icon, or crashed
+ // state changed.
INVALIDATE_LOAD = 1 << 2, // The loading state has changed.
INVALIDATE_PAGE_ACTIONS = 1 << 3, // Page action icons have changed.
INVALIDATE_BOOKMARK_BAR = 1 << 4, // State of ShouldShowBookmarkBar
@@ -181,6 +183,8 @@
return fav_icon_helper_;
}
+ // App extensions ------------------------------------------------------------
+
// Sets the extension denoting this as an app. If |extension| is non-null this
// tab becomes an app-tab. TabContents does not listen for unload events for
// the extension. It's up to consumers of TabContents to do that.
@@ -198,10 +202,14 @@
Extension* app_extension() const { return app_extension_; }
bool is_app() const { return app_extension_ != NULL; }
-#ifdef UNIT_TEST
- // Expose the render manager for testing.
- RenderViewHostManager* render_manager() { return &render_manager_; }
-#endif
+ // If an app extension has been explicitly set for this TabContents its icon
+ // is returned. If an app extension has not been set but there is an
+ // extension whose extent contains the url of the current page it's icon
+ // is returned. Otherwise an empty icon is returned.
+ //
+ // NOTE: the returned icon is larger than 16x16 (it's size is
+ // Extension::EXTENSION_ICON_SMALLISH).
+ const SkBitmap& app_extension_icon() const { return app_extension_icon_; }
// Tab navigation state ------------------------------------------------------
@@ -281,9 +289,7 @@
return web_app_info_;
}
- SkBitmap app_icon() const {
- return app_icon_;
- }
+ const SkBitmap& app_icon() const { return app_icon_; }
// Sets an app icon associated with TabContents and fires an INVALIDATE_TITLE
// navigation state change to trigger repaint of title.
@@ -329,6 +335,11 @@
virtual void ShowContents();
virtual void HideContents();
+#ifdef UNIT_TEST
+ // Expose the render manager for testing.
+ RenderViewHostManager* render_manager() { return &render_manager_; }
+#endif
+
// Commands ------------------------------------------------------------------
// Implementation of PageNavigator.
@@ -1001,6 +1012,22 @@
const NotificationSource& source,
const NotificationDetails& details);
+ // App extensions related methods:
+
+ // Returns the first extension whose extent contains |url|.
+ Extension* GetExtensionContaining(const GURL& url);
+
+ // Resets app_icon_ and if |extension| is non-null creates a new
+ // ImageLoadingTracker to load the extension's image.
+ void UpdateAppExtensionIcon(Extension* extension);
+
+ // Called on every navigation to update app_icon_cache_entry_ as necessary.
+ void UpdateAppExtensionForCurrentPage();
+
+ // ImageLoadingTracker::Observer.
+ virtual void OnImageLoaded(SkBitmap* image, ExtensionResource resource,
+ int index);
+
// Data for core operation ---------------------------------------------------
// Delegate for notifying our owner about stuff. Not owned by us.
@@ -1158,6 +1185,22 @@
// information to build its presentation.
FindNotificationDetails last_search_result_;
+ // Data for app extensions ---------------------------------------------------
+
+ // If non-null this tab is an app tab and this is the extension the tab was
+ // created for.
+ Extension* app_extension_;
+
+ // If app_extension_ is NULL and there is an extension whose extent contains
+ // the current url, this is the extension.
+ Extension* app_extension_for_current_page_;
+
+ // Icon for app_extension_ (if non-null) or extension_for_current_page_.
+ SkBitmap app_extension_icon_;
+
+ // Used for loading app_extension_icon_.
+ scoped_ptr<ImageLoadingTracker> app_extension_image_loader_;
+
// Data for misc internal state ----------------------------------------------
// See capturing_contents() above.
@@ -1217,10 +1260,6 @@
// profile
scoped_refptr<URLRequestContextGetter> request_context_;
- // If non-null this tab is an app tab and this is the extension the tab was
- // created for.
- Extension* app_extension_;
-
// Information about the language the page is in and has been translated to.
LanguageState language_state_;