diff options
Diffstat (limited to 'chrome/browser/extensions')
9 files changed, 138 insertions, 36 deletions
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index 60fe23e..5fede2e 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc @@ -13,6 +13,8 @@ #include "chrome/browser/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_error_reporter.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 @@ -116,6 +118,7 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, } if (client_.get()) { + DecodeInstallIcon(); ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &CrxInstaller::ConfirmInstall)); } else { @@ -123,16 +126,60 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, } } -void CrxInstaller::ConfirmInstall() { - if (!client_->ConfirmInstall(extension_.get())) { - // We're done. Since we don't post any more tasks to ourselves, our ref - // count should go to zero and we die. The destructor will clean up the temp - // dir. +void CrxInstaller::DecodeInstallIcon() { + std::map<int, std::string>::const_iterator iter = + extension_->icons().find(128); + if (iter == extension_->icons().end()) + return; + + FilePath path = extension_->GetResourcePath(iter->second); + std::string file_contents; + if (!file_util::ReadFileToString(path, &file_contents)) { + LOG(ERROR) << "Could not read icon file: " + << WideToUTF8(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(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; + } + + install_icon_.reset(decoded.release()); +} + +void CrxInstaller::ConfirmInstall() { + AddRef(); // balanced in ContinueInstall() and AbortInstall(). + + client_->ConfirmInstall(this, extension_.get(), install_icon_.get()); +} + +void CrxInstaller::ContinueInstall() { file_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &CrxInstaller::CompleteInstall)); + + Release(); // balanced in ConfirmInstall(). +} + +void CrxInstaller::AbortInstall() { + Release(); // balanced in ConfirmInstall(). + + // We're done. Since we don't post any more tasks to ourself, our ref count + // should go to zero and we die. The destructor will clean up the temp dir. } void CrxInstaller::CompleteInstall() { @@ -156,15 +203,23 @@ void CrxInstaller::CompleteInstall() { return; } - extension_->set_path(version_dir); - extension_->set_location(install_source_); - if (install_type == Extension::REINSTALL) { // We use this as a signal to switch themes. ReportOverinstallFromFileThread(); return; } + // This is lame, but we must reload the extension because absolute paths + // inside the content scripts are established inside InitFromValue() and we + // just moved the extension. + // TODO(aa): All paths to resources inside extensions should be created + // lazily and based on the Extension's root path at that moment. + std::string error; + extension_.reset(extension_file_util::LoadExtension(version_dir, true, + &error)); + DCHECK(error.empty()); + extension_->set_location(install_source_); + ReportSuccessFromFileThread(); } diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h index 5c373d9..0ea8398 100644 --- a/chrome/browser/extensions/crx_installer.h +++ b/chrome/browser/extensions/crx_installer.h @@ -14,6 +14,9 @@ #include "chrome/browser/extensions/sandboxed_extension_unpacker.h" #include "chrome/common/extensions/extension.h" +class CrxInstaller; +class SkBitmap; + // Classes that want to know about install completion, or that want to have an // opportunity to reject the unpacked extension before installation, should // implement this interface. @@ -22,8 +25,17 @@ class CrxInstallerClient public: virtual ~CrxInstallerClient() {} - // Return true to indicate that installation should proceed, false otherwise. - virtual bool ConfirmInstall(Extension* extension) = 0; + // This is called by the installer to verify whether the installation should + // proceed. Clients can use this time to put up UI, or to do any checks they + // need to on the unpacked extension. + // + // Clients *MUST* eventually call either ContinueInstall() or AbortInstall() + // on |installer|. + // + // Clients should not AddRef() |installer|. + virtual void ConfirmInstall(CrxInstaller* installer, + Extension* extension, + SkBitmap* icon) = 0; // Installation was successful. virtual void OnInstallSuccess(Extension* extension) = 0; @@ -79,6 +91,14 @@ class CrxInstaller : public SandboxedExtensionUnpackerClient { ExtensionsService* frontend, CrxInstallerClient* client); + // Clients should call this method after ConfirmInstall() if they want the + // installation to continue. + void ContinueInstall(); + + // Clients should call this method after ConfirmInstall() if they want the + // installation to stop. + void AbortInstall(); + private: CrxInstaller(const FilePath& crx_path, const FilePath& install_directory, @@ -96,6 +116,10 @@ class CrxInstaller : public SandboxedExtensionUnpackerClient { const FilePath& extension_dir, Extension* extension); + // Read the icon from the extension if present and decode it into + // install_icon_. + void DecodeInstallIcon(); + // Runs on the UI thread. Confirms with the user (via CrxInstallerClient) that // it is OK to install this extension. void ConfirmInstall(); @@ -145,6 +169,9 @@ class CrxInstaller : public SandboxedExtensionUnpackerClient { // ExtensionsService on success, or delete it on failure. scoped_ptr<Extension> extension_; + // The icon we will display in the installation UI, if any. + scoped_ptr<SkBitmap> install_icon_; + // The temp directory extension resources were unpacked to. We own this and // must delete it when we are done with it. FilePath temp_dir_; diff --git a/chrome/browser/extensions/extension_file_util.cc b/chrome/browser/extensions/extension_file_util.cc index b46404c..9020b1b 100644 --- a/chrome/browser/extensions/extension_file_util.cc +++ b/chrome/browser/extensions/extension_file_util.cc @@ -254,13 +254,12 @@ Extension* LoadExtension(const FilePath& extension_path, bool require_key, for (PageActionMap::const_iterator i(page_actions.begin()); i != page_actions.end(); ++i) { PageAction* page_action = i->second; - const std::vector<FilePath>& icon_paths = page_action->icon_paths(); - for (std::vector<FilePath>::const_iterator iter = icon_paths.begin(); + 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) { - FilePath path = *iter; - if (!file_util::PathExists(path)) { + if (!file_util::PathExists(extension->GetResourcePath(*iter))) { *error = StringPrintf("Could not load icon '%s' for page action.", - WideToUTF8(path.ToWStringHack()).c_str()); + iter->c_str()); return NULL; } } diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc index 4416701..135aac7 100644 --- a/chrome/browser/extensions/extension_install_ui.cc +++ b/chrome/browser/extensions/extension_install_ui.cc @@ -4,12 +4,17 @@ #include "chrome/browser/extensions/extension_install_ui.h" +#include <map> + #include "app/l10n_util.h" -#include "grit/chromium_strings.h" +#include "base/file_util.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/theme_preview_infobar_delegate.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/extensions/extension.h" +#include "grit/chromium_strings.h" #if defined(OS_WIN) #include "app/win_util.h" @@ -23,24 +28,24 @@ ExtensionInstallUI::ExtensionInstallUI(Profile* profile) : profile_(profile), ui_loop_(MessageLoop::current()) { } -bool ExtensionInstallUI::ConfirmInstall(Extension* extension) { +void ExtensionInstallUI::ConfirmInstall(CrxInstaller* installer, + Extension* extension, + SkBitmap* install_icon) { DCHECK(ui_loop_ == MessageLoop::current()); // We special-case themes to not show any confirm UI. Instead they are // immediately installed, and then we show an infobar (see OnInstallSuccess) // to allow the user to revert if they don't like it. - if (extension->IsTheme()) - return true; + if (extension->IsTheme()) { + installer->ContinueInstall(); + return; + } #if defined(OS_WIN) - if (win_util::MessageBox(GetForegroundWindow(), - L"Are you sure you want to install this extension?\n\n" - L"You should only install extensions from sources you trust.", - l10n_util::GetString(IDS_PRODUCT_NAME).c_str(), - MB_OKCANCEL) != IDOK) { - return false; - } + ShowExtensionInstallPrompt(profile_, installer, extension, install_icon); + #elif defined(OS_MACOSX) + // TODO(port): Implement nicer UI. // Using CoreFoundation to do this dialog is unimaginably lame but will do // until the UI is redone. scoped_cftyperef<CFStringRef> product_name( @@ -53,13 +58,15 @@ bool ExtensionInstallUI::ConfirmInstall(Extension* extension) { "This is a temporary message and it will be removed when " "extensions UI is finalized."), NULL, CFSTR("Cancel"), NULL, &response)) { - return false; + installer->AbortInstall(); + } else { + installer->ContinueInstall(); } #else + // TODO(port): Implement some UI. NOTREACHED(); + installer->ContinueInstall(); #endif // OS_* - - return true; } void ExtensionInstallUI::OnInstallSuccess(Extension* extension) { diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h index 1fc0379..9cdc5ac 100644 --- a/chrome/browser/extensions/extension_install_ui.h +++ b/chrome/browser/extensions/extension_install_ui.h @@ -16,16 +16,20 @@ class Profile; class SandboxedExtensionUnpacker; // Displays all the UI around extension installation. -// -// TODO(aa): This will become a view and move to browser/views/extensions in the -// future. class ExtensionInstallUI : public CrxInstallerClient { public: + // NOTE: The implementation of this is platform-specific. + static void ShowExtensionInstallPrompt(Profile* profile, + CrxInstaller* installer, + Extension* extension, + SkBitmap* install_icon); + ExtensionInstallUI(Profile* profile); private: // CrxInstallerClient - virtual bool ConfirmInstall(Extension* extension); + virtual void ConfirmInstall(CrxInstaller* installer, Extension* extension, + SkBitmap* icon); virtual void OnInstallSuccess(Extension* extension); virtual void OnInstallFailure(const std::string& error); virtual void OnOverinstallAttempted(Extension* extension); diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index 08a99a4..7b4d061 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -213,7 +213,7 @@ void ExtensionPrefs::OnExtensionInstalled(Extension* extension) { FilePath::StringType path = MakePathRelative(install_directory_, extension->path(), NULL); UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path)); - prefs_->ScheduleSavePersistentPrefs(); + prefs_->SavePersistentPrefs(); } void ExtensionPrefs::OnExtensionUninstalled(const Extension* extension, diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc index 46a8382..c736f39 100644 --- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc +++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc @@ -119,6 +119,13 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded( // originals are gone for good. extension_.reset(new Extension); std::string manifest_error; + + // Update the path to refer to the temporary location. We do this because + // clients may want to use resources inside the extension before it is + // installed and they need the correct path. For example, the install UI shows + // one of the icons from the extension. + extension_->set_path(extension_root_); + if (!extension_->InitFromValue(*final_manifest, true, // require id &manifest_error)) { ReportFailure(std::string("Manifest is invalid: ") + diff --git a/chrome/browser/extensions/theme_preview_infobar_delegate.cc b/chrome/browser/extensions/theme_preview_infobar_delegate.cc index d22ebda..a1a179f 100644 --- a/chrome/browser/extensions/theme_preview_infobar_delegate.cc +++ b/chrome/browser/extensions/theme_preview_infobar_delegate.cc @@ -21,7 +21,7 @@ void ThemePreviewInfobarDelegate::InfoBarClosed() { } std::wstring ThemePreviewInfobarDelegate::GetMessageText() const { - return l10n_util::GetStringF(IDS_THEME_PREVIEW_INFOBAR_LABEL, + return l10n_util::GetStringF(IDS_THEME_INSTALL_INFOBAR_LABEL, UTF8ToWide(name_)); } @@ -44,7 +44,7 @@ std::wstring ThemePreviewInfobarDelegate::GetButtonLabel( ConfirmInfoBarDelegate::InfoBarButton button) const { switch (button) { case BUTTON_CANCEL: - return l10n_util::GetString(IDS_THEME_PREVIEW_INFOBAR_UNDO_BUTTON); + return l10n_util::GetString(IDS_THEME_INSTALL_INFOBAR_UNDO_BUTTON); default: return L""; } diff --git a/chrome/browser/extensions/theme_preview_infobar_delegate.h b/chrome/browser/extensions/theme_preview_infobar_delegate.h index 54a8507..dcc34b6 100644 --- a/chrome/browser/extensions/theme_preview_infobar_delegate.h +++ b/chrome/browser/extensions/theme_preview_infobar_delegate.h @@ -14,6 +14,9 @@ class TabContents; // When a user installs a theme, we display it immediately, but provide an // infobar allowing them to cancel. +// +// TODO(aa): Rename this to ThemeInstalledInfoBarDelegate, since it isn't +// used for previewing anymore. class ThemePreviewInfobarDelegate : public ConfirmInfoBarDelegate { public: ThemePreviewInfobarDelegate(TabContents* tab_contents, |