diff options
Diffstat (limited to 'chrome')
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; +} |