diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-27 00:10:52 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-27 00:10:52 +0000 |
commit | 56ce6e5e9c393626dc3da68e9703423fffa273df (patch) | |
tree | 838bc7600dbcd7b37ff6180c9ed256856b960ead /chrome | |
parent | 530a94a66cc9a68075bce7c625cb6e1d480e22a8 (diff) | |
download | chromium_src-56ce6e5e9c393626dc3da68e9703423fffa273df.zip chromium_src-56ce6e5e9c393626dc3da68e9703423fffa273df.tar.gz chromium_src-56ce6e5e9c393626dc3da68e9703423fffa273df.tar.bz2 |
Move page actions over to ExtensionAction2 and get rid of
extension_action.*.
Final bit of refactor will be to rename ExtensionAction2 to
ExtensionAction will be the next CL.
BUG=24472,25844
Review URL: http://codereview.chromium.org/332021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30133 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
26 files changed, 484 insertions, 546 deletions
diff --git a/chrome/browser/extensions/extension_file_util.cc b/chrome/browser/extensions/extension_file_util.cc index 60d4981..a71f2a2 100644 --- a/chrome/browser/extensions/extension_file_util.cc +++ b/chrome/browser/extensions/extension_file_util.cc @@ -228,10 +228,12 @@ bool ValidateExtension(Extension* extension, std::string* error) { } // Validate icon location for page actions. - const ExtensionAction* page_action = extension->page_action(); + ExtensionAction2* page_action = extension->page_action(); if (page_action) { - const std::vector<std::string>& icon_paths = page_action->icon_paths(); - for (std::vector<std::string>::const_iterator iter = icon_paths.begin(); + std::vector<std::string> icon_paths(*page_action->icon_paths()); + if (!page_action->default_icon_path().empty()) + icon_paths.push_back(page_action->default_icon_path()); + for (std::vector<std::string>::iterator iter = icon_paths.begin(); iter != icon_paths.end(); ++iter) { if (extension->GetResource(*iter).GetFilePath().empty()) { *error = StringPrintf("Could not load icon '%s' for page action.", @@ -242,14 +244,14 @@ bool ValidateExtension(Extension* extension, std::string* error) { } // Validate icon location for browser actions. + // Note: browser actions don't use the icon_paths(). ExtensionAction2* browser_action = extension->browser_action(); if (browser_action) { - std::vector<std::string>* icon_paths = browser_action->icon_paths(); - for (std::vector<std::string>::iterator iter = icon_paths->begin(); - iter != icon_paths->end(); ++iter) { - if (extension->GetResource(*iter).GetFilePath().empty()) { + std::string default_icon_path = browser_action->default_icon_path(); + if (!default_icon_path.empty()) { + if (extension->GetResource(default_icon_path).GetFilePath().empty()) { *error = StringPrintf("Could not load icon '%s' for browser action.", - iter->c_str()); + default_icon_path.c_str()); return false; } } diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc index b39ca32..b41386d 100644 --- a/chrome/browser/extensions/extension_page_actions_module.cc +++ b/chrome/browser/extensions/extension_page_actions_module.cc @@ -56,15 +56,14 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { } } - const ExtensionAction* page_action = - dispatcher()->GetExtension()->page_action(); + ExtensionAction2* page_action = dispatcher()->GetExtension()->page_action(); if (!page_action) { error_ = kNoPageActionError; return false; } if (icon_id < 0 || - static_cast<size_t>(icon_id) >= page_action->icon_paths().size()) { + static_cast<size_t>(icon_id) >= page_action->icon_paths()->size()) { error_ = (icon_id == 0) ? kNoIconSpecified : kIconIndexOutOfBounds; return false; } @@ -86,7 +85,9 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { } // Set visibility and broadcast notifications that the UI should be updated. - contents->SetPageActionEnabled(page_action, enable, title, icon_id); + page_action->SetIsVisible(tab_id, enable); + page_action->SetTitle(tab_id, title); + page_action->SetIconIndex(tab_id, icon_id); contents->PageActionStateChanged(); return true; @@ -108,17 +109,16 @@ bool PageActionFunction::InitCommon(int tab_id) { return false; } - state_ = contents_->GetOrCreatePageActionState(page_action_); return true; } -bool PageActionFunction::SetHidden(bool hidden) { +bool PageActionFunction::SetVisible(bool visible) { int tab_id; EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&tab_id)); if (!InitCommon(tab_id)) return false; - state_->set_hidden(hidden); + page_action_->SetIsVisible(tab_id, visible); contents_->PageActionStateChanged(); return true; } @@ -132,11 +132,11 @@ bool DisablePageActionFunction::RunImpl() { } bool PageActionShowFunction::RunImpl() { - return SetHidden(false); + return SetVisible(true); } bool PageActionHideFunction::RunImpl() { - return SetHidden(true); + return SetVisible(false); } bool PageActionSetIconFunction::RunImpl() { @@ -158,15 +158,15 @@ bool PageActionSetIconFunction::RunImpl() { scoped_ptr<SkBitmap> bitmap(new SkBitmap); EXTENSION_FUNCTION_VALIDATE( IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get())); - state_->set_icon(bitmap.release()); + page_action_->SetIcon(tab_id, *bitmap); } else if (args->GetInteger(L"iconIndex", &icon_index)) { - if (icon_index < 0 || - static_cast<size_t>(icon_index) >= page_action_->icon_paths().size()) { + if (icon_index < 0 || static_cast<size_t>(icon_index) >= + page_action_->icon_paths()->size()) { error_ = kIconIndexOutOfBounds; return false; } - state_->set_icon(NULL); - state_->set_icon_index(icon_index); + page_action_->SetIcon(tab_id, SkBitmap()); + page_action_->SetIconIndex(tab_id, icon_index); } else { EXTENSION_FUNCTION_VALIDATE(false); } @@ -187,7 +187,7 @@ bool PageActionSetTitleFunction::RunImpl() { std::string title; EXTENSION_FUNCTION_VALIDATE(args->GetString(L"title", &title)); - state_->set_title(title); + page_action_->SetTitle(tab_id, title); contents_->PageActionStateChanged(); return true; } @@ -213,7 +213,7 @@ bool PageActionSetBadgeBackgroundColorFunction::RunImpl() { SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1], color_array[2]); - state_->set_badge_background_color(color); + page_action_->SetBadgeBackgroundColor(tab_id, color); contents_->PageActionStateChanged(); return true; } @@ -239,7 +239,7 @@ bool PageActionSetBadgeTextColorFunction::RunImpl() { SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1], color_array[2]); - state_->set_badge_text_color(color); + page_action_->SetBadgeTextColor(tab_id, color); contents_->PageActionStateChanged(); return true; } @@ -258,7 +258,7 @@ bool PageActionSetBadgeTextFunction::RunImpl() { std::string text; EXTENSION_FUNCTION_VALIDATE(args->GetString(L"text", &text)); - state_->set_badge_text(text); + page_action_->SetBadgeText(tab_id, text); contents_->PageActionStateChanged(); return true; } diff --git a/chrome/browser/extensions/extension_page_actions_module.h b/chrome/browser/extensions/extension_page_actions_module.h index f3ac6f0..f991d71 100644 --- a/chrome/browser/extensions/extension_page_actions_module.h +++ b/chrome/browser/extensions/extension_page_actions_module.h @@ -8,19 +8,17 @@ #include "chrome/browser/extensions/extension_function.h" class TabContents; -class ExtensionAction; -class ExtensionActionState; +class ExtensionAction2; class PageActionFunction : public SyncExtensionFunction { protected: bool SetPageActionEnabled(bool enable); bool InitCommon(int tab_id); - bool SetHidden(bool hidden); + bool SetVisible(bool visible); - ExtensionAction* page_action_; + ExtensionAction2* page_action_; TabContents* contents_; - ExtensionActionState* state_; }; class EnablePageActionFunction : public PageActionFunction { diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 354d7d2..ef6d9cd 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -140,19 +140,6 @@ void ExtensionsService::Init() { GarbageCollectExtensions(); } -std::vector<ExtensionAction*> ExtensionsService::GetPageActions() const { - std::vector<ExtensionAction*> result; - - // TODO(finnur): Sort the icons in some meaningful way. - for (ExtensionList::const_iterator iter = extensions_.begin(); - iter != extensions_.end(); ++iter) { - if ((*iter)->page_action()) - result.push_back((*iter)->page_action()); - } - - return result; -} - void ExtensionsService::InstallExtension(const FilePath& extension_path) { CrxInstaller::Start(extension_path, install_directory_, Extension::INTERNAL, "", // no expected id diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 0dad4cd..ecd670d 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -102,10 +102,6 @@ class ExtensionsService return GetExtensionByIdInternal(id, true, false); } - // Retrieves a vector of all page actions, irrespective of which extension - // they belong to. - std::vector<ExtensionAction*> GetPageActions() const; - // Install the extension file at |extension_path|. Will install as an // update if an older version is already installed. // For fresh installs, this method also causes the extension to be diff --git a/chrome/browser/extensions/page_action_apitest.cc b/chrome/browser/extensions/page_action_apitest.cc index 207eccc..4a97d79 100644 --- a/chrome/browser/extensions/page_action_apitest.cc +++ b/chrome/browser/extensions/page_action_apitest.cc @@ -12,7 +12,7 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/views/browser_actions_container.h" #include "chrome/browser/views/toolbar_view.h" -#include "chrome/common/extensions/extension_action.h" +#include "chrome/common/extensions/extension_action2.h" #include "chrome/test/ui_test_utils.h" IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageAction) { @@ -33,11 +33,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageAction) { } // Test that we received the changes. - const ExtensionActionState* action_state = - browser()->GetSelectedTabContents()->GetPageActionState( - extension->page_action()); - ASSERT_TRUE(action_state); - EXPECT_EQ("Modified", action_state->title()); + int tab_id = + browser()->GetSelectedTabContents()->controller().session_id().id(); + ExtensionAction2* action = extension->page_action(); + ASSERT_TRUE(action); + EXPECT_EQ("Modified", action->GetTitle(tab_id)); { // Simulate the page action being clicked. @@ -57,7 +57,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageAction) { } // Test that we received the changes. - action_state = browser()->GetSelectedTabContents()->GetPageActionState( - extension->page_action()); - EXPECT_TRUE(action_state->icon()); + tab_id = browser()->GetSelectedTabContents()->controller().session_id().id(); + EXPECT_FALSE(action->GetIcon(tab_id).isNull()); } diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc index b137203..583f8ce 100644 --- a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc @@ -53,7 +53,7 @@ class BrowserActionButton : public NotificationObserver, // The Browser Action API does not allow the default icon path to be // changed at runtime, so we can load this now and cache it. - std::string path = extension_->browser_action()->GetDefaultIconPath(); + std::string path = extension_->browser_action()->default_icon_path(); if (!path.empty()) { tracker_ = new ImageLoadingTracker(this, 1); tracker_->PostLoadImageTask(extension_->GetResource(path), @@ -103,7 +103,8 @@ class BrowserActionButton : public NotificationObserver, // ImageLoadingTracker::Observer implementation. void OnImageLoaded(SkBitmap* image, size_t index) { - default_icon_ = gfx::GdkPixbufFromSkBitmap(image); + if (image) + default_icon_ = gfx::GdkPixbufFromSkBitmap(image); UpdateState(); } @@ -167,10 +168,7 @@ class BrowserActionButton : public NotificationObserver, gfx::CanvasPaint canvas(event, false); gfx::Rect bounding_rect(widget->allocation); - ExtensionActionState::PaintBadge(&canvas, bounding_rect, - action->GetBadgeText(tab_id), - action->GetBadgeTextColor(tab_id), - action->GetBadgeBackgroundColor(tab_id)); + action->PaintBadge(&canvas, bounding_rect, tab_id); return FALSE; } diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc index 38c24c0..198aa31 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -33,7 +33,6 @@ #include "chrome/common/page_transition_types.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "webkit/glue/window_open_disposition.h" namespace { @@ -406,17 +405,15 @@ void LocationBarViewGtk::FocusSearch() { } void LocationBarViewGtk::UpdatePageActions() { - std::vector<ExtensionAction*> page_actions; - if (profile_->GetExtensionsService()) - page_actions = profile_->GetExtensionsService()->GetPageActions(); - - // Page actions can be created without an icon, so make sure we count only - // those that have been given an icon. - for (size_t i = 0; i < page_actions.size();) { - if (page_actions[i]->icon_paths().empty()) - page_actions.erase(page_actions.begin() + i); - else - ++i; + std::vector<ExtensionAction2*> page_actions; + ExtensionsService* service = profile_->GetExtensionsService(); + if (!service) + return; + + // Find all the page actions. + for (size_t i = 0; i < service->extensions()->size(); ++i) { + if (service->extensions()->at(i)->page_action()) + page_actions.push_back(service->extensions()->at(i)->page_action()); } // Initialize on the first call, or re-inialize if more extensions have been @@ -690,11 +687,10 @@ gboolean LocationBarViewGtk::OnSecurityIconPressed( LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk( LocationBarViewGtk* owner, Profile* profile, - const ExtensionAction* page_action) + ExtensionAction2* page_action) : owner_(owner), profile_(profile), page_action_(page_action), - last_icon_skbitmap_(NULL), last_icon_pixbuf_(NULL) { event_box_.Own(gtk_event_box_new()); gtk_widget_set_size_request(event_box_.get(), kButtonSize, kButtonSize); @@ -713,11 +709,14 @@ LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk( page_action->extension_id()); DCHECK(extension); - DCHECK(!page_action->icon_paths().empty()); - const std::vector<std::string>& icon_paths = page_action->icon_paths(); - pixbufs_.resize(icon_paths.size()); + // Load all the icons declared in the manifest. This is the contents of the + // icons array, plus the default_icon property, if any. + std::vector<std::string> icon_paths(*page_action->icon_paths()); + if (!page_action_->default_icon_path().empty()) + icon_paths.push_back(page_action_->default_icon_path()); + tracker_ = new ImageLoadingTracker(this, icon_paths.size()); - for (std::vector<std::string>::const_iterator iter = icon_paths.begin(); + for (std::vector<std::string>::iterator iter = icon_paths.begin(); iter != icon_paths.end(); ++iter) { tracker_->PostLoadImageTask( extension->GetResource(*iter), @@ -731,9 +730,9 @@ LocationBarViewGtk::PageActionViewGtk::~PageActionViewGtk() { tracker_->StopTrackingImageLoad(); image_.Destroy(); event_box_.Destroy(); - for (size_t i = 0; i < pixbufs_.size(); ++i) { - if (pixbufs_[i]) - g_object_unref(pixbufs_[i]); + for (PixbufMap::iterator iter = pixbufs_.begin(); iter != pixbufs_.end(); + ++iter) { + g_object_unref(iter->second); } if (last_icon_pixbuf_) g_object_unref(last_icon_pixbuf_); @@ -746,35 +745,48 @@ void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility( current_tab_id_ = ExtensionTabUtil::GetTabId(contents); current_url_ = url; - const ExtensionActionState* state = - contents->GetPageActionState(page_action_); - bool visible = state && !state->hidden(); + bool visible = page_action_->GetIsVisible(current_tab_id_); if (visible) { // Set the tooltip. - if (state->title().empty()) - gtk_widget_set_tooltip_text(event_box_.get(), - page_action_->title().c_str()); - else - gtk_widget_set_tooltip_text(event_box_.get(), state->title().c_str()); + gtk_widget_set_tooltip_text(event_box_.get(), + page_action_->GetTitle(current_tab_id_).c_str()); // Set the image. - SkBitmap* icon = state->icon(); + // It can come from three places. In descending order of priority: + // - The developer can set it dynamically by path or bitmap. It will be in + // page_action_->GetIcon(). + // - The developer can set it dyanmically by index. It will be in + // page_action_->GetIconIndex(). + // - It can be set in the manifest by path. It will be in page_action_-> + // default_icon_path(). + + // First look for a dynamically set bitmap. + SkBitmap icon = page_action_->GetIcon(current_tab_id_); GdkPixbuf* pixbuf = NULL; - if (icon) { - if (icon != last_icon_skbitmap_) { + if (!icon.isNull()) { + if (icon.pixelRef() != last_icon_skbitmap_.pixelRef()) { if (last_icon_pixbuf_) g_object_unref(last_icon_pixbuf_); last_icon_skbitmap_ = icon; - last_icon_pixbuf_ = gfx::GdkPixbufFromSkBitmap(icon); + last_icon_pixbuf_ = gfx::GdkPixbufFromSkBitmap(&icon); } DCHECK(last_icon_pixbuf_); pixbuf = last_icon_pixbuf_; } else { - int index = state->icon_index(); - // The image index (if not within bounds) will be set to the first image. - if (index < 0 || index >= static_cast<int>(pixbufs_.size())) - index = 0; - pixbuf = pixbufs_[index]; + // Otherwise look for a dynamically set index, or fall back to the + // default path. + int icon_index = page_action_->GetIconIndex(current_tab_id_); + std::string icon_path; + if (icon_index >= 0) + icon_path = page_action_->icon_paths()->at(icon_index); + else + icon_path = page_action_->default_icon_path(); + + if (!icon_path.empty()) { + PixbufMap::iterator iter = pixbufs_.find(icon_path); + if (iter != pixbufs_.end()) + pixbuf = iter->second; + } } // The pixbuf might not be loaded yet. @@ -793,10 +805,27 @@ void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility( void LocationBarViewGtk::PageActionViewGtk::OnImageLoaded(SkBitmap* image, size_t index) { - DCHECK(index < pixbufs_.size()); - if (index == pixbufs_.size() - 1) - tracker_ = NULL; // The tracker object will delete itself when we return. - pixbufs_[index] = gfx::GdkPixbufFromSkBitmap(image); + // We loaded icons()->size() icons, plus one extra if the page action had + // a default icon. + size_t total_icons = page_action_->icon_paths()->size(); + if (!page_action_->default_icon_path().empty()) + total_icons++; + DCHECK(index < total_icons); + + // Map the index of the loaded image back to its name. If we ever get an + // index greater than the number of icons, it must be the default icon. + if (image) { + GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(image); + if (index < page_action_->icon_paths()->size()) + pixbufs_[page_action_->icon_paths()->at(index)] = pixbuf; + else + pixbufs_[page_action_->default_icon_path()] = pixbuf; + } + + // If we are done, release the tracker. + if (index == (total_icons - 1)) + tracker_ = NULL; + owner_->UpdatePageActions(); } @@ -821,16 +850,17 @@ gboolean LocationBarViewGtk::PageActionViewGtk::OnExposeEvent( TabContents* contents = view->owner_->browser_->GetSelectedTabContents(); if (!contents) return FALSE; - const ExtensionActionState* state = - contents->GetPageActionState(view->page_action_); - if (!state || state->badge_text().empty()) + + int tab_id = ExtensionTabUtil::GetTabId(contents); + if (tab_id < 0) + return FALSE; + + std::string badge_text = view->page_action_->GetBadgeText(tab_id); + if (badge_text.empty()) return FALSE; gfx::CanvasPaint canvas(event, false); gfx::Rect bounding_rect(widget->allocation); - ExtensionActionState::PaintBadge(&canvas, bounding_rect, - state->badge_text(), - state->badge_text_color(), - state->badge_background_color()); + view->page_action_->PaintBadge(&canvas, bounding_rect, tab_id); return FALSE; } diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h index bedf724..3d38c4e 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.h +++ b/chrome/browser/gtk/location_bar_view_gtk.h @@ -7,8 +7,8 @@ #include <gtk/gtk.h> +#include <map> #include <string> -#include <vector> #include "base/basictypes.h" #include "base/scoped_ptr.h" @@ -21,14 +21,15 @@ #include "chrome/common/notification_registrar.h" #include "chrome/common/owned_widget_gtk.h" #include "chrome/common/page_transition_types.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "webkit/glue/window_open_disposition.h" class AutocompleteEditViewGtk; class BubblePositioner; class Browser; class CommandUpdater; +class ExtensionAction2; class GtkThemeProvider; -class ExtensionAction; class Profile; class SkBitmap; class TabContents; @@ -105,7 +106,7 @@ class LocationBarViewGtk : public AutocompleteEditController, public: PageActionViewGtk( LocationBarViewGtk* owner, Profile* profile, - const ExtensionAction* page_action); + ExtensionAction2* page_action); virtual ~PageActionViewGtk(); GtkWidget* widget() { return event_box_.get(); } @@ -133,15 +134,16 @@ class LocationBarViewGtk : public AutocompleteEditController, // The PageAction that this view represents. The PageAction is not owned by // us, it resides in the extension of this particular profile. - const ExtensionAction* page_action_; + ExtensionAction2* page_action_; - // The icons representing different states for the page action. - std::vector<GdkPixbuf*> pixbufs_; + // A cache of all the different icon paths associated with this page action. + typedef std::map<std::string, GdkPixbuf*> PixbufMap; + PixbufMap pixbufs_; // A cache of the last dynamically generated bitmap and the pixbuf that // corresponds to it. We keep track of both so we can free old pixbufs as // their icons are replaced. - SkBitmap* last_icon_skbitmap_; + SkBitmap last_icon_skbitmap_; GdkPixbuf* last_icon_pixbuf_; // The object that is waiting for the image loading to complete diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 3876053..6fdd6bb 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -55,7 +55,7 @@ #include "chrome/browser/search_engines/template_url_fetcher.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/extensions/extension_action.h" +#include "chrome/common/extensions/extension_action2.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" @@ -605,36 +605,6 @@ void TabContents::SetIsCrashed(bool state) { NotifyNavigationStateChanged(INVALIDATE_TAB); } -void TabContents::SetPageActionEnabled(const ExtensionAction* page_action, - bool enable, - const std::string& title, - int icon_id) { - DCHECK(page_action); - ExtensionActionState* state = GetOrCreatePageActionState(page_action); - state->set_hidden(!enable); - state->set_title(title); - state->set_icon_index(icon_id); - state->set_icon(NULL); -} - -const ExtensionActionState* TabContents::GetPageActionState( - const ExtensionAction* page_action) { - if (page_actions_.end() == page_actions_.find(page_action)) - return NULL; - - return page_actions_[page_action].get(); -} - -ExtensionActionState* TabContents::GetOrCreatePageActionState( - const ExtensionAction* page_action) { - if (page_actions_.end() == page_actions_.find(page_action)) { - page_actions_[page_action].reset( - new ExtensionActionState(page_action->title(), 0)); - } - - return page_actions_[page_action].get(); -} - void TabContents::PageActionStateChanged() { NotifyNavigationStateChanged(TabContents::INVALIDATE_PAGE_ACTIONS); } @@ -1414,27 +1384,31 @@ void TabContents::DidNavigateMainFramePostCommit( // Get the favicon, either from history or request it from the net. fav_icon_helper_.FetchFavIcon(details.entry->url()); - // Disable all page actions, unless this is an in-page navigation. + // Clear all page and browser action state for this tab, unless this is an + // in-page navigation. url_canon::Replacements<char> replacements; replacements.ClearRef(); if (params.url.ReplaceComponents(replacements) != params.referrer.ReplaceComponents(replacements)) { - if (!page_actions_.empty()) - page_actions_.clear(); - ExtensionsService* service = profile()->GetExtensionsService(); if (service) { for (size_t i = 0; i < service->extensions()->size(); ++i) { - ExtensionAction2* action = + ExtensionAction2* browser_action = service->extensions()->at(i)->browser_action(); - if (!action) - continue; - - action->ClearAllValuesForTab(controller().session_id().id()); - NotificationService::current()->Notify( - NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, - Source<ExtensionAction2>(action), - NotificationService::NoDetails()); + if (browser_action) { + browser_action->ClearAllValuesForTab(controller().session_id().id()); + NotificationService::current()->Notify( + NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, + Source<ExtensionAction2>(browser_action), + NotificationService::NoDetails()); + } + + ExtensionAction2* page_action = + service->extensions()->at(i)->page_action(); + if (page_action) { + page_action->ClearAllValuesForTab(controller().session_id().id()); + PageActionStateChanged(); + } } } } diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 091bde2..b613627 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -30,7 +30,6 @@ #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/page_navigator.h" #include "chrome/browser/tab_contents/render_view_host_manager.h" -#include "chrome/common/extensions/extension_action.h" #include "chrome/common/gears_api.h" #include "chrome/common/navigation_types.h" #include "chrome/common/notification_registrar.h" @@ -74,7 +73,6 @@ class DOMUI; class DownloadItem; class LoadNotificationDetails; class OmniboxSearchHint; -class PageAction; class PasswordManager; class PluginInstaller; class Profile; @@ -255,28 +253,7 @@ class TabContents : public PageNavigator, bool is_crashed() const { return is_crashed_; } void SetIsCrashed(bool state); - // Adds/removes a page action to the list of page actions that are active in - // this tab. The parameter |title| (if not empty) can be used to override the - // page action title for this tab and |icon_id| specifies an icon index - // (defined in the manifest) to use instead of the first icon (for this tab). - void SetPageActionEnabled(const ExtensionAction* page_action, bool enable, - const std::string& title, int icon_id); - - // Returns the page action state for this tab. The pair returns contains - // the title (string) for the page action and the icon index to use (int). - // If this function returns NULL it means the page action is not enabled for - // this tab. - const ExtensionActionState* GetPageActionState( - const ExtensionAction* page_action); - - // Same as above, but creates an enable state if it doesn't exist. The return - // value can be updated. The caller should call PageActionStateChanged when - // done modifying the state. - ExtensionActionState* GetOrCreatePageActionState( - const ExtensionAction* page_action); - - // Call this after updating a ExtensionActionState object returned by - // GetOrCreatePageActionState to notify clients about the changes. + // Call this after updating a page action to notify clients about the changes. void PageActionStateChanged(); // Whether the tab is in the process of being destroyed. @@ -1127,16 +1104,6 @@ class TabContents : public PageNavigator, // information to build its presentation. FindNotificationDetails last_search_result_; - // Data for Page Actions ----------------------------------------------------- - - // A map of page actions that this tab knows about (and a state object that - // can be used to update the title, icon, visibilty, etc used for the page - // action). This map is cleared every time the mainframe navigates and - // populated by the PageAction extension API. - typedef std::map< const ExtensionAction*, linked_ptr<ExtensionActionState> > - PageActionStateMap; - PageActionStateMap page_actions_; - // Data for misc internal state ---------------------------------------------- // See capturing_contents() above. diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc index f3f02f0..6a91690 100644 --- a/chrome/browser/views/browser_actions_container.cc +++ b/chrome/browser/views/browser_actions_container.cc @@ -15,8 +15,6 @@ #include "chrome/browser/view_ids.h" #include "chrome/browser/views/extensions/extension_popup.h" #include "chrome/browser/views/toolbar_view.h" -#include "chrome/common/extensions/extension_action.h" -#include "chrome/common/extensions/extension_action2.h" #include "chrome/common/notification_source.h" #include "chrome/common/notification_type.h" #include "grit/app_resources.h" @@ -86,7 +84,7 @@ void BrowserActionButton::LoadImage() { // Load the default image from the browser action asynchronously on the file // thread. We'll get a call back into OnImageLoaded if the image loads // successfully. - std::string relative_path = browser_action()->GetDefaultIconPath(); + std::string relative_path = browser_action()->default_icon_path(); if (relative_path.empty()) return; @@ -98,7 +96,8 @@ void BrowserActionButton::LoadImage() { } void BrowserActionButton::OnImageLoaded(SkBitmap* image, size_t index) { - SetIcon(*image); + if (image) + SetIcon(*image); tracker_ = NULL; // The tracker object will delete itself when we return. GetParent()->SchedulePaint(); } @@ -211,11 +210,7 @@ void BrowserActionView::PaintChildren(gfx::Canvas* canvas) { if (tab_id < 0) return; - ExtensionActionState::PaintBadge( - canvas, gfx::Rect(width(), height()), - action->GetBadgeText(tab_id), - action->GetBadgeTextColor(tab_id), - action->GetBadgeBackgroundColor(tab_id)); + action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id); } diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index 95d2915..cbe8dd6 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -108,13 +108,13 @@ void LocationBarView::PageActionWithBadgeView::Layout() { void LocationBarView::PageActionWithBadgeView::PaintChildren( gfx::Canvas* canvas) { View::PaintChildren(canvas); - const ExtensionActionState* state = image_view_->GetPageActionState(); - if (state) { - ExtensionActionState::PaintBadge(canvas, gfx::Rect(width(), height()), - state->badge_text(), - state->badge_text_color(), - state->badge_background_color()); - } + + ExtensionAction2* action = image_view_->page_action(); + int tab_id = image_view_->current_tab_id(); + if (tab_id < 0) + return; + + action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id); } void LocationBarView::PageActionWithBadgeView::UpdateVisibility( @@ -684,17 +684,14 @@ void LocationBarView::DeletePageActionViews() { } void LocationBarView::RefreshPageActionViews() { - std::vector<ExtensionAction*> page_actions; - if (profile_->GetExtensionsService()) - page_actions = profile_->GetExtensionsService()->GetPageActions(); - - // Page actions can be created without an icon, so make sure we count only - // those that have been given an icon. - for (size_t i = 0; i < page_actions.size();) { - if (page_actions[i]->icon_paths().empty()) - page_actions.erase(page_actions.begin() + i); - else - ++i; + std::vector<ExtensionAction2*> page_actions; + ExtensionsService* service = profile_->GetExtensionsService(); + if (!service) + return; + + for (size_t i = 0; i < service->extensions()->size(); ++i) { + if (service->extensions()->at(i)->page_action()) + page_actions.push_back(service->extensions()->at(i)->page_action()); } // On startup we sometimes haven't loaded any extensions. This makes sure @@ -1228,48 +1225,30 @@ void LocationBarView::SecurityImageView::ShowInfoBubble() { SECURITY_INFO_BUBBLE_TEXT)); } -void LocationBarView::PageActionImageView::Paint(gfx::Canvas* canvas) { - LocationBarImageView::Paint(canvas); - - TabContents* contents = owner_->delegate_->GetTabContents(); - if (!contents) - return; - - const ExtensionActionState* state = - contents->GetPageActionState(page_action_); - if (state) { - ExtensionActionState::PaintBadge(canvas, gfx::Rect(width(), height()), - state->badge_text(), - state->badge_text_color(), - state->badge_background_color()); - } -} - // PageActionImageView---------------------------------------------------------- LocationBarView::PageActionImageView::PageActionImageView( LocationBarView* owner, Profile* profile, - const ExtensionAction* page_action, + ExtensionAction2* page_action, const BubblePositioner* bubble_positioner) : LocationBarImageView(bubble_positioner), owner_(owner), profile_(profile), page_action_(page_action), - current_tab_id_(-1), - tooltip_(page_action_->title()) { + current_tab_id_(-1) { Extension* extension = profile->GetExtensionsService()->GetExtensionById( page_action->extension_id()); DCHECK(extension); - // Load the images this view needs asynchronously on the file thread. We'll - // get a call back into OnImageLoaded if the image loads successfully. If not, - // the ImageView will have no image and will not appear in the Omnibox. - DCHECK(!page_action->icon_paths().empty()); - const std::vector<std::string>& icon_paths = page_action->icon_paths(); - page_action_icons_.resize(icon_paths.size()); + // Load all the icons declared in the manifest. This is the contents of the + // icons array, plus the default_icon property, if any. + std::vector<std::string> icon_paths(*page_action->icon_paths()); + if (!page_action_->default_icon_path().empty()) + icon_paths.push_back(page_action_->default_icon_path()); + tracker_ = new ImageLoadingTracker(this, icon_paths.size()); - for (std::vector<std::string>::const_iterator iter = icon_paths.begin(); + for (std::vector<std::string>::iterator iter = icon_paths.begin(); iter != icon_paths.end(); ++iter) { tracker_->PostLoadImageTask( extension->GetResource(*iter), @@ -1299,26 +1278,32 @@ bool LocationBarView::PageActionImageView::OnMousePressed( return true; } -const ExtensionActionState* - LocationBarView::PageActionImageView::GetPageActionState() { - TabContents* contents = owner_->delegate_->GetTabContents(); - if (!contents) - return NULL; - - return contents->GetPageActionState(page_action_); -} - void LocationBarView::PageActionImageView::ShowInfoBubble() { ShowInfoBubbleImpl(ASCIIToWide(tooltip_), GetColor(false, TEXT)); } void LocationBarView::PageActionImageView::OnImageLoaded(SkBitmap* image, size_t index) { - DCHECK(index < page_action_icons_.size()); - if (index == page_action_icons_.size() - 1) - tracker_ = NULL; // The tracker object will delete itself when we return. - if (image) - page_action_icons_[index] = *image; + // We loaded icons()->size() icons, plus one extra if the page action had + // a default icon. + int total_icons = page_action_->icon_paths()->size(); + if (!page_action_->default_icon_path().empty()) + total_icons++; + DCHECK(static_cast<int>(index) < total_icons); + + // Map the index of the loaded image back to its name. If we ever get an + // index greater than the number of icons, it must be the default icon. + if (image) { + if (index < page_action_->icon_paths()->size()) + page_action_icons_[page_action_->icon_paths()->at(index)] = *image; + else + page_action_icons_[page_action_->default_icon_path()] = *image; + } + + // If we are done, release the tracker. + if (static_cast<int>(index) == (total_icons - 1)) + tracker_ = NULL; + owner_->UpdatePageActions(); } @@ -1329,26 +1314,39 @@ void LocationBarView::PageActionImageView::UpdateVisibility( current_tab_id_ = ExtensionTabUtil::GetTabId(contents); current_url_ = url; - const ExtensionActionState* state = - contents->GetPageActionState(page_action_); - bool visible = state && !state->hidden(); + bool visible = page_action_->GetIsVisible(current_tab_id_); if (visible) { // Set the tooltip. - if (state->title().empty()) - tooltip_ = page_action_->title(); - else - tooltip_ = state->title(); + tooltip_ = page_action_->GetTitle(current_tab_id_); // Set the image. - SkBitmap* icon = state->icon(); - if (!icon) { - int index = state->icon_index(); - // The image index (if not within bounds) will be set to the first image. - if (index < 0 || index >= static_cast<int>(page_action_icons_.size())) - index = 0; - icon = &page_action_icons_[index]; + // It can come from three places. In descending order of priority: + // - The developer can set it dynamically by path or bitmap. It will be in + // page_action_->GetIcon(). + // - The developer can set it dynamically by index. It will be in + // page_action_->GetIconIndex(). + // - It can be set in the manifest by path. It will be in page_action_-> + // default_icon_path(). + + // First look for a dynamically set bitmap. + SkBitmap icon = page_action_->GetIcon(current_tab_id_); + if (icon.isNull()) { + int icon_index = page_action_->GetIconIndex(current_tab_id_); + std::string icon_path; + if (icon_index >= 0) + icon_path = page_action_->icon_paths()->at(icon_index); + else + icon_path = page_action_->default_icon_path(); + + if (!icon_path.empty()) { + PageActionMap::iterator iter = page_action_icons_.find(icon_path); + if (iter != page_action_icons_.end()) + icon = iter->second; + } } - ImageView::SetImage(icon); + + if (!icon.isNull()) + ImageView::SetImage(&icon); } SetVisible(visible); } diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h index 5c40886..5accd9b 100644 --- a/chrome/browser/views/location_bar_view.h +++ b/chrome/browser/views/location_bar_view.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_VIEWS_LOCATION_BAR_VIEW_H_ #include <string> +#include <map> #include <vector> #include "app/gfx/font.h" @@ -29,8 +30,8 @@ class BubblePositioner; class CommandUpdater; +class ExtensionAction2; class GURL; -class PageAction; class Profile; ///////////////////////////////////////////////////////////////////////////// @@ -348,18 +349,19 @@ class LocationBarView : public LocationBar, public: PageActionImageView(LocationBarView* owner, Profile* profile, - const ExtensionAction* page_action, + ExtensionAction2* page_action, const BubblePositioner* bubble_positioner); virtual ~PageActionImageView(); - const ExtensionActionState* GetPageActionState(); + ExtensionAction2* page_action() { return page_action_; } + + int current_tab_id() { return current_tab_id_; } // Overridden from view for the mouse hovering. virtual bool OnMousePressed(const views::MouseEvent& event); // Overridden from LocationBarImageView. virtual void ShowInfoBubble(); - virtual void Paint(gfx::Canvas* canvas); // Overridden from ImageLoadingTracker. virtual void OnImageLoaded(SkBitmap* image, size_t index); @@ -378,10 +380,11 @@ class LocationBarView : public LocationBar, // The PageAction that this view represents. The PageAction is not owned by // us, it resides in the extension of this particular profile. - const ExtensionAction* page_action_; + ExtensionAction2* page_action_; - // The icons representing different states for the page action. - std::vector<SkBitmap> page_action_icons_; + // A cache of bitmaps the page actions might need to show, mapped by path. + typedef std::map<std::string, SkBitmap> PageActionMap; + PageActionMap page_action_icons_; // The object that is waiting for the image loading to complete // asynchronously. diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index ed9a1bc..71486f6 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -538,8 +538,6 @@ 'common/extensions/extension_error_reporter.h', 'common/extensions/extension_error_utils.cc', 'common/extensions/extension_error_utils.h', - 'common/extensions/extension_action.cc', - 'common/extensions/extension_action.h', 'common/extensions/extension_action2.cc', 'common/extensions/extension_action2.h', 'common/extensions/extension_message_bundle.cc', diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index 202a2dc..2fae2ab 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -297,99 +297,15 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, return true; } -// Helper method that loads a PageAction or BrowserAction object from a -// dictionary in the page_actions list or browser_action key of the manifest. -ExtensionAction* Extension::LoadExtensionActionHelper( - const DictionaryValue* page_action, std::string* error, - ExtensionAction::ExtensionActionType action_type) { - scoped_ptr<ExtensionAction> result(new ExtensionAction()); - result->set_extension_id(id()); - result->set_type(action_type); - - // TODO(EXTENSIONS_DEPRECATED): icons list is obsolete. - ListValue* icons = NULL; - if (page_action->HasKey(keys::kPageActionIcons) && - page_action->GetList(keys::kPageActionIcons, &icons)) { - for (ListValue::const_iterator iter = icons->begin(); - iter != icons->end(); ++iter) { - std::string path; - if (!(*iter)->GetAsString(&path) || path.empty()) { - *error = errors::kInvalidPageActionIconPath; - return NULL; - } - - result->AddIconPath(path); - } - } - - // TODO(EXTENSIONS_DEPRECATED): Read the page action |id| (optional). - std::string id; - if (action_type == ExtensionAction::PAGE_ACTION) - page_action->GetString(keys::kPageActionId, &id); - result->set_id(id); - - std::string default_icon; - // Read the page action |default_icon| (optional). - if (page_action->HasKey(keys::kPageActionDefaultIcon)) { - if (!page_action->GetString(keys::kPageActionDefaultIcon, &default_icon) || - default_icon.empty()) { - *error = errors::kInvalidPageActionIconPath; - return NULL; - } - // TODO(EXTENSIONS_DEPRECATED): one icon. - result->AddIconPath(default_icon); - } - - // Read the page action |default_title|. - std::string title; - if (!page_action->GetString(keys::kName, &title) && - !page_action->GetString(keys::kPageActionDefaultTitle, &title)) { - *error = errors::kInvalidPageActionDefaultTitle; - return NULL; - } - result->set_title(title); - - // Read the action's |popup| (optional). - DictionaryValue* popup = NULL; - std::string url_str; - if (page_action->HasKey(keys::kPageActionPopup) && - !page_action->GetDictionary(keys::kPageActionPopup, &popup) && - !page_action->GetString(keys::kPageActionPopup, &url_str)) { - *error = errors::kInvalidPageActionPopup; - return NULL; - } - if (popup) { - // TODO(EXTENSIONS_DEPRECATED): popup is a string only - if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) { - *error = ExtensionErrorUtils::FormatErrorMessage( - errors::kInvalidPageActionPopupPath, "<missing>"); - return NULL; - } - GURL url = GetResourceURL(url_str); - if (!url.is_valid()) { - *error = ExtensionErrorUtils::FormatErrorMessage( - errors::kInvalidPageActionPopupPath, url_str); - return NULL; - } - result->set_popup_url(url); - } else if (!url_str.empty()) { - GURL url = GetResourceURL(url_str); - if (!url.is_valid()) { - *error = ExtensionErrorUtils::FormatErrorMessage( - errors::kInvalidPageActionPopupPath, url_str); - return NULL; - } - result->set_popup_url(url); - } - - return result.release(); -} - ExtensionAction2* Extension::LoadExtensionAction2Helper( const DictionaryValue* extension_action, std::string* error) { scoped_ptr<ExtensionAction2> result(new ExtensionAction2()); result->set_extension_id(id()); + // Page actions are hidden by default, and browser actions ignore + // visibility. + result->SetIsVisible(ExtensionAction2::kDefaultTabId, false); + // TODO(EXTENSIONS_DEPRECATED): icons list is obsolete. ListValue* icons = NULL; if (extension_action->HasKey(keys::kPageActionIcons) && @@ -403,7 +319,6 @@ ExtensionAction2* Extension::LoadExtensionAction2Helper( } result->icon_paths()->push_back(path); - result->SetDefaultIcon(path); } } @@ -426,7 +341,7 @@ ExtensionAction2* Extension::LoadExtensionAction2Helper( *error = errors::kInvalidPageActionIconPath; return NULL; } - result->SetDefaultIcon(default_icon); + result->set_default_icon_path(default_icon); } // Read the page action |default_title|. @@ -1031,8 +946,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id, } page_action_.reset( - LoadExtensionActionHelper(page_action_value, error, - ExtensionAction::PAGE_ACTION)); + LoadExtensionAction2Helper(page_action_value, error)); if (!page_action_.get()) return false; // Failed to parse page action definition. } else if (source.HasKey(keys::kPageAction)) { @@ -1043,8 +957,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id, } page_action_.reset( - LoadExtensionActionHelper(page_action_value, error, - ExtensionAction::PAGE_ACTION)); + LoadExtensionAction2Helper(page_action_value, error)); if (!page_action_.get()) return false; // Failed to parse page action definition. } @@ -1179,9 +1092,9 @@ std::set<FilePath> Extension::GetBrowserImages() { // page action icons if (page_action_.get()) { - const std::vector<std::string>& icon_paths = page_action_->icon_paths(); - for (std::vector<std::string>::const_iterator iter = icon_paths.begin(); - iter != icon_paths.end(); ++iter) { + std::vector<std::string>* icon_paths = page_action_->icon_paths(); + for (std::vector<std::string>::iterator iter = icon_paths->begin(); + iter != icon_paths->end(); ++iter) { image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(*iter))); } } diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index 4a9fcd9..4677e2d 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -191,7 +191,7 @@ class Extension { const std::string& public_key() const { return public_key_; } const std::string& description() const { return description_; } const UserScriptList& content_scripts() const { return content_scripts_; } - ExtensionAction* page_action() const { return page_action_.get(); } + ExtensionAction2* page_action() const { return page_action_.get(); } ExtensionAction2* browser_action() const { return browser_action_.get(); } const std::vector<PrivacyBlacklistInfo>& privacy_blacklists() const { return privacy_blacklists_; @@ -281,7 +281,7 @@ class Extension { // Helper method that loads a ExtensionAction object from a // dictionary in the page_action or browser_action section of the manifest. - ExtensionAction* LoadExtensionActionHelper( + ExtensionAction2* LoadExtensionActionHelper( const DictionaryValue* contextual_action, std::string* error, ExtensionAction::ExtensionActionType action_type); @@ -326,7 +326,7 @@ class Extension { UserScriptList content_scripts_; // The extension's page action, if any. - scoped_ptr<ExtensionAction> page_action_; + scoped_ptr<ExtensionAction2> page_action_; // The extension's browser action, if any. scoped_ptr<ExtensionAction2> browser_action_; diff --git a/chrome/common/extensions/extension_action2.cc b/chrome/common/extensions/extension_action2.cc index 653de95..b36ef44 100755 --- a/chrome/common/extensions/extension_action2.cc +++ b/chrome/common/extensions/extension_action2.cc @@ -4,28 +4,129 @@ #include "chrome/common/extensions/extension_action2.h" -#include "base/logging.h" +#include "app/gfx/canvas.h" +#include "app/resource_bundle.h" +#include "base/gfx/rect.h" +#include "chrome/app/chrome_dll_resource.h" +#include "grit/app_resources.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/effects/SkGradientShader.h" const int ExtensionAction2::kDefaultTabId = -1; -void ExtensionAction2::SetDefaultIcon(const std::string& path) { - default_icon_path_ = path; - icon_.erase(kDefaultTabId); +void ExtensionAction2::ClearAllValuesForTab(int tab_id) { + title_.erase(tab_id); + icon_.erase(tab_id); + icon_index_.erase(tab_id); + badge_text_.erase(tab_id); + badge_text_color_.erase(tab_id); + badge_background_color_.erase(tab_id); + visible_.erase(tab_id); } -void ExtensionAction2::SetDefaultIcon(int icon_index) { - if (static_cast<size_t>(icon_index) >= icon_paths_.size()) { - NOTREACHED(); +void ExtensionAction2::PaintBadge(gfx::Canvas* canvas, + const gfx::Rect& bounds, + int tab_id) { + std::string text = GetBadgeText(tab_id); + if (text.empty()) return; + + SkColor text_color = GetBadgeTextColor(tab_id); + SkColor background_color = GetBadgeBackgroundColor(tab_id); + + if (SkColorGetA(text_color) == 0x00) + text_color = SK_ColorWHITE; + + if (SkColorGetA(background_color) == 0x00) + background_color = SkColorSetARGB(255, 218, 0, 24); // default badge color + + // Different platforms need slightly different constants to look good. +#if defined(OS_LINUX) + const int kTextSize = 9; + const int kBottomMargin = 4; + const int kPadding = 2; + const int kBadgeHeight = 12; + const int kMaxTextWidth = 23; + // The minimum width for center-aligning the badge. + const int kCenterAlignThreshold = 20; +#else + const int kTextSize = 8; + const int kBottomMargin = 5; + const int kPadding = 2; + const int kBadgeHeight = 11; + const int kMaxTextWidth = 23; + // The minimum width for center-aligning the badge. + const int kCenterAlignThreshold = 20; +#endif + + canvas->save(); + + SkTypeface* typeface = SkTypeface::CreateFromName("Arial", SkTypeface::kBold); + SkPaint text_paint; + text_paint.setAntiAlias(true); + text_paint.setColor(text_color); + text_paint.setFakeBoldText(true); + text_paint.setTextAlign(SkPaint::kLeft_Align); + text_paint.setTextSize(SkIntToScalar(kTextSize)); + text_paint.setTypeface(typeface); + + // Calculate text width. We clamp it to a max size. + SkScalar text_width = text_paint.measureText(text.c_str(), text.size()); + text_width = SkIntToScalar( + std::min(kMaxTextWidth, SkScalarFloor(text_width))); + + // Cacluate badge size. It is clamped to a min width just because it looks + // silly if it is too skinny. + int badge_width = SkScalarFloor(text_width) + kPadding * 2; + badge_width = std::max(kBadgeHeight, badge_width); + + // Paint the badge background color in the right location. It is usually + // right-aligned, but it can also be center-aligned if it is large. + SkRect rect; + rect.fBottom = SkIntToScalar(bounds.bottom() - kBottomMargin); + rect.fTop = rect.fBottom - SkIntToScalar(kBadgeHeight); + if (badge_width >= kCenterAlignThreshold) { + rect.fLeft = SkIntToScalar((bounds.right() - badge_width) / 2); + rect.fRight = rect.fLeft + SkIntToScalar(badge_width); + } else { + rect.fRight = SkIntToScalar(bounds.right()); + rect.fLeft = rect.fRight - badge_width; } - SetDefaultIcon(icon_paths_[icon_index]); -} + SkPaint rect_paint; + rect_paint.setStyle(SkPaint::kFill_Style); + rect_paint.setAntiAlias(true); + rect_paint.setColor(background_color); + canvas->drawRoundRect(rect, SkIntToScalar(2), SkIntToScalar(2), rect_paint); -void ExtensionAction2::ClearAllValuesForTab(int tab_id) { - title_.erase(tab_id); - icon_.erase(tab_id); - badge_text_.erase(tab_id); - badge_background_color_.erase(tab_id); - badge_text_color_.erase(tab_id); + // Overlay the gradient. It is stretchy, so we do this in three parts. + ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance(); + SkBitmap* gradient_left = resource_bundle.GetBitmapNamed( + IDR_BROWSER_ACTION_BADGE_LEFT); + SkBitmap* gradient_right = resource_bundle.GetBitmapNamed( + IDR_BROWSER_ACTION_BADGE_RIGHT); + SkBitmap* gradient_center = resource_bundle.GetBitmapNamed( + IDR_BROWSER_ACTION_BADGE_CENTER); + + canvas->drawBitmap(*gradient_left, rect.fLeft, rect.fTop); + canvas->TileImageInt(*gradient_center, + SkScalarFloor(rect.fLeft) + gradient_left->width(), + SkScalarFloor(rect.fTop), + SkScalarFloor(rect.width()) - gradient_left->width() - + gradient_right->width(), + SkScalarFloor(rect.height())); + canvas->drawBitmap(*gradient_right, + rect.fRight - SkIntToScalar(gradient_right->width()), rect.fTop); + + // Finally, draw the text centered within the badge. We set a clip in case the + // text was too large. + rect.fLeft += kPadding; + rect.fRight -= kPadding; + canvas->clipRect(rect); + canvas->drawText(text.c_str(), text.size(), + rect.fLeft + (rect.width() - text_width) / 2, + rect.fTop + kTextSize + 1, + text_paint); + canvas->restore(); } diff --git a/chrome/common/extensions/extension_action2.h b/chrome/common/extensions/extension_action2.h index ae4cf34..53c62bc 100755 --- a/chrome/common/extensions/extension_action2.h +++ b/chrome/common/extensions/extension_action2.h @@ -10,11 +10,17 @@ #include <vector> #include "base/basictypes.h" +#include "base/logging.h" #include "base/scoped_ptr.h" #include "googleurl/src/gurl.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" +namespace gfx { +class Canvas; +class Rect; +} + // ExtensionAction2 encapsulates the state of a browser or page action. // Instances can have both global and per-tab state. If a property does not have // a per-tab value, the global value is used instead. @@ -37,6 +43,13 @@ class ExtensionAction2 { void set_popup_url(const GURL& url) { popup_url_ = url; } bool has_popup() const { return !popup_url_.is_empty(); } + // action id -- only used with legacy page actions API + std::string id() const { return id_; } + void set_id(const std::string& id) { id_ = id; } + + // static icon paths from manifest -- only used with legacy page actions API. + std::vector<std::string>* icon_paths() { return &icon_paths_; } + // title void SetTitle(int tab_id, const std::string& title) { SetValue(&title_, tab_id, title); @@ -50,20 +63,30 @@ class ExtensionAction2 { // To get the default icon, first check for the bitmap. If it is null, check // for the path. - // icon bitmap + // Icon bitmap. void SetIcon(int tab_id, const SkBitmap& bitmap) { SetValue(&icon_, tab_id, bitmap); - if (tab_id == kDefaultTabId) - default_icon_path_.clear(); } SkBitmap GetIcon(int tab_id) { return GetValue(&icon_, tab_id); } - // icon path (relative to extension_id()'s root) - // For legacy code, we also support setting the path as an index into - // icon_paths(). - void SetDefaultIcon(const std::string& path); - void SetDefaultIcon(int icon_index); - std::string GetDefaultIconPath() { + // Icon index -- for use with icon_paths(), only used in page actions. + void SetIconIndex(int tab_id, int index) { + if (static_cast<size_t>(index) >= icon_paths_.size()) { + NOTREACHED(); + return; + } + SetValue(&icon_index_, tab_id, index); + } + int GetIconIndex(int tab_id) { + return GetValue(&icon_index_, tab_id); + } + + // Non-tab-specific icon path. This is used to support the default_icon key of + // page and browser actions. + void set_default_icon_path(const std::string& path) { + default_icon_path_ = path; + } + std::string default_icon_path() { return default_icon_path_; } @@ -89,16 +112,19 @@ class ExtensionAction2 { return GetValue(&badge_background_color_, tab_id); } + // visibility + void SetIsVisible(int tab_id, bool value) { + SetValue(&visible_, tab_id, value); + } + bool GetIsVisible(int tab_id) { + return GetValue(&visible_, tab_id); + } + // Remove all tab-specific state. void ClearAllValuesForTab(int tab_id); - //--------------------------------------------------------------------------- - // Legacy support - - std::string id() const { return id_; } - void set_id(const std::string& id) { id_ = id; } - - std::vector<std::string>* icon_paths() { return &icon_paths_; } + // If the specified tab has a badge, paint it into the provided bounds. + void PaintBadge(gfx::Canvas* canvas, const gfx::Rect& bounds, int tab_id); private: template <class T> @@ -132,31 +158,30 @@ class ExtensionAction2 { // kDefaultTabId), or tab-specific state (stored with the tab_id as the key). std::map<int, std::string> title_; std::map<int, SkBitmap> icon_; + std::map<int, int> icon_index_; // index into icon_paths_ std::map<int, std::string> badge_text_; std::map<int, SkColor> badge_background_color_; std::map<int, SkColor> badge_text_color_; + std::map<int, bool> visible_; std::string default_icon_path_; // If the action has a popup, it has a URL and a height. GURL popup_url_; - //--------------------------------------------------------------------------- - // Legacy support - // The id for the ExtensionAction2, for example: "RssPageAction". This is // needed for compat with an older version of the page actions API. std::string id_; // A list of paths to icons this action might show. This is needed to support - // the setIcon({iconIndex:...} method. + // the legacy setIcon({iconIndex:...} method of the page actions API. std::vector<std::string> icon_paths_; }; -template <> -struct ExtensionAction2::ValueTraits<SkColor> { - static SkColor CreateEmpty() { - return 0x00000000; +template<> +struct ExtensionAction2::ValueTraits<int> { + static int CreateEmpty() { + return -1; } }; diff --git a/chrome/common/extensions/extension_action2_unittest.cc b/chrome/common/extensions/extension_action2_unittest.cc index 7f1d78b..47a32d7 100644 --- a/chrome/common/extensions/extension_action2_unittest.cc +++ b/chrome/common/extensions/extension_action2_unittest.cc @@ -65,6 +65,35 @@ TEST(ExtensionAction2Test, TabSpecificState) { ASSERT_TRUE(BitmapsAreEqual(icon1, action.GetIcon(1))); ASSERT_TRUE(BitmapsAreEqual(icon2, action.GetIcon(100))); + // icon index + ASSERT_EQ(-1, action.GetIconIndex(1)); + action.icon_paths()->push_back("foo.png"); + action.icon_paths()->push_back("bar.png"); + action.SetIconIndex(ExtensionAction2::kDefaultTabId, 1); + ASSERT_EQ(1, action.GetIconIndex(1)); + ASSERT_EQ(1, action.GetIconIndex(100)); + action.SetIconIndex(100, 0); + ASSERT_EQ(0, action.GetIconIndex(100)); + ASSERT_EQ(1, action.GetIconIndex(1)); + action.ClearAllValuesForTab(100); + ASSERT_EQ(1, action.GetIconIndex(100)); + ASSERT_EQ(1, action.GetIconIndex(1)); + + // visibility + ASSERT_EQ(false, action.GetIsVisible(1)); + action.SetIsVisible(ExtensionAction2::kDefaultTabId, true); + ASSERT_EQ(true, action.GetIsVisible(1)); + ASSERT_EQ(true, action.GetIsVisible(100)); + action.SetIsVisible(ExtensionAction2::kDefaultTabId, false); + ASSERT_EQ(false, action.GetIsVisible(1)); + ASSERT_EQ(false, action.GetIsVisible(100)); + action.SetIsVisible(100, true); + ASSERT_EQ(false, action.GetIsVisible(1)); + ASSERT_EQ(true, action.GetIsVisible(100)); + action.ClearAllValuesForTab(100); + ASSERT_EQ(false, action.GetIsVisible(1)); + ASSERT_EQ(false, action.GetIsVisible(100)); + // badge text ASSERT_EQ("", action.GetBadgeText(1)); action.SetBadgeText(ExtensionAction2::kDefaultTabId, "foo"); @@ -80,48 +109,29 @@ TEST(ExtensionAction2Test, TabSpecificState) { // badge text color ASSERT_EQ(0x00000000u, action.GetBadgeTextColor(1)); - action.SetBadgeTextColor(ExtensionAction2::kDefaultTabId, 0xFFFF0000); + action.SetBadgeTextColor(ExtensionAction2::kDefaultTabId, 0xFFFF0000u); ASSERT_EQ(0xFFFF0000u, action.GetBadgeTextColor(1)); ASSERT_EQ(0xFFFF0000u, action.GetBadgeTextColor(100)); action.SetBadgeTextColor(100, 0xFF00FF00); ASSERT_EQ(0xFFFF0000u, action.GetBadgeTextColor(1)); ASSERT_EQ(0xFF00FF00u, action.GetBadgeTextColor(100)); - action.SetBadgeTextColor(ExtensionAction2::kDefaultTabId, 0xFF0000FF); + action.SetBadgeTextColor(ExtensionAction2::kDefaultTabId, 0xFF0000FFu); ASSERT_EQ(0xFF0000FFu, action.GetBadgeTextColor(1)); action.ClearAllValuesForTab(100); ASSERT_EQ(0xFF0000FFu, action.GetBadgeTextColor(100)); // badge background color ASSERT_EQ(0x00000000u, action.GetBadgeBackgroundColor(1)); - action.SetBadgeBackgroundColor(ExtensionAction2::kDefaultTabId, 0xFFFF0000); + action.SetBadgeBackgroundColor(ExtensionAction2::kDefaultTabId, + 0xFFFF0000u); ASSERT_EQ(0xFFFF0000u, action.GetBadgeBackgroundColor(1)); ASSERT_EQ(0xFFFF0000u, action.GetBadgeBackgroundColor(100)); action.SetBadgeBackgroundColor(100, 0xFF00FF00); ASSERT_EQ(0xFFFF0000u, action.GetBadgeBackgroundColor(1)); ASSERT_EQ(0xFF00FF00u, action.GetBadgeBackgroundColor(100)); - action.SetBadgeBackgroundColor(ExtensionAction2::kDefaultTabId, 0xFF0000FF); + action.SetBadgeBackgroundColor(ExtensionAction2::kDefaultTabId, + 0xFF0000FFu); ASSERT_EQ(0xFF0000FFu, action.GetBadgeBackgroundColor(1)); action.ClearAllValuesForTab(100); ASSERT_EQ(0xFF0000FFu, action.GetBadgeBackgroundColor(100)); } - -TEST(ExtensionAction2Test, IconOddCases) { - ExtensionAction2 action; - - action.SetIcon(ExtensionAction2::kDefaultTabId, LoadIcon("icon1.png")); - action.SetDefaultIcon("foo.png"); - ASSERT_TRUE(action.GetIcon(1).isNull()); - ASSERT_EQ("foo.png", action.GetDefaultIconPath()); - - action.icon_paths()->push_back("a.png"); - action.icon_paths()->push_back("b.png"); - action.SetDefaultIcon(1); - ASSERT_TRUE(action.GetIcon(1).isNull()); - ASSERT_EQ("b.png", action.GetDefaultIconPath()); - - action.SetIcon(100, LoadIcon("icon1.png")); - ASSERT_TRUE(!action.GetIcon(100).isNull()); - action.SetIcon(ExtensionAction2::kDefaultTabId, LoadIcon("icon1.png")); - ASSERT_TRUE(!action.GetIcon(1).isNull()); - ASSERT_EQ("", action.GetDefaultIconPath()); -} diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc index eeb4499..dd366fb 100644 --- a/chrome/common/extensions/extension_unittest.cc +++ b/chrome/common/extensions/extension_unittest.cc @@ -297,18 +297,18 @@ TEST(ExtensionTest, LoadPageActionHelper) { #endif Extension extension(path); std::string error_msg; - scoped_ptr<ExtensionAction> action; + scoped_ptr<ExtensionAction2> action; DictionaryValue input; // First try with an empty dictionary. We should get nothing back. - ASSERT_TRUE(extension.LoadExtensionActionHelper( - &input, &error_msg, ExtensionAction::PAGE_ACTION) == NULL); + ASSERT_TRUE(extension.LoadExtensionAction2Helper( + &input, &error_msg) == NULL); ASSERT_STRNE("", error_msg.c_str()); error_msg = ""; // Now try the same, but as a browser action. Ensure same results. - ASSERT_TRUE(extension.LoadExtensionActionHelper( - &input, &error_msg, ExtensionAction::BROWSER_ACTION) == NULL); + ASSERT_TRUE(extension.LoadExtensionAction2Helper( + &input, &error_msg) == NULL); ASSERT_STRNE("", error_msg.c_str()); error_msg = ""; @@ -326,46 +326,23 @@ TEST(ExtensionTest, LoadPageActionHelper) { icons->Set(1, Value::CreateStringValue(img2)); input.Set(keys::kPageActionIcons, icons); - // Parse as page action and read back the values from the object. - action.reset(extension.LoadExtensionActionHelper( - &input, &error_msg, ExtensionAction::PAGE_ACTION)); + // Parse and read back the values from the object. + action.reset(extension.LoadExtensionAction2Helper( + &input, &error_msg)); ASSERT_TRUE(NULL != action.get()); ASSERT_STREQ("", error_msg.c_str()); ASSERT_STREQ(id.c_str(), action->id().c_str()); - ASSERT_STREQ(name.c_str(), action->title().c_str()); - ASSERT_EQ(2u, action->icon_paths().size()); - ASSERT_STREQ(img1.c_str(), action->icon_paths()[0].c_str()); - ASSERT_STREQ(img2.c_str(), action->icon_paths()[1].c_str()); - ASSERT_EQ(ExtensionAction::PAGE_ACTION, action->type()); - - // Now try the same, but as a browser action. - action.reset(extension.LoadExtensionActionHelper( - &input, &error_msg, ExtensionAction::BROWSER_ACTION)); - ASSERT_TRUE(NULL != action.get()); - ASSERT_STREQ("", error_msg.c_str()); - // Browser actions don't have an id, page actions do. - ASSERT_STREQ("", action->id().c_str()); - ASSERT_STREQ(name.c_str(), action->title().c_str()); - ASSERT_EQ(2u, action->icon_paths().size()); - ASSERT_STREQ(img1.c_str(), action->icon_paths()[0].c_str()); - ASSERT_STREQ(img2.c_str(), action->icon_paths()[1].c_str()); - ASSERT_EQ(ExtensionAction::BROWSER_ACTION, action->type()); + ASSERT_STREQ(name.c_str(), action->GetTitle(1).c_str()); + ASSERT_EQ(2u, action->icon_paths()->size()); + ASSERT_STREQ(img1.c_str(), action->icon_paths()->at(0).c_str()); + ASSERT_STREQ(img2.c_str(), action->icon_paths()->at(1).c_str()); // Explicitly set the same type and parse again. input.SetString(keys::kType, values::kPageActionTypeTab); - action.reset(extension.LoadExtensionActionHelper( - &input, &error_msg, ExtensionAction::BROWSER_ACTION)); - ASSERT_TRUE(NULL != action.get()); - ASSERT_STREQ("", error_msg.c_str()); - ASSERT_EQ(ExtensionAction::BROWSER_ACTION, action->type()); - - // Explicitly set the PAGE_ACTION type and parse again. - input.SetString(keys::kType, values::kPageActionTypePermanent); - action.reset(extension.LoadExtensionActionHelper( - &input, &error_msg, ExtensionAction::PAGE_ACTION)); + action.reset(extension.LoadExtensionAction2Helper( + &input, &error_msg)); ASSERT_TRUE(NULL != action.get()); ASSERT_STREQ("", error_msg.c_str()); - ASSERT_EQ(ExtensionAction::PAGE_ACTION, action->type()); // Make a deep copy of the input and remove one key at a time and see if we // get the right error. @@ -374,18 +351,8 @@ TEST(ExtensionTest, LoadPageActionHelper) { // First remove id key. copy.reset(static_cast<DictionaryValue*>(input.DeepCopy())); copy->Remove(keys::kPageActionId, NULL); - action.reset(extension.LoadExtensionActionHelper( - copy.get(), &error_msg, ExtensionAction::PAGE_ACTION)); - ASSERT_TRUE(NULL != action.get()); - ASSERT_STREQ("", error_msg.c_str()); - error_msg = ""; - - // Same test (id key), but with browser action. - copy.reset(static_cast<DictionaryValue*>(input.DeepCopy())); - copy->Remove(keys::kPageActionId, NULL); - action.reset(extension.LoadExtensionActionHelper( - copy.get(), &error_msg, ExtensionAction::BROWSER_ACTION)); - // Having no id is valid for browser actions. + action.reset(extension.LoadExtensionAction2Helper( + copy.get(), &error_msg)); ASSERT_TRUE(NULL != action.get()); ASSERT_STREQ("", error_msg.c_str()); error_msg = ""; @@ -393,18 +360,8 @@ TEST(ExtensionTest, LoadPageActionHelper) { // Then remove the name key. copy.reset(static_cast<DictionaryValue*>(input.DeepCopy())); copy->Remove(keys::kName, NULL); - action.reset(extension.LoadExtensionActionHelper( - copy.get(), &error_msg, ExtensionAction::PAGE_ACTION)); - ASSERT_TRUE(NULL == action.get()); - ASSERT_TRUE(MatchPattern(error_msg.c_str(), - errors::kInvalidPageActionDefaultTitle)); - error_msg = ""; - - // Same test (name key), but with browser action. - copy.reset(static_cast<DictionaryValue*>(input.DeepCopy())); - copy->Remove(keys::kName, NULL); - action.reset(extension.LoadExtensionActionHelper( - copy.get(), &error_msg, ExtensionAction::BROWSER_ACTION)); + action.reset(extension.LoadExtensionAction2Helper( + copy.get(), &error_msg)); ASSERT_TRUE(NULL == action.get()); ASSERT_TRUE(MatchPattern(error_msg.c_str(), errors::kInvalidPageActionDefaultTitle)); @@ -413,18 +370,11 @@ TEST(ExtensionTest, LoadPageActionHelper) { // Then remove the icon paths key. copy.reset(static_cast<DictionaryValue*>(input.DeepCopy())); copy->Remove(keys::kPageActionIcons, NULL); - action.reset(extension.LoadExtensionActionHelper( - copy.get(), &error_msg, ExtensionAction::PAGE_ACTION)); + action.reset(extension.LoadExtensionAction2Helper( + copy.get(), &error_msg)); ASSERT_TRUE(NULL != action.get()); error_msg = ""; - // Same test (name key), but with browser action. - copy.reset(static_cast<DictionaryValue*>(input.DeepCopy())); - copy->Remove(keys::kPageActionIcons, NULL); - action.reset(extension.LoadExtensionActionHelper( - copy.get(), &error_msg, ExtensionAction::BROWSER_ACTION)); - ASSERT_TRUE(NULL != action.get()); - // Now test that we can parse the new format for page actions. // Now setup some values to use in the page action. @@ -436,15 +386,13 @@ TEST(ExtensionTest, LoadPageActionHelper) { input.SetString(keys::kPageActionDefaultTitle, kTitle); input.SetString(keys::kPageActionDefaultIcon, kIcon); - // Parse as page action and read back the values from the object. - action.reset(extension.LoadExtensionActionHelper( - &input, &error_msg, ExtensionAction::PAGE_ACTION)); + // Parse and read back the values from the object. + action.reset(extension.LoadExtensionAction2Helper( + &input, &error_msg)); ASSERT_TRUE(action.get()); ASSERT_STREQ("", error_msg.c_str()); - ASSERT_EQ(kTitle, action->title()); - ASSERT_EQ(1u, action->icon_paths().size()); - ASSERT_EQ(kIcon, action->icon_paths()[0]); - ASSERT_EQ(ExtensionAction::PAGE_ACTION, action->type()); + ASSERT_EQ(kTitle, action->GetTitle(1)); + ASSERT_EQ(0u, action->icon_paths()->size()); } TEST(ExtensionTest, IdIsValid) { diff --git a/chrome/test/data/extensions/samples/test_page_action/background.html b/chrome/test/data/extensions/samples/test_page_action/background.html index b9de03d..2b77a66 100644 --- a/chrome/test/data/extensions/samples/test_page_action/background.html +++ b/chrome/test/data/extensions/samples/test_page_action/background.html @@ -2,15 +2,18 @@ <head> <script> var lastTabId = 0; + var visible = false; chrome.tabs.onUpdated.addListener(function(tabId, p) { lastTabId = tabId; + chrome.pageAction.show(tabId); }); - // Called when the user clicks on the browser action. + // Called when the user clicks on the page action. var clicks = 0; var text = ""; chrome.pageAction.onClicked.addListener(function(_, info) { - chrome.pageAction.setIcon({iconIndex: clicks, tabId: info.tabId}); + chrome.pageAction.setIcon({path: "icon" + (clicks + 1) + ".png", + tabId: info.tabId}); if (clicks % 2) { chrome.pageAction.show(info.tabId); } else { @@ -18,19 +21,7 @@ setTimeout(function() { chrome.pageAction.show(info.tabId); }, 200); } chrome.pageAction.setTitle({title: "click:" + clicks, tabId: info.tabId}); - chrome.pageAction.setBadgeTextColor({ - tabId: info.tabId, - color: [255, 255, clicks * 50, 255] - }); - chrome.pageAction.setBadgeBackgroundColor({ - tabId: info.tabId, - color: [255, clicks * 50, 0, 255] - }); text += clicks.toString(); - chrome.pageAction.setBadgeText({ - tabId: info.tabId, - text: text - }); // We only have 2 icons, but cycle through 3 icons to test the // out-of-bounds index bug. @@ -43,6 +34,10 @@ window.setInterval(function() { // Don't animate while in "click" mode. if (clicks > 0) return; + + // Don't do anything if we don't have a tab yet. + if (lastTabId == 0) return; + i++; chrome.pageAction.setIcon({imageData: draw(i*2, i*4), tabId: lastTabId}); }, 50); diff --git a/chrome/test/data/extensions/samples/test_page_action/icon1.png b/chrome/test/data/extensions/samples/test_page_action/icon1.png Binary files differnew file mode 100755 index 0000000..9a79a46 --- /dev/null +++ b/chrome/test/data/extensions/samples/test_page_action/icon1.png diff --git a/chrome/test/data/extensions/samples/test_page_action/icon2.png b/chrome/test/data/extensions/samples/test_page_action/icon2.png Binary files differnew file mode 100755 index 0000000..8d3f710 --- /dev/null +++ b/chrome/test/data/extensions/samples/test_page_action/icon2.png diff --git a/chrome/test/data/extensions/samples/test_page_action/manifest.json b/chrome/test/data/extensions/samples/test_page_action/manifest.json index 28e0dab..5a374e8 100644 --- a/chrome/test/data/extensions/samples/test_page_action/manifest.json +++ b/chrome/test/data/extensions/samples/test_page_action/manifest.json @@ -5,7 +5,6 @@ "permissions": ["tabs"], "background_page": "background.html", "page_action": { - "default_title": "First icon", - "default_icon": "print_16x16.png" + "default_title": "First icon" } } diff --git a/chrome/test/data/extensions/samples/test_page_action/print_16x16.png b/chrome/test/data/extensions/samples/test_page_action/print_16x16.png Binary files differdeleted file mode 100644 index d145964..0000000 --- a/chrome/test/data/extensions/samples/test_page_action/print_16x16.png +++ /dev/null |