summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-27 01:56:20 +0000
committerthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-27 01:56:20 +0000
commita1104b0a2fac7b6a49524d28a82f63947d3f8ef3 (patch)
tree24816a393c5ae4e5b7eba3ef0585ba2002ea0bca
parent35b176f29a575774b3127d4ebe120861ad529b4c (diff)
downloadchromium_src-a1104b0a2fac7b6a49524d28a82f63947d3f8ef3.zip
chromium_src-a1104b0a2fac7b6a49524d28a82f63947d3f8ef3.tar.gz
chromium_src-a1104b0a2fac7b6a49524d28a82f63947d3f8ef3.tar.bz2
mac: Correctly use the mask image for the new tab button.
The mask is used to cut out the new tab background image from the tab background bitmap. Bake masked background image plus overlay into a new NSImage and give that to image_button_cell. Teach image_button_cell to handle images in addition to image ids. Remove the broken direct support for mask images from image_button_cell. Teach image_button_cell about different images in non-focused windows. BUG=52468 TEST=look at new tab button. install a theme, new tab button updates immediately. uninstall it again. Review URL: https://codereview.chromium.org/11677002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@174653 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ui/cocoa/image_button_cell.h14
-rw-r--r--chrome/browser/ui/cocoa/image_button_cell.mm71
-rw-r--r--chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm132
3 files changed, 161 insertions, 56 deletions
diff --git a/chrome/browser/ui/cocoa/image_button_cell.h b/chrome/browser/ui/cocoa/image_button_cell.h
index 7b3e8b8..8d64c1e 100644
--- a/chrome/browser/ui/cocoa/image_button_cell.h
+++ b/chrome/browser/ui/cocoa/image_button_cell.h
@@ -7,6 +7,8 @@
#import <Cocoa/Cocoa.h>
+#include "base/memory/scoped_nsobject.h"
+
namespace image_button_cell {
// Possible states
@@ -15,7 +17,9 @@ enum ButtonState {
kHoverState,
kPressedState,
kDisabledState,
- kMaskState,
+ // The same as above, but for non-main, non-key windows.
+ kDefaultStateBackground,
+ kHoverStateBackground,
kButtonStateCount
};
@@ -32,7 +36,7 @@ enum ButtonState {
// state. Images are specified by image IDs.
@interface ImageButtonCell : NSButtonCell {
@private
- NSInteger imageID_[image_button_cell::kButtonStateCount];
+ scoped_nsobject<NSImage> image_[image_button_cell::kButtonStateCount];
NSInteger overlayImageID_;
BOOL isMouseInside_;
}
@@ -41,10 +45,14 @@ enum ButtonState {
@property(assign, nonatomic) BOOL isMouseInside;
// Sets the image for the given button state using an image ID.
-// The image will be lazy loaded from a resource pak.
+// The image will be loaded from a resource pak.
- (void)setImageID:(NSInteger)imageID
forButtonState:(image_button_cell::ButtonState)state;
+// Sets the image for the given button state using an image.
+- (void)setImage:(NSImage*)image
+ forButtonState:(image_button_cell::ButtonState)state;
+
@end
#endif // CHROME_BROWSER_UI_COCOA_IMAGE_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/image_button_cell.mm b/chrome/browser/ui/cocoa/image_button_cell.mm
index 1c71e7b..a574e53 100644
--- a/chrome/browser/ui/cocoa/image_button_cell.mm
+++ b/chrome/browser/ui/cocoa/image_button_cell.mm
@@ -7,6 +7,7 @@
#include "base/logging.h"
#import "chrome/browser/themes/theme_service.h"
#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
namespace {
@@ -61,9 +62,20 @@ const CGFloat kImageNoFocusAlpha = 0.65;
BOOL windowHasFocus = [[controlView window] isMainWindow] ||
[[controlView window] isKeyWindow];
CGFloat alpha = windowHasFocus ? 1.0 : kImageNoFocusAlpha;
+ NSImage* image = image_[[self currentButtonState]];
+
+ if (!windowHasFocus) {
+ if ([self currentButtonState] == image_button_cell::kDefaultState &&
+ image_[image_button_cell::kDefaultStateBackground]) {
+ image = image_[image_button_cell::kDefaultStateBackground];
+ alpha = 1.0;
+ } else if ([self currentButtonState] == image_button_cell::kHoverState &&
+ image_[image_button_cell::kHoverStateBackground]) {
+ image = image_[image_button_cell::kHoverStateBackground];
+ alpha = 1.0;
+ }
+ }
- NSImage* image = [self imageForID:imageID_[[self currentButtonState]]
- controlView:controlView];
NSRect imageRect;
imageRect.size = [image size];
imageRect.origin.x = cellFrame.origin.x +
@@ -71,36 +83,12 @@ const CGFloat kImageNoFocusAlpha = 0.65;
imageRect.origin.y = cellFrame.origin.y +
roundf((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
- if (!imageID_[image_button_cell::kMaskState] ||
- [self currentButtonState] == image_button_cell::kPressedState) {
- [image drawInRect:imageRect
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:alpha
- respectFlipped:YES
- hints:nil];
- } else {
- image = [self imageForID:imageID_[image_button_cell::kMaskState]
- controlView:controlView];
- [image drawInRect:imageRect
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:alpha * 0.3
- respectFlipped:YES
- hints:nil];
-
- if ([self currentButtonState] == image_button_cell::kDefaultState ||
- [self currentButtonState] == image_button_cell::kHoverState) {
- image = [self imageForID:imageID_[[self currentButtonState]]
- controlView:controlView];
- [image drawInRect:imageRect
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:alpha
- respectFlipped:YES
- hints:nil];
- }
- }
+ [image drawInRect:imageRect
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:alpha
+ respectFlipped:YES
+ hints:nil];
if (overlayImageID_) {
NSImage* overlayImage = [self imageForID:overlayImageID_
@@ -122,12 +110,17 @@ const CGFloat kImageNoFocusAlpha = 0.65;
- (void)setImageID:(NSInteger)imageID
forButtonState:(image_button_cell::ButtonState)state {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ NSImage* image = imageID ? rb.GetNativeImageNamed(imageID).ToNSImage() : nil;
+ [self setImage:image forButtonState:state];
+}
+
+// Sets the image for the given button state using an image.
+- (void)setImage:(NSImage*)image
+ forButtonState:(image_button_cell::ButtonState)state {
DCHECK_GE(state, 0);
DCHECK_LT(state, image_button_cell::kButtonStateCount);
- if (imageID_[state] != imageID) {
- imageID_[state] = imageID;
- [[self controlView] setNeedsDisplay:YES];
- }
+ image_[state].reset([image retain]);
}
- (void)setOverlayImageID:(NSInteger)imageID {
@@ -138,11 +131,11 @@ const CGFloat kImageNoFocusAlpha = 0.65;
}
- (image_button_cell::ButtonState)currentButtonState {
- if (![self isEnabled] && imageID_[image_button_cell::kDisabledState])
+ if (![self isEnabled] && image_[image_button_cell::kDisabledState])
return image_button_cell::kDisabledState;
- else if ([self isHighlighted] && imageID_[image_button_cell::kPressedState])
+ else if ([self isHighlighted] && image_[image_button_cell::kPressedState])
return image_button_cell::kPressedState;
- else if ([self isMouseInside] && imageID_[image_button_cell::kHoverState])
+ else if ([self isMouseInside] && image_[image_button_cell::kHoverState])
return image_button_cell::kHoverState;
else
return image_button_cell::kDefaultState;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index 80b4216..1d6449a 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -26,6 +26,7 @@
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_tabstrip.h"
@@ -152,6 +153,80 @@ private:
DISALLOW_COPY_AND_ASSIGN(ScopedNSAnimationContextGroup);
};
+// Creates an NSImage with size |size| and bitmap image representations for both
+// 1x and 2x scale factors. |drawingHandler| is called once for every scale
+// factor. This is similar to -[NSImage imageWithSize:flipped:drawingHandler:],
+// but this function always evaluates drawingHandler eagerly, and it works on
+// 10.6 and 10.7.
+NSImage* CreateImageWithSize(NSSize size,
+ void (^drawingHandler)(NSSize)) {
+ scoped_nsobject<NSImage> result([[NSImage alloc] initWithSize:size]);
+ [NSGraphicsContext saveGraphicsState];
+ for (ui::ScaleFactor scale_factor : ui::GetSupportedScaleFactors()) {
+ float scale = GetScaleFactorScale(scale_factor);
+ NSBitmapImageRep *bmpImageRep = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:NULL
+ pixelsWide:size.width * scale
+ pixelsHigh:size.height * scale
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSCalibratedRGBColorSpace
+ bitmapFormat:NSAlphaFirstBitmapFormat
+ bytesPerRow:0
+ bitsPerPixel:0];
+ [bmpImageRep setSize:size];
+ [NSGraphicsContext setCurrentContext:
+ [NSGraphicsContext graphicsContextWithBitmapImageRep:bmpImageRep]];
+ drawingHandler(size);
+ [result addRepresentation:bmpImageRep];
+ }
+ [NSGraphicsContext restoreGraphicsState];
+
+ return result.release();
+}
+
+// Takes a normal bitmap and a mask image and returns an image the size of the
+// mask that has pixels from |image| but alpha information from |mask|.
+NSImage* ApplyMask(NSImage* image, NSImage* mask) {
+ return [CreateImageWithSize([mask size], ^(NSSize size) {
+ // Skip a few pixels from the top of the tab background gradient, because
+ // the new tab button is not drawn at the very top of the browser window.
+ const int kYOffset = 10;
+ CGFloat width = size.width;
+ CGFloat height = size.height;
+ [image drawAtPoint:NSZeroPoint
+ fromRect:NSMakeRect(0, [image size].height - height - kYOffset,
+ width, height)
+ operation:NSCompositeCopy
+ fraction:1.0];
+ [mask drawAtPoint:NSZeroPoint
+ fromRect:NSMakeRect(0, 0, width, height)
+ operation:NSCompositeDestinationIn
+ fraction:1.0];
+ }) autorelease];
+}
+
+// Paints |overlay| on top of |ground|.
+NSImage* Overlay(NSImage* ground, NSImage* overlay) {
+ DCHECK_EQ([ground size].width, [overlay size].width);
+ DCHECK_EQ([ground size].height, [overlay size].height);
+
+ return [CreateImageWithSize([ground size], ^(NSSize size) {
+ CGFloat width = size.width;
+ CGFloat height = size.height;
+ [ground drawAtPoint:NSZeroPoint
+ fromRect:NSMakeRect(0, 0, width, height)
+ operation:NSCompositeCopy
+ fraction:1.0];
+ [overlay drawAtPoint:NSZeroPoint
+ fromRect:NSMakeRect(0, 0, width, height)
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+ }) autorelease];
+}
+
} // namespace
@interface TabStripController (Private)
@@ -176,6 +251,8 @@ private:
givesIndex:(NSInteger*)index
disposition:(WindowOpenDisposition*)disposition;
- (void)setNewTabButtonHoverState:(BOOL)showHover;
+- (void)themeDidChangeNotification:(NSNotification*)notification;
+- (void)setNewTabImages;
@end
// A simple view class that prevents the Window Server from dragging the area
@@ -206,8 +283,9 @@ private:
- (id)initWithFrame:(NSRect)frameRect
controller:(TabStripController*)controller {
- if ((self = [super initWithFrame:frameRect]))
+ if ((self = [super initWithFrame:frameRect])) {
controller_ = controller;
+ }
return self;
}
@@ -389,24 +467,12 @@ private:
[self setLeftIndentForControls:[[self class] defaultLeftIndentForControls]];
[self setRightIndentForControls:0];
- // TODO(viettrungluu): WTF? "For some reason, if the view is present in the
- // nib a priori, it draws correctly. If we create it in code and add it to
- // the tab view, it draws with all sorts of crazy artifacts."
newTabButton_ = [view getNewTabButton];
[self addSubviewToPermanentList:newTabButton_];
[newTabButton_ setTarget:self];
[newTabButton_ setAction:@selector(clickNewTabButton:)];
- // Set the images from code because Cocoa fails to find them in our sub
- // bundle during tests.
- [[newTabButton_ cell] setImageID:IDR_NEWTAB_BUTTON
- forButtonState:image_button_cell::kDefaultState];
- [[newTabButton_ cell] setImageID:IDR_NEWTAB_BUTTON_H
- forButtonState:image_button_cell::kHoverState];
- [[newTabButton_ cell] setImageID:IDR_NEWTAB_BUTTON_P
- forButtonState:image_button_cell::kPressedState];
- [[newTabButton_ cell] setImageID:IDR_NEWTAB_BUTTON_MASK
- forButtonState:image_button_cell::kMaskState];
+ [self setNewTabImages];
newTabButtonShowingHoverImage_ = NO;
newTabTrackingArea_.reset(
[[CrTrackingArea alloc] initWithRect:[newTabButton_ bounds]
@@ -440,6 +506,12 @@ private:
name:NSViewFrameDidChangeNotification
object:tabStripView_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(themeDidChangeNotification:)
+ name:kBrowserThemeDidChangeNotification
+ object:nil];
+
trackingArea_.reset([[CrTrackingArea alloc]
initWithRect:NSZeroRect // Ignored by NSTrackingInVisibleRect
options:NSTrackingMouseEnteredAndExited |
@@ -2100,6 +2172,38 @@ private:
return [tabContentsArray_ objectAtIndex:index];
}
+- (void)themeDidChangeNotification:(NSNotification*)notification {
+ [self setNewTabImages];
+}
+
+- (void)setNewTabImages {
+ ui::ThemeProvider* theme = [[tabStripView_ window] themeProvider];
+ if (!theme)
+ return;
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* mask = rb.GetNativeImageNamed(IDR_NEWTAB_BUTTON_MASK).ToNSImage();
+ NSImage* normal = rb.GetNativeImageNamed(IDR_NEWTAB_BUTTON).ToNSImage();
+ NSImage* hover = rb.GetNativeImageNamed(IDR_NEWTAB_BUTTON_H).ToNSImage();
+ NSImage* pressed = rb.GetNativeImageNamed(IDR_NEWTAB_BUTTON_P).ToNSImage();
+
+ NSImage* foreground = ApplyMask(
+ theme->GetNSImageNamed(IDR_THEME_TAB_BACKGROUND, true), mask);
+ NSImage* background = ApplyMask(
+ theme->GetNSImageNamed(IDR_THEME_TAB_BACKGROUND_INACTIVE, true), mask);
+
+ [[newTabButton_ cell] setImage:Overlay(foreground, normal)
+ forButtonState:image_button_cell::kDefaultState];
+ [[newTabButton_ cell] setImage:Overlay(foreground, hover)
+ forButtonState:image_button_cell::kHoverState];
+ [[newTabButton_ cell] setImage:Overlay(foreground, pressed)
+ forButtonState:image_button_cell::kPressedState];
+ [[newTabButton_ cell] setImage:Overlay(background, normal)
+ forButtonState:image_button_cell::kDefaultStateBackground];
+ [[newTabButton_ cell] setImage:Overlay(background, hover)
+ forButtonState:image_button_cell::kHoverStateBackground];
+}
+
@end
NSView* GetSheetParentViewForWebContents(WebContents* web_contents) {