diff options
Diffstat (limited to 'chrome/browser')
13 files changed, 386 insertions, 69 deletions
diff --git a/chrome/browser/extensions/browser_action_apitest.cc b/chrome/browser/extensions/browser_action_apitest.cc index 5a7c086..e5a4650 100644 --- a/chrome/browser/extensions/browser_action_apitest.cc +++ b/chrome/browser/extensions/browser_action_apitest.cc @@ -37,7 +37,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BrowserAction) { // Test that we received the changes. ExtensionActionState* action_state = extension->browser_action_state(); ASSERT_EQ("Modified", action_state->title()); - ASSERT_EQ(1, action_state->icon_index()); ASSERT_EQ("badge", action_state->badge_text()); ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255), action_state->badge_background_color()); diff --git a/chrome/browser/extensions/extension_browser_actions_api.cc b/chrome/browser/extensions/extension_browser_actions_api.cc index e7d875e..5cf68e8 100644 --- a/chrome/browser/extensions/extension_browser_actions_api.cc +++ b/chrome/browser/extensions/extension_browser_actions_api.cc @@ -18,10 +18,8 @@ const char kIconIndexOutOfBounds[] = } bool BrowserActionSetIconFunction::RunImpl() { - // setIcon can take a variant argument: either a canvas ImageData, or an - // icon index. - EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_BINARY) || - args_->IsType(Value::TYPE_DICTIONARY)); + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + const DictionaryValue* args = static_cast<const DictionaryValue*>(args_); Extension* extension = dispatcher()->GetExtension(); if (!extension->browser_action()) { @@ -29,28 +27,28 @@ bool BrowserActionSetIconFunction::RunImpl() { return false; } - if (args_->IsType(Value::TYPE_BINARY)) { - BinaryValue* binary = static_cast<BinaryValue*>(args_); + // setIcon can take a variant argument: either a canvas ImageData, or an + // icon index. + BinaryValue* binary; + int icon_index; + if (args->GetBinary(L"imageData", &binary)) { IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize()); void* iter = NULL; scoped_ptr<SkBitmap> bitmap(new SkBitmap); EXTENSION_FUNCTION_VALIDATE( IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get())); extension->browser_action_state()->set_icon(bitmap.release()); - } else { - int icon_index = -1; - EXTENSION_FUNCTION_VALIDATE( - static_cast<DictionaryValue*>(args_)->GetInteger( - L"iconIndex", &icon_index)); + } else if (args->GetInteger(L"iconIndex", &icon_index)) { + if (icon_index < 0 || static_cast<size_t>(icon_index) >= - if (icon_index < 0 || - static_cast<size_t>(icon_index) >= extension->browser_action()->icon_paths().size()) { error_ = kIconIndexOutOfBounds; return false; } extension->browser_action_state()->set_icon_index(icon_index); extension->browser_action_state()->set_icon(NULL); + } else { + EXTENSION_FUNCTION_VALIDATE(false); } NotificationService::current()->Notify( diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 1870701..ffbac6c 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -101,6 +101,13 @@ void FactoryRegistry::ResetFunctions() { // Page Actions. RegisterFunction<EnablePageActionFunction>(); RegisterFunction<DisablePageActionFunction>(); + RegisterFunction<PageActionShowFunction>(); + RegisterFunction<PageActionHideFunction>(); + RegisterFunction<PageActionSetIconFunction>(); + RegisterFunction<PageActionSetTitleFunction>(); + RegisterFunction<PageActionSetBadgeBackgroundColorFunction>(); + RegisterFunction<PageActionSetBadgeTextColorFunction>(); + RegisterFunction<PageActionSetBadgeTextFunction>(); // Browser Actions. RegisterFunction<BrowserActionSetIconFunction>(); diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc index 51866e3..60eb86a 100644 --- a/chrome/browser/extensions/extension_page_actions_module.cc +++ b/chrome/browser/extensions/extension_page_actions_module.cc @@ -15,9 +15,21 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_error_utils.h" +#include "chrome/common/render_messages.h" namespace keys = extension_page_actions_module_constants; +namespace { +// Errors. +const char kNoExtensionError[] = "No extension with id: *."; +const char kNoTabError[] = "No tab with id: *."; +const char kNoPageActionError[] = + "This extension has no page action specified."; +const char kUrlNotActiveError[] = "This url is no longer active: *."; +const char kIconIndexOutOfBounds[] = "Page action icon index out of bounds."; +} + +// TODO(EXTENSIONS_DEPRECATED): obsolete API. bool PageActionFunction::SetPageActionEnabled(bool enable) { EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST)); const ListValue* args = static_cast<const ListValue*>(args_); @@ -48,7 +60,7 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { TabContents* contents = NULL; ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, &contents, NULL); if (!contents) { - error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNoTabError, + error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError, IntToString(tab_id)); return false; } @@ -56,8 +68,7 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { // Make sure the URL hasn't changed. NavigationEntry* entry = contents->controller().GetActiveEntry(); if (!entry || url != entry->url().spec()) { - error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kUrlNotActiveError, - url); + error_ = ExtensionErrorUtils::FormatErrorMessage(kUrlNotActiveError, url); return false; } @@ -66,22 +77,52 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { ExtensionsService* service = profile()->GetExtensionsService(); extension = service->GetExtensionById(extension_id()); if (!extension) { - error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNoExtensionError, + error_ = ExtensionErrorUtils::FormatErrorMessage(kNoExtensionError, extension_id()); return false; } const ExtensionAction* page_action = extension->page_action(); if (!page_action) { - error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNoPageActionError, - page_action_id); + error_ = kNoPageActionError; return false; } // Set visibility and broadcast notifications that the UI should be updated. contents->SetPageActionEnabled(page_action, enable, title, icon_id); - contents->NotifyNavigationStateChanged(TabContents::INVALIDATE_PAGE_ACTIONS); + contents->PageActionStateChanged(); + + return true; +} + +bool PageActionFunction::InitCommon(int tab_id) { + page_action_ = dispatcher()->GetExtension()->page_action(); + if (!page_action_) { + error_ = kNoPageActionError; + return false; + } + + // Find the TabContents that contains this tab id. + contents_ = NULL; + ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, &contents_, NULL); + if (!contents_) { + error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError, + IntToString(tab_id)); + return false; + } + + state_ = contents_->GetOrCreatePageActionState(page_action_); + return true; +} + +bool PageActionFunction::SetHidden(bool hidden) { + int tab_id; + EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&tab_id)); + if (!InitCommon(tab_id)) + return false; + state_->set_hidden(hidden); + contents_->PageActionStateChanged(); return true; } @@ -92,3 +133,126 @@ bool EnablePageActionFunction::RunImpl() { bool DisablePageActionFunction::RunImpl() { return SetPageActionEnabled(false); } + +bool PageActionShowFunction::RunImpl() { + return SetHidden(false); +} + +bool PageActionHideFunction::RunImpl() { + return SetHidden(true); +} + +bool PageActionSetIconFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + const DictionaryValue* args = static_cast<const DictionaryValue*>(args_); + + int tab_id; + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id)); + if (!InitCommon(tab_id)) + return false; + + // setIcon can take a variant argument: either a canvas ImageData, or an + // icon index. + BinaryValue* binary; + int icon_index; + if (args->GetBinary(L"imageData", &binary)) { + IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize()); + void* iter = NULL; + scoped_ptr<SkBitmap> bitmap(new SkBitmap); + EXTENSION_FUNCTION_VALIDATE( + IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get())); + state_->set_icon(bitmap.release()); + } else if (args->GetInteger(L"iconIndex", &icon_index)) { + 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); + } else { + EXTENSION_FUNCTION_VALIDATE(false); + } + + contents_->PageActionStateChanged(); + return true; +} + +bool PageActionSetTitleFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + const DictionaryValue* args = static_cast<const DictionaryValue*>(args_); + + int tab_id; + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id)); + if (!InitCommon(tab_id)) + return false; + + std::string title; + EXTENSION_FUNCTION_VALIDATE(args->GetString(L"title", &title)); + + state_->set_title(title); + contents_->PageActionStateChanged(); + return true; +} + +bool PageActionSetBadgeBackgroundColorFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + const DictionaryValue* args = static_cast<const DictionaryValue*>(args_); + + int tab_id; + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id)); + if (!InitCommon(tab_id)) + return false; + + ListValue* color_value; + EXTENSION_FUNCTION_VALIDATE(args->GetList(L"color", &color_value)); + EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4); + + int color_array[4] = {0}; + for (size_t i = 0; i < arraysize(color_array); ++i) + EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i])); + + SkColor color = SkColorSetARGB(color_array[0], color_array[1], color_array[2], + color_array[3]); + state_->set_badge_background_color(color); + contents_->PageActionStateChanged(); + return true; +} + +bool PageActionSetBadgeTextColorFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + const DictionaryValue* args = static_cast<const DictionaryValue*>(args_); + + int tab_id; + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id)); + if (!InitCommon(tab_id)) + return false; + + ListValue* color_value; + EXTENSION_FUNCTION_VALIDATE(args->GetList(L"color", &color_value)); + EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4); + + int color_array[4] = {0}; + for (size_t i = 0; i < arraysize(color_array); ++i) + EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i])); + + // TODO(mpcomplete): implement text coloring. + return true; +} + +bool PageActionSetBadgeTextFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + const DictionaryValue* args = static_cast<const DictionaryValue*>(args_); + + int tab_id; + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id)); + if (!InitCommon(tab_id)) + return false; + + std::string text; + EXTENSION_FUNCTION_VALIDATE(args->GetString(L"text", &text)); + + state_->set_badge_text(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 6a85cc3..f3ac6f0 100644 --- a/chrome/browser/extensions/extension_page_actions_module.h +++ b/chrome/browser/extensions/extension_page_actions_module.h @@ -7,9 +7,20 @@ #include "chrome/browser/extensions/extension_function.h" +class TabContents; +class ExtensionAction; +class ExtensionActionState; + class PageActionFunction : public SyncExtensionFunction { protected: bool SetPageActionEnabled(bool enable); + + bool InitCommon(int tab_id); + bool SetHidden(bool hidden); + + ExtensionAction* page_action_; + TabContents* contents_; + ExtensionActionState* state_; }; class EnablePageActionFunction : public PageActionFunction { @@ -22,4 +33,39 @@ class DisablePageActionFunction : public PageActionFunction { DECLARE_EXTENSION_FUNCTION_NAME("pageActions.disableForTab") }; +class PageActionShowFunction : public PageActionFunction { + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("pageAction.show") +}; + +class PageActionHideFunction : public PageActionFunction { + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("pageAction.hide") +}; + +class PageActionSetIconFunction : public PageActionFunction { + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("pageAction.setIcon") +}; + +class PageActionSetTitleFunction : public PageActionFunction { + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("pageAction.setTitle") +}; + +class PageActionSetBadgeBackgroundColorFunction : public PageActionFunction { + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("pageAction.setBadgeBackgroundColor") +}; + +class PageActionSetBadgeTextColorFunction : public PageActionFunction { + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("pageAction.setBadgeTextColor") +}; + +class PageActionSetBadgeTextFunction : public PageActionFunction { + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("pageAction.setBadgeText") +}; + #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PAGE_ACTIONS_MODULE_H_ diff --git a/chrome/browser/extensions/extension_page_actions_module_constants.cc b/chrome/browser/extensions/extension_page_actions_module_constants.cc index 48ceaae..8690c94 100644 --- a/chrome/browser/extensions/extension_page_actions_module_constants.cc +++ b/chrome/browser/extensions/extension_page_actions_module_constants.cc @@ -12,9 +12,4 @@ const wchar_t kTitleKey[] = L"title"; const wchar_t kIconIdKey[] = L"iconId"; const wchar_t kButtonKey[] = L"button"; -const char kNoExtensionError[] = "No extension with id: *."; -const char kNoTabError[] = "No tab with id: *."; -const char kNoPageActionError[] = "No PageAction with id: *."; -const char kUrlNotActiveError[] = "This url is no longer active: *."; - } // namespace extension_page_actions_module_constants diff --git a/chrome/browser/extensions/extension_page_actions_module_constants.h b/chrome/browser/extensions/extension_page_actions_module_constants.h index 16556d6..5bb435e 100644 --- a/chrome/browser/extensions/extension_page_actions_module_constants.h +++ b/chrome/browser/extensions/extension_page_actions_module_constants.h @@ -16,12 +16,6 @@ extern const wchar_t kTitleKey[]; extern const wchar_t kIconIdKey[]; extern const wchar_t kButtonKey[]; -// Error messages. -extern const char kNoExtensionError[]; -extern const char kNoTabError[]; -extern const char kNoPageActionError[]; -extern const char kUrlNotActiveError[]; - }; // namespace extension_page_actions_module_constants #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PAGE_ACTIONS_MODULE_CONSTANTS_H_ diff --git a/chrome/browser/extensions/page_action_apitest.cc b/chrome/browser/extensions/page_action_apitest.cc new file mode 100644 index 0000000..3996de7 --- /dev/null +++ b/chrome/browser/extensions/page_action_apitest.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2009 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/browser.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/extensions/extension_browser_event_router.h" +#include "chrome/browser/extensions/extension_tabs_module.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/profile.h" +#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/test/ui_test_utils.h" + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageAction) { + StartHTTPServer(); + ASSERT_TRUE(RunExtensionTest("page_action")) << message_; + + ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ASSERT_EQ(1u, service->extensions()->size()); + Extension* extension = service->extensions()->at(0); + ASSERT_TRUE(extension); + + { + // Tell the extension to update the page action state. + ResultCatcher catcher; + ui_test_utils::NavigateToURL(browser(), + GURL(extension->GetResourceURL("update.html"))); + ASSERT_TRUE(catcher.GetNextResult()); + } + + // 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()); + EXPECT_EQ("badge", action_state->badge_text()); + EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), + action_state->badge_background_color()); + + { + // Simulate the page action being clicked. + ResultCatcher catcher; + int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents()); + ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted( + browser()->profile(), extension->id(), "", tab_id, "", 0); + EXPECT_TRUE(catcher.GetNextResult()); + } + + { + // Tell the extension to update the page action state again. + ResultCatcher catcher; + ui_test_utils::NavigateToURL(browser(), + GURL(extension->GetResourceURL("update2.html"))); + ASSERT_TRUE(catcher.GetNextResult()); + } + + // Test that we received the changes. + action_state = browser()->GetSelectedTabContents()->GetPageActionState( + extension->page_action()); + EXPECT_TRUE(action_state->icon()); +} diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc index cd7aeefe..78bbd04 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -676,7 +676,9 @@ LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk( const ExtensionAction* page_action) : owner_(owner), profile_(profile), - page_action_(page_action) { + page_action_(page_action), + last_icon_skbitmap_(NULL), + last_icon_pixbuf_(NULL) { event_box_.Own(gtk_event_box_new()); // Make the event box not visible so it does not paint a background. gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE); @@ -709,6 +711,8 @@ LocationBarViewGtk::PageActionViewGtk::~PageActionViewGtk() { if (pixbufs_[i]) g_object_unref(pixbufs_[i]); } + if (last_icon_pixbuf_) + g_object_unref(last_icon_pixbuf_); } void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility( @@ -720,7 +724,7 @@ void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility( const ExtensionActionState* state = contents->GetPageActionState(page_action_); - bool visible = state != NULL; + bool visible = state && !state->hidden(); if (visible) { // Set the tooltip. if (state->title().empty()) @@ -728,14 +732,30 @@ void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility( page_action_->title().c_str()); else gtk_widget_set_tooltip_text(event_box_.get(), state->title().c_str()); + // Set the image. - 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; + SkBitmap* icon = state->icon(); + GdkPixbuf* pixbuf = NULL; + if (icon) { + if (icon != last_icon_skbitmap_) { + if (last_icon_pixbuf_) + g_object_unref(last_icon_pixbuf_); + last_icon_skbitmap_ = 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]; + } + // The pixbuf might not be loaded yet. - if (pixbufs_[index]) - gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbufs_[index]); + if (pixbuf) + gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbuf); else visible = false; } diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h index 3fe531a..32a5f9e 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.h +++ b/chrome/browser/gtk/location_bar_view_gtk.h @@ -134,6 +134,12 @@ class LocationBarViewGtk : public AutocompleteEditController, // The icons representing different states for the page action. std::vector<GdkPixbuf*> 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_; + GdkPixbuf* last_icon_pixbuf_; + // The object that is waiting for the image loading to complete // asynchronously. It will delete itself once it is done. ImageLoadingTracker* tracker_; diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index a526207..43c7c27 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -609,26 +609,33 @@ void TabContents::SetPageActionEnabled(const ExtensionAction* page_action, const std::string& title, int icon_id) { DCHECK(page_action); - - if (!enable && - enabled_page_actions_.end() == enabled_page_actions_.find(page_action)) { - return; // Don't need to disable twice. - } - - if (enable) { - enabled_page_actions_[page_action].reset( - new ExtensionActionState(title, icon_id)); - } else { - enabled_page_actions_.erase(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 (enabled_page_actions_.end() == enabled_page_actions_.find(page_action)) + if (page_actions_.end() == page_actions_.find(page_action)) return NULL; - return enabled_page_actions_[page_action].get(); + 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); } void TabContents::NotifyNavigationStateChanged(unsigned changed_flags) { @@ -1400,12 +1407,12 @@ void TabContents::DidNavigateMainFramePostCommit( fav_icon_helper_.FetchFavIcon(details.entry->url()); // Disable all page actions, unless this is an in-page navigation. - if (!enabled_page_actions_.empty()) { + if (!page_actions_.empty()) { url_canon::Replacements<char> replacements; replacements.ClearRef(); if (params.url.ReplaceComponents(replacements) != params.referrer.ReplaceComponents(replacements)) { - enabled_page_actions_.clear(); + page_actions_.clear(); } } @@ -2625,4 +2632,3 @@ void TabContents::Observe(NotificationType type, void TabContents::set_encoding(const std::string& encoding) { encoding_ = CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding); } - diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 99db09c..47b4243 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -269,6 +269,16 @@ class TabContents : public PageNavigator, 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. + void PageActionStateChanged(); + // Whether the tab is in the process of being destroyed. // Added as a tentative work-around for focus related bug #4633. This allows // us not to store focus when a tab is being closed. @@ -1111,12 +1121,13 @@ class TabContents : public PageNavigator, // Data for Page Actions ----------------------------------------------------- - // A map of page actions that are enabled in this tab (and a state object - // that can be used to override the title and icon used for the page action). - // This map is cleared every time the mainframe navigates and populated by the - // PageAction extension API. - std::map< const ExtensionAction*, linked_ptr<ExtensionActionState> > - enabled_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 ---------------------------------------------- diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index 324cf60..437862f 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -1245,19 +1245,24 @@ void LocationBarView::PageActionImageView::UpdateVisibility( const ExtensionActionState* state = contents->GetPageActionState(page_action_); - bool visible = state != NULL; + bool visible = state && !state->hidden(); if (visible) { // Set the tooltip. if (state->title().empty()) tooltip_ = page_action_->title(); else tooltip_ = state->title(); + // Set the image. - 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; - ImageView::SetImage(page_action_icons_[index]); + 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]; + } + ImageView::SetImage(icon); } SetVisible(visible); } |