summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/browser_resources.grd7
-rw-r--r--chrome/browser/cocoa/extensions/extension_action_context_menu.h3
-rw-r--r--chrome/browser/cocoa/extensions/extension_action_context_menu.mm5
-rw-r--r--chrome/browser/cocoa/extensions/extension_infobar_controller.h18
-rw-r--r--chrome/browser/cocoa/extensions/extension_infobar_controller.mm169
-rw-r--r--chrome/browser/extensions/extension_infobar_apitest.cc5
-rw-r--r--chrome/browser/resources/extensions_infobar_mac.css13
7 files changed, 201 insertions, 19 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 1b2f708..920e23f 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -33,7 +33,12 @@ without changes to the corresponding grd file. eadee -->
<include name="IDR_DOM_UI2_CSS" file="resources\dom_ui2.css" flattenhtml="true" type="BINDATA" />
<include name="IDR_DOWNLOADS_HTML" file="resources\downloads.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_EXTENSION_DEFAULT_ICON" file="resources\extension_default_icon.png" type="BINDATA" />
- <include name="IDR_EXTENSIONS_INFOBAR_CSS" file="resources\extensions_infobar.css" flattenhtml="true" type="BINDATA" />
+ <if expr="os == 'darwin'">
+ <include name="IDR_EXTENSIONS_INFOBAR_CSS" file="resources\extensions_infobar_mac.css" flattenhtml="true" type="BINDATA" />
+ </if>
+ <if expr="os != 'darwin'">
+ <include name="IDR_EXTENSIONS_INFOBAR_CSS" file="resources\extensions_infobar.css" flattenhtml="true" type="BINDATA" />
+ </if>
<include name="IDR_EXTENSIONS_TOOLSTRIP_THEME_CSS" file="resources\extensions_toolstrip.css" flattenhtml="true" type="BINDATA" />
<include name="IDR_EXTENSIONS_UI_HTML" file="resources\extensions_ui.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_GAIA_LOGIN_HTML" file="sync\resources\gaia_login.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/cocoa/extensions/extension_action_context_menu.h b/chrome/browser/cocoa/extensions/extension_action_context_menu.h
index 52c088e..06c2276 100644
--- a/chrome/browser/cocoa/extensions/extension_action_context_menu.h
+++ b/chrome/browser/cocoa/extensions/extension_action_context_menu.h
@@ -23,8 +23,7 @@ class DevmodeObserver;
} // namespace extension_action_context_menu
-// A context menu used by the Browser and Page Action components that appears
-// if a user right-clicks the view of the given extension.
+// A context menu used by any extension UI components that require it.
@interface ExtensionActionContextMenu : NSMenu {
@private
// The extension that this menu belongs to. Weak.
diff --git a/chrome/browser/cocoa/extensions/extension_action_context_menu.mm b/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
index 1622451..1b954a6 100644
--- a/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
+++ b/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
@@ -243,6 +243,7 @@ int CurrentTabId() {
(AutocompleteTextField*)locationBar->location_entry()->
GetNativeView();
AutocompleteTextFieldCell* fieldCell = [field autocompleteTextFieldCell];
+ DCHECK(action_);
NSRect popupRect =
[fieldCell pageActionFrameForExtensionAction:action_
inFrame:[field bounds]];
@@ -276,8 +277,8 @@ int CurrentTabId() {
}
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
- if([menuItem isEqualTo: inspectorItem_.get()]) {
- return (action_->HasPopup(CurrentTabId()));
+ if([menuItem isEqualTo:inspectorItem_.get()]) {
+ return action_ && action_->HasPopup(CurrentTabId());
}
return YES;
}
diff --git a/chrome/browser/cocoa/extensions/extension_infobar_controller.h b/chrome/browser/cocoa/extensions/extension_infobar_controller.h
index 93b7e57..c1dd730 100644
--- a/chrome/browser/cocoa/extensions/extension_infobar_controller.h
+++ b/chrome/browser/cocoa/extensions/extension_infobar_controller.h
@@ -9,12 +9,30 @@
#import <Cocoa/Cocoa.h>
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+@class ExtensionActionContextMenu;
+class ExtensionInfoBarDelegate;
+class InfobarBridge;
+@class MenuButton;
+
@interface ExtensionInfoBarController : InfoBarController {
// The native extension view retrieved from the extension host. Weak.
NSView* extensionView_;
// The window containing this InfoBar. Weak.
NSWindow* window_;
+
+ // The InfoBar's button with the Extension's icon that launches the context
+ // menu.
+ scoped_nsobject<MenuButton> dropdownButton_;
+
+ // The context menu that pops up when the left button is clicked.
+ scoped_nsobject<ExtensionActionContextMenu> contextMenu_;
+
+ // Helper class to bridge C++ and ObjC functionality together for the infobar.
+ scoped_ptr<InfobarBridge> bridge_;
}
@end
diff --git a/chrome/browser/cocoa/extensions/extension_infobar_controller.mm b/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
index 1a65161..f9599fa 100644
--- a/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
+++ b/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
@@ -4,30 +4,155 @@
#import "chrome/browser/cocoa/extensions/extension_infobar_controller.h"
+#include <cmath>
+
+#include "app/resource_bundle.h"
#import "chrome/browser/cocoa/animatable_view.h"
+#import "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
+#import "chrome/browser/cocoa/menu_button.h"
#include "chrome/browser/cocoa/infobar.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "gfx/canvas_skia.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
namespace {
const CGFloat kAnimationDuration = 0.12;
const CGFloat kBottomBorderHeightPx = 1.0;
-} // namepsace
+const CGFloat kButtonHeightPx = 26.0;
+const CGFloat kButtonLeftMarginPx = 2.0;
+const CGFloat kButtonWidthPx = 34.0;
+const CGFloat kDropArrowLeftMarginPx = 3.0;
+const CGFloat kToolbarMinHeightPx = 36.0;
+const CGFloat kToolbarMaxHeightPx = 72.0;
+} // namespace
@interface ExtensionInfoBarController(Private)
// Called when the extension's hosted NSView has been resized.
- (void)extensionViewFrameChanged;
-// Adjusts the width of the extension's hosted view to match the window's width.
-- (void)adjustWidthToFitWindow;
+// Returns the clamped height of the extension view to be within the min and max
+// values defined above.
+- (CGFloat)clampedExtensionViewHeight;
+// Adjusts the width of the extension's hosted view to match the window's width
+// and sets the proper height for it as well.
+- (void)adjustExtensionViewSize;
+// Sets the image to be used in the button on the left side of the infobar.
+- (void)setButtonImage:(NSImage*)image;
@end
+// A helper class to bridge the asynchronous Skia bitmap loading mechanism to
+// the extension's button.
+class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver,
+ public ImageLoadingTracker::Observer {
+ public:
+ explicit InfobarBridge(ExtensionInfoBarController* owner)
+ : owner_(owner),
+ delegate_([owner delegate]->AsExtensionInfoBarDelegate()),
+ tracker_(this) {
+ delegate_->set_observer(this);
+ LoadIcon();
+ }
+
+ virtual ~InfobarBridge() {
+ if (delegate_)
+ delegate_->set_observer(NULL);
+ }
+
+ // Load the Extension's icon image.
+ void LoadIcon() {
+ ExtensionResource icon_resource;
+ Extension* extension = delegate_->extension_host()->extension();
+ Extension::Icons size =
+ extension->GetIconPathAllowLargerSize(&icon_resource,
+ Extension::EXTENSION_ICON_BITTY);
+ if (!icon_resource.relative_path().empty()) {
+ tracker_.LoadImage(extension, icon_resource, gfx::Size(size, size),
+ ImageLoadingTracker::DONT_CACHE);
+ } else {
+ OnImageLoaded(NULL, icon_resource, 0);
+ }
+ }
+
+ // ImageLoadingTracker::Observer implementation.
+ // TODO(andybons): The infobar view implementations share a lot of the same
+ // code. Come up with a strategy to share amongst them.
+ virtual void OnImageLoaded(
+ SkBitmap* image, ExtensionResource resource, int index) {
+ if (!delegate_)
+ return; // The delegate can go away while the image asynchronously loads.
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ // Fall back on the default extension icon on failure.
+ SkBitmap* icon;
+ if (!image || image->empty())
+ icon = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
+ else
+ icon = image;
+
+ SkBitmap* drop_image = rb.GetBitmapNamed(IDR_APP_DROPARROW);
+
+ const int image_size = Extension::EXTENSION_ICON_BITTY;
+ scoped_ptr<gfx::CanvasSkia> canvas(
+ new gfx::CanvasSkia(
+ image_size + kDropArrowLeftMarginPx + drop_image->width(),
+ image_size, false));
+ canvas->DrawBitmapInt(*icon,
+ 0, 0, icon->width(), icon->height(),
+ 0, 0, image_size, image_size,
+ false);
+ canvas->DrawBitmapInt(*drop_image,
+ image_size + kDropArrowLeftMarginPx,
+ image_size / 2);
+ [owner_ setButtonImage:gfx::SkBitmapToNSImage(canvas->ExtractBitmap())];
+ }
+
+ // Overridden from ExtensionInfoBarDelegate::DelegateObserver:
+ virtual void OnDelegateDeleted() {
+ delegate_ = NULL;
+ }
+
+ private:
+ // Weak. Owns us.
+ ExtensionInfoBarController* owner_;
+
+ // Weak.
+ ExtensionInfoBarDelegate* delegate_;
+
+ // Loads the extensions's icon on the file thread.
+ ImageLoadingTracker tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(InfobarBridge);
+};
+
+
@implementation ExtensionInfoBarController
- (id)initWithDelegate:(InfoBarDelegate*)delegate
window:(NSWindow*)window {
if ((self = [super initWithDelegate:delegate])) {
window_ = window;
+ dropdownButton_.reset([[MenuButton alloc] init]);
+
+ ExtensionHost* extensionHost = delegate_->AsExtensionInfoBarDelegate()->
+ extension_host();
+ contextMenu_.reset([[ExtensionActionContextMenu alloc]
+ initWithExtension:extensionHost->extension()
+ profile:extensionHost->profile()
+ extensionAction:NULL]);
+ // See menu_button.h for documentation on why this is needed.
+ NSMenuItem* dummyItem =
+ [[[NSMenuItem alloc] initWithTitle:@""
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [contextMenu_ insertItem:dummyItem atIndex:0];
+ [dropdownButton_ setAttachedMenu:contextMenu_.get()];
+
+ bridge_.reset(new InfobarBridge(self));
}
return self;
}
@@ -40,8 +165,8 @@ const CGFloat kBottomBorderHeightPx = 1.0;
- (void)addAdditionalControls {
[self removeButtons];
- extensionView_ = delegate_->AsExtensionInfoBarDelegate()->
- extension_host()->view()->native_view();
+ extensionView_ = delegate_->AsExtensionInfoBarDelegate()->extension_host()->
+ view()->native_view();
// Add the extension's RenderWidgetHostViewMac to the view hierarchy of the
// InfoBar and make sure to place it below the Close button.
@@ -49,6 +174,17 @@ const CGFloat kBottomBorderHeightPx = 1.0;
positioned:NSWindowBelow
relativeTo:(NSView*)closeButton_];
+ // Add the context menu button to the hierarchy.
+ [dropdownButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ CGFloat buttonY =
+ std::floor(NSMidY([infoBarView_ frame]) - (kButtonHeightPx / 2.0)) +
+ kBottomBorderHeightPx;
+ NSRect buttonFrame = NSMakeRect(
+ kButtonLeftMarginPx, buttonY, kButtonWidthPx, kButtonHeightPx);
+ [dropdownButton_ setFrame:buttonFrame];
+ [dropdownButton_ setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin];
+ [infoBarView_ addSubview:dropdownButton_];
+
// Because the parent view has a bottom border, account for it during
// positioning.
NSRect extensionFrame = [extensionView_ frame];
@@ -61,14 +197,15 @@ const CGFloat kBottomBorderHeightPx = 1.0;
// needed is because the extension view's frame will not have changed in the
// above case, so the NSViewFrameDidChangeNotification registered below will
// never fire.
- if (extensionFrame.size.height > 0.0) {
+ if (NSHeight(extensionFrame) > 0.0) {
NSSize infoBarSize = [[self view] frame].size;
- infoBarSize.height = extensionFrame.size.height + kBottomBorderHeightPx;
+ infoBarSize.height = [self clampedExtensionViewHeight] +
+ kBottomBorderHeightPx;
[[self view] setFrameSize:infoBarSize];
[infoBarView_ setFrameSize:infoBarSize];
}
- [self adjustWidthToFitWindow];
+ [self adjustExtensionViewSize];
// These two notification handlers are here to ensure the width of the
// native extension view is the same as the browser window's width and that
@@ -87,11 +224,11 @@ const CGFloat kBottomBorderHeightPx = 1.0;
}
- (void)extensionViewFrameChanged {
- [self adjustWidthToFitWindow];
+ [self adjustExtensionViewSize];
AnimatableView* view = [self animatableView];
NSRect infoBarFrame = [view frame];
- CGFloat newHeight = NSHeight([extensionView_ frame]) + kBottomBorderHeightPx;
+ CGFloat newHeight = [self clampedExtensionViewHeight] + kBottomBorderHeightPx;
[infoBarView_ setPostsFrameChangedNotifications:NO];
infoBarFrame.size.height = newHeight;
[infoBarView_ setFrame:infoBarFrame];
@@ -99,14 +236,24 @@ const CGFloat kBottomBorderHeightPx = 1.0;
[view animateToNewHeight:newHeight duration:kAnimationDuration];
}
-- (void)adjustWidthToFitWindow {
+- (CGFloat)clampedExtensionViewHeight {
+ return std::max(kToolbarMinHeightPx,
+ std::min(NSHeight([extensionView_ frame]), kToolbarMaxHeightPx));
+}
+
+- (void)adjustExtensionViewSize {
[extensionView_ setPostsFrameChangedNotifications:NO];
NSSize extensionViewSize = [extensionView_ frame].size;
extensionViewSize.width = NSWidth([window_ frame]);
+ extensionViewSize.height = [self clampedExtensionViewHeight];
[extensionView_ setFrameSize:extensionViewSize];
[extensionView_ setPostsFrameChangedNotifications:YES];
}
+- (void)setButtonImage:(NSImage*)image {
+ [dropdownButton_ setImage:image];
+}
+
@end
InfoBar* ExtensionInfoBarDelegate::CreateInfoBar() {
diff --git a/chrome/browser/extensions/extension_infobar_apitest.cc b/chrome/browser/extensions/extension_infobar_apitest.cc
index 47f726e..a7afb17 100644
--- a/chrome/browser/extensions/extension_infobar_apitest.cc
+++ b/chrome/browser/extensions/extension_infobar_apitest.cc
@@ -6,11 +6,10 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
-#if defined(TOOLKIT_VIEWS)
+#if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
#define MAYBE_Infobars Infobars
#else
-// Need to port ExtensionInfoBarDelegate::CreateInfoBar() to other platforms.
-// See http://crbug.com/39916 for details.
+// Need to finish port to Linux. See http://crbug.com/39916 for details.
#define MAYBE_Infobars DISABLED_Infobars
#endif
diff --git a/chrome/browser/resources/extensions_infobar_mac.css b/chrome/browser/resources/extensions_infobar_mac.css
new file mode 100644
index 0000000..c2a9bbe
--- /dev/null
+++ b/chrome/browser/resources/extensions_infobar_mac.css
@@ -0,0 +1,13 @@
+/**
+ * The following style rules affect Extension Infobars on the Mac.
+ */
+
+body {
+ background: -webkit-gradient(linear, left top, left bottom,
+ from(#EBEBEB), to(#CFCFCF));
+ font-family: 'Lucida Grande', Helvetica, sans-serif;
+ font-size: 11px;
+ height: 36px; /* Infobars are limited to 36-72px */
+ margin: 0px;
+ overflow: hidden;
+}