diff options
author | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-17 05:55:32 +0000 |
---|---|---|
committer | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-17 05:55:32 +0000 |
commit | c690a981436bb6a6d69ab8df959ffa5b116bf356 (patch) | |
tree | dfb4134472778bdb6409679faec3fea2e4946633 /chrome | |
parent | 5d39e314de21a384eaa226d4875b6a6e8e1bea17 (diff) | |
download | chromium_src-c690a981436bb6a6d69ab8df959ffa5b116bf356.zip chromium_src-c690a981436bb6a6d69ab8df959ffa5b116bf356.tar.gz chromium_src-c690a981436bb6a6d69ab8df959ffa5b116bf356.tar.bz2 |
Add the right-click context menu for Browser actions and Page Actions.
BUG=29538
TEST=Right-click an extension icon and make sure all the options work for both
Page and Browser actions (Options should be grayed out when there is no Options
page specified in the manifest).
Review URL: http://codereview.chromium.org/486022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34812 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/app/generated_resources.grd | 3 | ||||
-rw-r--r-- | chrome/browser/extensions/crx_installer.cc | 41 | ||||
-rw-r--r-- | chrome/browser/extensions/crx_installer.h | 5 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_action_context_menu_model.cc | 105 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_action_context_menu_model.h | 40 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_disabled_infobar_delegate.cc | 4 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_ui.cc | 5 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.cc | 35 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.h | 16 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_action_context_menu.cc | 34 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_action_context_menu.h | 38 | ||||
-rw-r--r-- | chrome/browser/views/location_bar_view.cc | 22 | ||||
-rw-r--r-- | chrome/browser/views/location_bar_view.h | 4 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 6 | ||||
-rw-r--r-- | chrome/common/extensions/extension.cc | 45 | ||||
-rw-r--r-- | chrome/common/extensions/extension.h | 12 |
16 files changed, 350 insertions, 65 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 4b6485e..8083f06 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -2632,6 +2632,9 @@ each locale. --> This icon will be visible when the extension can act on the current page. </message> + <message name="IDS_MANAGE_EXTENSIONS" desc="The 'Manage Extensions...' text in the context menu for when right-clicking on extension icons"> + Manage extensions... + </message> <message name="IDS_EXTENSION_INSTALLED_MANAGE_INFO" desc="Text displayed in the InfoBubble with instructives on how to find the chrome://extensions/ management page"> You can manage your installed extensions by clicking Extensions in the Tools menu. </message> diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index bfd6ef4..ca01297 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc @@ -18,7 +18,6 @@ #include "chrome/common/notification_type.h" #include "grit/chromium_strings.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "webkit/glue/image_decoder.h" namespace { // Helper function to delete files. This is used to avoid ugly casts which @@ -155,50 +154,14 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, } if (client_.get()) { - FilePath icon_path = - extension_->GetIconPath(Extension::EXTENSION_ICON_LARGE).GetFilePath(); - DecodeInstallIcon(icon_path, &install_icon_); + Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE, + &install_icon_); } ChromeThread::PostTask( ChromeThread::UI, FROM_HERE, NewRunnableMethod(this, &CrxInstaller::ConfirmInstall)); } -// static -void CrxInstaller::DecodeInstallIcon(const FilePath& large_icon_path, - scoped_ptr<SkBitmap>* result) { - if (large_icon_path.empty()) - return; - - std::string file_contents; - if (!file_util::ReadFileToString(large_icon_path, &file_contents)) { - LOG(ERROR) << "Could not read icon file: " - << WideToUTF8(large_icon_path.ToWStringHack()); - return; - } - - // Decode the image using WebKit's image decoder. - const unsigned char* data = - reinterpret_cast<const unsigned char*>(file_contents.data()); - webkit_glue::ImageDecoder decoder; - scoped_ptr<SkBitmap> decoded(new SkBitmap()); - *decoded = decoder.Decode(data, file_contents.length()); - if (decoded->empty()) { - LOG(ERROR) << "Could not decode icon file: " - << WideToUTF8(large_icon_path.ToWStringHack()); - return; - } - - if (decoded->width() != 128 || decoded->height() != 128) { - LOG(ERROR) << "Icon file has unexpected size: " - << IntToString(decoded->width()) << "x" - << IntToString(decoded->height()); - return; - } - - result->swap(decoded); -} - void CrxInstaller::ConfirmInstall() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); if (frontend_->extension_prefs()->IsExtensionBlacklisted(extension_->id())) { diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h index 2f0843e..30f0cd5 100644 --- a/chrome/browser/extensions/crx_installer.h +++ b/chrome/browser/extensions/crx_installer.h @@ -71,11 +71,6 @@ class CrxInstaller ExtensionsService* frontend, ExtensionInstallUI* client); - // Given the path to the large icon from an extension, read it if present and - // decode it into result. - static void DecodeInstallIcon(const FilePath& large_icon_path, - scoped_ptr<SkBitmap>* result); - // ExtensionInstallUI::Delegate virtual void InstallUIProceed(); virtual void InstallUIAbort(); diff --git a/chrome/browser/extensions/extension_action_context_menu_model.cc b/chrome/browser/extensions/extension_action_context_menu_model.cc new file mode 100644 index 0000000..e2713f7 --- /dev/null +++ b/chrome/browser/extensions/extension_action_context_menu_model.cc @@ -0,0 +1,105 @@ +// 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/extensions/extension_action_context_menu_model.h" + +#include "app/l10n_util.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/profile.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/url_constants.h" +#include "grit/generated_resources.h" + +enum MenuEntries { + NAME = 0, + CONFIGURE, + DISABLE, + UNINSTALL, + MANAGE, +}; + +ExtensionActionContextMenuModel::ExtensionActionContextMenuModel( + Extension* extension, ExtensionInstallUI::Delegate* delegate) + : ALLOW_THIS_IN_INITIALIZER_LIST(SimpleMenuModel(this)), + extension_(extension), + delegate_(delegate) { + AddItem(NAME, ASCIIToUTF16(extension->name())); + AddSeparator(); + AddItemWithStringId(CONFIGURE, IDS_EXTENSIONS_OPTIONS); + AddItemWithStringId(DISABLE, IDS_EXTENSIONS_DISABLE); + AddItemWithStringId(UNINSTALL, IDS_EXTENSIONS_UNINSTALL); + AddSeparator(); + + // TODO(finnur): It is too late in the process to do another round of + // translations, so we'll switch fully to IDS_MANAGE_EXTENSIONS after merging + // this to the beta branch. :/ + std::string locale = g_browser_process->GetApplicationLocale(); + if (locale.find_first_of("en-") == 0) + AddItemWithStringId(MANAGE, IDS_MANAGE_EXTENSIONS); + else + AddItemWithStringId(MANAGE, IDS_SHOW_EXTENSIONS); +} + +ExtensionActionContextMenuModel::~ExtensionActionContextMenuModel() { +} + +bool ExtensionActionContextMenuModel::IsCommandIdChecked(int command_id) const { + return false; +} + +bool ExtensionActionContextMenuModel::IsCommandIdEnabled(int command_id) const { + if (command_id == CONFIGURE) + return extension_->options_url().spec().length() > 0; + return true; +} + +bool ExtensionActionContextMenuModel::GetAcceleratorForCommandId( + int command_id, menus::Accelerator* accelerator) { + return false; +} + +void ExtensionActionContextMenuModel::ExecuteCommand(int command_id) { + // TODO(finnur): GetLastActive returns NULL in unit tests. + Browser* browser = BrowserList::GetLastActive(); + Profile* profile = browser->profile(); + + switch (command_id) { + case NAME: { + GURL url(std::string(extension_urls::kGalleryBrowsePrefix) + + std::string("/detail/") + extension_->id()); + browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); + break; + } + case CONFIGURE: + DCHECK(!extension_->options_url().is_empty()); + browser->OpenURL(extension_->options_url(), GURL(), + NEW_FOREGROUND_TAB, PageTransition::LINK); + break; + case DISABLE: { + ExtensionsService* extension_service = profile->GetExtensionsService(); + extension_service->DisableExtension(extension_->id()); + break; + } + case UNINSTALL: { + scoped_ptr<SkBitmap> uninstall_icon; + Extension::DecodeIcon(extension_, Extension::EXTENSION_ICON_LARGE, + &uninstall_icon); + + ExtensionInstallUI client(profile); + client.ConfirmUninstall(delegate_, extension_, uninstall_icon.get()); + break; + } + case MANAGE: { + browser->OpenURL(GURL(chrome::kChromeUIExtensionsURL), GURL(), + NEW_FOREGROUND_TAB, PageTransition::LINK); + break; + } + default: + NOTREACHED() << "Unknown option"; + break; + } +} diff --git a/chrome/browser/extensions/extension_action_context_menu_model.h b/chrome/browser/extensions/extension_action_context_menu_model.h new file mode 100644 index 0000000..62bfdc6 --- /dev/null +++ b/chrome/browser/extensions/extension_action_context_menu_model.h @@ -0,0 +1,40 @@ +// 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. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_MODEL_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_MODEL_H_ + +#include "app/menus/simple_menu_model.h" +#include "chrome/browser/extensions/extension_install_ui.h" + +class Extension; + +// The menu model for the context menu for extension action icons (browser and +// page actions). +class ExtensionActionContextMenuModel + : public menus::SimpleMenuModel, + public menus::SimpleMenuModel::Delegate { + public: + ExtensionActionContextMenuModel(Extension* extension, + ExtensionInstallUI::Delegate* delegate); + ~ExtensionActionContextMenuModel(); + + // SimpleMenuModel behavior overrides. + virtual bool IsCommandIdChecked(int command_id) const; + virtual bool IsCommandIdEnabled(int command_id) const; + virtual bool GetAcceleratorForCommandId(int command_id, + menus::Accelerator* accelerator); + virtual void ExecuteCommand(int command_id); + + private: + // The extension we are displaying the context menu for. + Extension* extension_; + + // The delegate that handles the extension Uninstall operation. + ExtensionInstallUI::Delegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionActionContextMenuModel); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_MODEL_H_ diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc index 54d2ed9..a1012c0 100644 --- a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc +++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc @@ -6,7 +6,6 @@ #include "app/l10n_util.h" #include "chrome/browser/chrome_thread.h" -#include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_file_util.h" #include "chrome/browser/extensions/extension_install_ui.h" #include "chrome/browser/extensions/extensions_service.h" @@ -55,7 +54,8 @@ class ExtensionDisabledDialogDelegate void Start() { // We start on the file thread so we can decode the install icon. FilePath install_icon_path = install_icon_resource_.GetFilePath(); - CrxInstaller::DecodeInstallIcon(install_icon_path, &install_icon_); + Extension::DecodeIconFromPath( + install_icon_path, Extension::EXTENSION_ICON_LARGE, &install_icon_); // Then we display the UI on the UI thread. ChromeThread::PostTask( ChromeThread::UI, FROM_HERE, diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index b762d1f..a18cb7a 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -404,10 +404,9 @@ void ExtensionsDOMHandler::HandleUninstallMessage(const Value* value) { if (!extension) return; - FilePath icon_path = - extension->GetIconPath(Extension::EXTENSION_ICON_LARGE).GetFilePath(); scoped_ptr<SkBitmap> uninstall_icon; - CrxInstaller::DecodeInstallIcon(icon_path, &uninstall_icon); + Extension::DecodeIcon(extension, Extension::EXTENSION_ICON_LARGE, + &uninstall_icon); extension_id_uninstalling_ = extension_id; ExtensionInstallUI client(dom_ui_->GetProfile()); diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc index ccbc581..e593f83 100644 --- a/chrome/browser/views/browser_actions_container.cc +++ b/chrome/browser/views/browser_actions_container.cc @@ -56,10 +56,11 @@ BrowserActionButton::BrowserActionButton(Extension* extension, browser_action_(extension->browser_action()), extension_(extension), tracker_(NULL), + showing_context_menu_(false), panel_(panel) { set_alignment(TextButton::ALIGN_CENTER); - // No UpdateState() here because View heirarchy not setup yet. Our parent + // No UpdateState() here because View hierarchy not setup yet. Our parent // should call UpdateState() after creation. registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, @@ -155,14 +156,32 @@ bool BrowserActionButton::Activate() { } bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) { - if (IsPopup()) + showing_context_menu_ = e.IsRightMouseButton(); + if (showing_context_menu_) { + SetButtonPushed(); + + // Get the top left point of this button in screen coordinates. + gfx::Point point = gfx::Point(0, 0); + ConvertPointToScreen(this, &point); + + // Make the menu appear below the button. + point.Offset(0, height()); + + if (!context_menu_.get()) + context_menu_.reset(new ExtensionActionContextMenu()); + context_menu_->Run(extension(), point); + + SetButtonNotPushed(); + return false; + } else if (IsPopup()) { return MenuButton::OnMousePressed(e); + } return TextButton::OnMousePressed(e); } void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e, bool canceled) { - if (IsPopup()) { + if (IsPopup() || showing_context_menu_) { // TODO(erikkay) this never actually gets called (probably because of the // loss of focus). MenuButton::OnMouseReleased(e, canceled); @@ -178,18 +197,18 @@ bool BrowserActionButton::OnKeyReleased(const views::KeyEvent& e) { } void BrowserActionButton::OnMouseExited(const views::MouseEvent& e) { - if (IsPopup()) + if (IsPopup() || showing_context_menu_) MenuButton::OnMouseExited(e); else TextButton::OnMouseExited(e); } -void BrowserActionButton::PopupDidShow() { +void BrowserActionButton::SetButtonPushed() { SetState(views::CustomButton::BS_PUSHED); menu_visible_ = true; } -void BrowserActionButton::PopupDidHide() { +void BrowserActionButton::SetButtonNotPushed() { SetState(views::CustomButton::BS_NORMAL); menu_visible_ = false; } @@ -350,7 +369,7 @@ void BrowserActionsContainer::HidePopup() { closing_popup->DetachFromBrowser(); delete closing_popup; - closing_button->PopupDidHide(); + closing_button->SetButtonNotPushed(); return; } } @@ -396,7 +415,7 @@ void BrowserActionsContainer::OnBrowserActionExecuted( true); // Activate the popup window. popup_->set_delegate(this); popup_button_ = button; - popup_button_->PopupDidShow(); + popup_button_->SetButtonPushed(); return; } diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h index 2499007..dbbd248 100644 --- a/chrome/browser/views/browser_actions_container.h +++ b/chrome/browser/views/browser_actions_container.h @@ -10,6 +10,7 @@ #include "base/task.h" #include "chrome/browser/extensions/image_loading_tracker.h" #include "chrome/browser/views/browser_bubble.h" +#include "chrome/browser/views/extensions/extension_action_context_menu.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" #include "views/controls/button/menu_button.h" @@ -42,7 +43,7 @@ class BrowserActionButton : public views::MenuButton, // Called to update the display to match the browser action's state. void UpdateState(); - // Overriden from views::View. Return a 0-inset so the icon can draw all the + // Overridden from views::View. Return a 0-inset so the icon can draw all the // way to the edge of the view if it wants. virtual gfx::Insets GetInsets() const; @@ -71,9 +72,10 @@ class BrowserActionButton : public views::MenuButton, // Does this button's action have a popup? virtual bool IsPopup(); - // Notifications when the popup is hidden or shown by the container. - virtual void PopupDidShow(); - virtual void PopupDidHide(); + // Notifications when to set button state to pushed/not pushed (for when the + // popup/context menu is hidden or shown by the container). + virtual void SetButtonPushed(); + virtual void SetButtonNotPushed(); private: // The browser action this view represents. The ExtensionAction is not owned @@ -88,6 +90,12 @@ class BrowserActionButton : public views::MenuButton, // and takes care of deleting itself. ImageLoadingTracker* tracker_; + // The context menu for browser action icons. + scoped_ptr<ExtensionActionContextMenu> context_menu_; + + // Whether we are currently showing/just finished showing a context menu. + bool showing_context_menu_; + // The default icon for our browser action. This might be non-empty if the // browser action had a value for default_icon in the manifest. SkBitmap default_icon_; diff --git a/chrome/browser/views/extensions/extension_action_context_menu.cc b/chrome/browser/views/extensions/extension_action_context_menu.cc new file mode 100644 index 0000000..dbf7c07 --- /dev/null +++ b/chrome/browser/views/extensions/extension_action_context_menu.cc @@ -0,0 +1,34 @@ +// 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/views/extensions/extension_action_context_menu.h" + +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/profile.h" + +ExtensionActionContextMenu::ExtensionActionContextMenu() + : extension_(NULL) { +} + +ExtensionActionContextMenu::~ExtensionActionContextMenu() { +} + +void ExtensionActionContextMenu::Run(Extension* extension, + const gfx::Point& point) { + extension_ = extension; + + context_menu_contents_.reset( + new ExtensionActionContextMenuModel(extension, this)); + context_menu_menu_.reset(new views::Menu2(context_menu_contents_.get())); + context_menu_menu_->RunContextMenuAt(point); +} + +void ExtensionActionContextMenu::InstallUIProceed() { + // TODO(finnur): GetLastActive returns NULL in unit tests. + Browser* browser = BrowserList::GetLastActive(); + std::string id = extension_->id(); + browser->profile()->GetExtensionsService()->UninstallExtension(id, false); +} diff --git a/chrome/browser/views/extensions/extension_action_context_menu.h b/chrome/browser/views/extensions/extension_action_context_menu.h new file mode 100644 index 0000000..92ac97c --- /dev/null +++ b/chrome/browser/views/extensions/extension_action_context_menu.h @@ -0,0 +1,38 @@ +// 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. + +#ifndef CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_ +#define CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_ + +#include "views/controls/menu/menu_2.h" +#include "chrome/browser/extensions/extension_install_ui.h" +#include "chrome/browser/extensions/extension_action_context_menu_model.h" + +class Extension; + +// Displays the context menu for extension action icons (browser/page actions). +class ExtensionActionContextMenu : public ExtensionInstallUI::Delegate { + public: + ExtensionActionContextMenu(); + ~ExtensionActionContextMenu(); + + // Display the context menu at a given point. + void Run(Extension* extension, const gfx::Point& point); + + // ExtensionInstallUI::Delegate overrides. + virtual void InstallUIProceed(); + virtual void InstallUIAbort() {} + + private: + // The options menu. + scoped_ptr<ExtensionActionContextMenuModel> context_menu_contents_; + scoped_ptr<views::Menu2> context_menu_menu_; + + // The extension we are showing the menu for. + Extension* extension_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionActionContextMenu); +}; + +#endif // CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_ diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index d8c41e0..004656d 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -1379,12 +1379,26 @@ void LocationBarView::PageActionImageView::OnMouseMoved( bool LocationBarView::PageActionImageView::OnMousePressed( const views::MouseEvent& event) { int button = -1; - if (event.IsLeftMouseButton()) + if (event.IsLeftMouseButton()) { button = 1; - else if (event.IsMiddleMouseButton()) + } else if (event.IsMiddleMouseButton()) { button = 2; - else if (event.IsRightMouseButton()) - button = 3; + } else if (event.IsRightMouseButton()) { + // Get the top left point of this button in screen coordinates. + gfx::Point point = gfx::Point(0,0); + ConvertPointToScreen(this, &point); + + // Make the menu appear below the button. + point.Offset(0, height()); + + Extension* extension = profile_->GetExtensionsService()->GetExtensionById( + page_action()->extension_id(), false); + + if (!context_menu_.get()) + context_menu_.reset(new ExtensionActionContextMenu()); + context_menu_->Run(extension, point); + return false; + } ExecuteAction(button); return true; diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h index 85d1d89..3319c39 100644 --- a/chrome/browser/views/location_bar_view.h +++ b/chrome/browser/views/location_bar_view.h @@ -18,6 +18,7 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/toolbar_model.h" #include "chrome/browser/views/browser_bubble.h" +#include "chrome/browser/views/extensions/extension_action_context_menu.h" #include "chrome/browser/views/info_bubble.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" @@ -428,6 +429,9 @@ class LocationBarView : public LocationBar, typedef std::map<std::string, SkBitmap> PageActionMap; PageActionMap page_action_icons_; + // The context menu for this page action. + scoped_ptr<ExtensionActionContextMenu> context_menu_; + // The object that is waiting for the image loading to complete // asynchronously. ImageLoadingTracker* tracker_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 71224bd..7779dd1 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -644,6 +644,8 @@ 'browser/download/save_types.h', 'browser/encoding_menu_controller.cc', 'browser/encoding_menu_controller.h', + 'browser/extensions/extension_action_context_menu_model.cc', + 'browser/extensions/extension_action_context_menu_model.h', 'browser/extensions/convert_user_script.cc', 'browser/extensions/convert_user_script.h', 'browser/extensions/crashed_extension_infobar.cc', @@ -1623,6 +1625,8 @@ 'browser/views/edit_search_engine_dialog.h', 'browser/views/event_utils.cc', 'browser/views/event_utils.h', + 'browser/views/extensions/extension_action_context_menu.cc', + 'browser/views/extensions/extension_action_context_menu.h', 'browser/views/extensions/extension_install_prompt.cc', 'browser/views/extensions/extension_installed_bubble.cc', 'browser/views/extensions/extension_installed_bubble.h', @@ -2162,6 +2166,8 @@ ['include', '^browser/views/dropdown_bar_view.h'], ['include', '^browser/views/event_utils.cc'], ['include', '^browser/views/event_utils.h'], + ['include', '^browser/views/extensions/extension_action_context_menu.cc'], + ['include', '^browser/views/extensions/extension_action_context_menu.h'], ['include', '^browser/views/extensions/extension_install_prompt.cc'], ['include', '^browser/views/extensions/extension_installed_bubble.cc'], ['include', '^browser/views/extensions/extension_installed_bubble.h'], diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index 280ad98..4ed91b58 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -24,6 +24,7 @@ #include "chrome/common/extensions/user_script.h" #include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" +#include "webkit/glue/image_decoder.h" #if defined(OS_WIN) #include "base/registry.h" @@ -641,6 +642,50 @@ bool Extension::IsPrivilegeIncrease(Extension* old_extension, return false; } +// static +void Extension::DecodeIcon(Extension* extension, + Icons icon_size, + scoped_ptr<SkBitmap>* result) { + FilePath icon_path = extension->GetIconPath(icon_size).GetFilePath(); + DecodeIconFromPath(icon_path, icon_size, result); +} + +// static +void Extension::DecodeIconFromPath(const FilePath& icon_path, + Icons icon_size, + scoped_ptr<SkBitmap>* result) { + if (icon_path.empty()) + return; + + std::string file_contents; + if (!file_util::ReadFileToString(icon_path, &file_contents)) { + LOG(ERROR) << "Could not read icon file: " + << WideToUTF8(icon_path.ToWStringHack()); + return; + } + + // Decode the image using WebKit's image decoder. + const unsigned char* data = + reinterpret_cast<const unsigned char*>(file_contents.data()); + webkit_glue::ImageDecoder decoder; + scoped_ptr<SkBitmap> decoded(new SkBitmap()); + *decoded = decoder.Decode(data, file_contents.length()); + if (decoded->empty()) { + LOG(ERROR) << "Could not decode icon file: " + << WideToUTF8(icon_path.ToWStringHack()); + return; + } + + if (decoded->width() != icon_size || decoded->height() != icon_size) { + LOG(ERROR) << "Icon file has unexpected size: " + << IntToString(decoded->width()) << "x" + << IntToString(decoded->height()); + return; + } + + result->swap(decoded); +} + bool Extension::InitFromValue(const DictionaryValue& source, bool require_id, std::string* error) { if (source.HasKey(keys::kPublicKey)) { diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index d1b1aad..2fc25e5 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -178,6 +178,18 @@ class Extension { static bool IsPrivilegeIncrease(Extension* old_extension, Extension* new_extension); + // Given an extension and icon size, read it if present and decode it into + // result. + static void DecodeIcon(Extension* extension, + Icons icon_size, + scoped_ptr<SkBitmap>* result); + + // Given an icon_path and icon size, read it if present and decode it into + // result. + static void DecodeIconFromPath(const FilePath& icon_path, + Icons icon_size, + scoped_ptr<SkBitmap>* result); + // Initialize the extension from a parsed manifest. // If |require_id| is true, will return an error if the "id" key is missing // from the value. |