Bug 1055018 - Draw CoreUI widgets through -[NSAppearance _drawInRect:context:options:] on 10.10 in order to pick up the 10.10 look. r=smichaud

This commit is contained in:
Markus Stange 2014-08-28 02:15:27 +02:00
parent 11375e15fd
commit 318cce364d
5 changed files with 101 additions and 77 deletions

View File

@ -20,9 +20,6 @@ class nsChildView;
class nsMenuBarX;
@class ChildView;
// Value copied from BITMAP_MAX_AREA, used in nsNativeThemeCocoa.mm
#define CUIDRAW_MAX_AREA 500000
// If we are using an SDK older than 10.7, define bits we need that are missing
// from it.
#if !defined(MAC_OS_X_VERSION_10_7) || \

View File

@ -27,6 +27,7 @@
#include "nsMenuUtilsX.h"
#include "nsStyleConsts.h"
#include "nsNativeThemeColors.h"
#include "nsNativeThemeCocoa.h"
#include "nsChildView.h"
#include "nsCocoaFeatures.h"
#include "nsIScreenManager.h"
@ -3304,19 +3305,7 @@ static void
DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
CGFloat aUnifiedToolbarHeight, BOOL aIsMain)
{
if (aTitlebarRect.size.width * aTitlebarRect.size.height > CUIDRAW_MAX_AREA) {
return;
}
CUIDraw([NSWindow coreUIRenderer], aTitlebarRect, aContext,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
@"kCUIWidgetWindowFrame", @"widget",
@"regularwin", @"windowtype",
(aIsMain ? @"normal" : @"inactive"), @"state",
[NSNumber numberWithDouble:aUnifiedToolbarHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
[NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawTitleSeparatorKey",
nil],
nil);
nsNativeThemeCocoa::DrawNativeTitlebar(aContext, aTitlebarRect, aUnifiedToolbarHeight, aIsMain, NO);
if (nsCocoaFeatures::OnLionOrLater()) {
// On Lion the call to CUIDraw doesn't draw the top pixel strip at some

View File

@ -68,6 +68,9 @@ public:
bool inIsIndeterminate, bool inIsHorizontal,
double inValue, double inMaxValue, nsIFrame* aFrame);
static void DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
CGFloat aUnifiedHeight, BOOL aIsMain, BOOL aIsFlipped);
protected:
virtual ~nsNativeThemeCocoa();
@ -124,8 +127,6 @@ protected:
NSWindow* aWindow);
void DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect,
nsIFrame *aFrame);
void DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
CGFloat aUnifiedHeight, BOOL aIsMain);
void DrawResizer(CGContextRef cgContext, const HIRect& aRect, nsIFrame *aFrame);
// Scrollbars

View File

@ -44,6 +44,8 @@ using mozilla::dom::HTMLMeterElement;
// private Quartz routines needed here
extern "C" {
CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
typedef CFTypeRef CUIRendererRef;
void CUIDraw(CUIRendererRef r, CGRect rect, CGContextRef ctx, CFDictionaryRef options, CFDictionaryRef* result);
}
// Workaround for NSCell control tint drawing
@ -822,6 +824,60 @@ static void DrawCellWithSnapping(NSCell *cell,
NS_OBJC_END_TRY_ABORT_BLOCK;
}
@interface NSWindow(CoreUIRendererPrivate)
+ (CUIRendererRef)coreUIRenderer;
@end
static void
RenderWithCoreUILegacy(CGRect aRect, CGContextRef cgContext, NSDictionary* aOptions)
{
if (aRect.size.width * aRect.size.height <= BITMAP_MAX_AREA) {
CUIRendererRef renderer = [NSWindow respondsToSelector:@selector(coreUIRenderer)]
? [NSWindow coreUIRenderer] : nil;
CUIDraw(renderer, aRect, cgContext, (CFDictionaryRef)aOptions, NULL);
}
}
static id
GetAquaAppearance()
{
// We only need NSAppearance on 10.10 and up.
if (nsCocoaFeatures::OnYosemiteOrLater()) {
Class NSAppearanceClass = NSClassFromString(@"NSAppearance");
if (NSAppearanceClass &&
[NSAppearanceClass respondsToSelector:@selector(appearanceNamed:)]) {
return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
withObject:@"NSAppearanceNameAqua"];
}
}
return nil;
}
@interface NSObject(NSAppearanceCoreUIRendering)
- (void)_drawInRect:(CGRect)rect context:(CGContextRef)cgContext options:(id)options;
@end
static void
RenderWithCoreUI(CGRect aRect, CGContextRef cgContext, NSDictionary* aOptions)
{
static id appearance = GetAquaAppearance();
if (aRect.size.width * aRect.size.height > BITMAP_MAX_AREA) {
return;
}
if (appearance && [appearance respondsToSelector:@selector(_drawInRect:context:options:)]) {
// Render through NSAppearance on Mac OS 10.10 and up. This will call
// CUIDraw with a CoreUI renderer that will give us the correct 10.10
// style. Calling CUIDraw directly with [NSWindow coreUIRenderer] still
// renders 10.9-style widgets on 10.10.
[appearance _drawInRect:aRect context:cgContext options:aOptions];
} else {
// 10.9 and below
RenderWithCoreUILegacy(aRect, cgContext, aOptions);
}
}
static float VerticalAlignFactor(nsIFrame *aFrame)
{
if (!aFrame)
@ -1014,9 +1070,9 @@ nsNativeThemeCocoa::DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect,
[values insertObject:[NSNumber numberWithBool:YES] atIndex:1];
}
CUIDraw([NSWindow coreUIRenderer], drawRect, cgContext,
(CFDictionaryRef)[NSDictionary dictionaryWithObjects:values
forKeys:keys], nil);
RenderWithCoreUI(drawRect, cgContext,
[NSDictionary dictionaryWithObjects:values
forKeys:keys]);
#if DRAW_IN_FRAME_DEBUG
CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
@ -1840,16 +1896,13 @@ nsNativeThemeCocoa::DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
nsIFrame* left = GetAdjacentSiblingFrameWithSameAppearance(aFrame, isRTL);
nsIFrame* right = GetAdjacentSiblingFrameWithSameAppearance(aFrame, !isRTL);
CGRect drawRect = SeparatorAdjustedRect(inBoxRect, left, aFrame, right);
if (drawRect.size.width * drawRect.size.height > CUIDRAW_MAX_AREA) {
return;
}
BOOL drawLeftSeparator = SeparatorResponsibility(left, aFrame) == aFrame;
BOOL drawRightSeparator = SeparatorResponsibility(aFrame, right) == aFrame;
NSControlSize controlSize = FindControlSize(drawRect.size.height, aSettings.heights, 4.0f);
CUIDraw([NSWindow coreUIRenderer], drawRect, cgContext,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
RenderWithCoreUI(drawRect, cgContext, [NSDictionary dictionaryWithObjectsAndKeys:
aSettings.widgetName, @"widget",
(isActive ? @"kCUIPresentationStateActiveKey" : @"kCUIPresentationStateInactive"), @"kCUIPresentationStateKey",
ToolbarButtonPosition(!left, !right), @"kCUIPositionKey",
[NSNumber numberWithBool:drawLeftSeparator], @"kCUISegmentLeadingSeparatorKey",
[NSNumber numberWithBool:drawRightSeparator], @"kCUISegmentTrailingSeparatorKey",
@ -1859,8 +1912,7 @@ nsNativeThemeCocoa::DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
CUIControlSizeForCocoaSize(controlSize), @"size",
[NSNumber numberWithBool:YES], @"is.flipped",
@"up", @"direction",
nil],
nil);
nil]);
}
static inline UInt8
@ -2035,28 +2087,25 @@ ToolbarCanBeUnified(CGContextRef cgContext, const HIRect& inBoxRect, NSWindow* a
// So we draw square corners.
static void
DrawNativeTitlebarToolbarWithSquareCorners(CGContextRef aContext, const CGRect& aRect,
CGFloat aUnifiedHeight, BOOL aIsMain)
CGFloat aUnifiedHeight, BOOL aIsMain, BOOL aIsFlipped)
{
// We extend the draw rect horizontally and clip away the rounded corners.
const CGFloat extendHorizontal = 10;
CGRect drawRect = CGRectInset(aRect, -extendHorizontal, 0);
if (drawRect.size.width * drawRect.size.height <= CUIDRAW_MAX_AREA) {
CGContextSaveGState(aContext);
CGContextClipToRect(aContext, aRect);
CGContextSaveGState(aContext);
CGContextClipToRect(aContext, aRect);
CUIDraw([NSWindow coreUIRenderer], drawRect, aContext,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
@"kCUIWidgetWindowFrame", @"widget",
@"regularwin", @"windowtype",
(aIsMain ? @"normal" : @"inactive"), @"state",
[NSNumber numberWithDouble:aUnifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
[NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawTitleSeparatorKey",
[NSNumber numberWithBool:YES], @"is.flipped",
nil],
nil);
RenderWithCoreUI(drawRect, aContext,
[NSDictionary dictionaryWithObjectsAndKeys:
@"kCUIWidgetWindowFrame", @"widget",
@"regularwin", @"windowtype",
(aIsMain ? @"normal" : @"inactive"), @"state",
[NSNumber numberWithDouble:aUnifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
[NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawTitleSeparatorKey",
[NSNumber numberWithBool:aIsFlipped], @"is.flipped",
nil]);
CGContextRestoreGState(aContext);
}
CGContextRestoreGState(aContext);
}
void
@ -2074,7 +2123,7 @@ nsNativeThemeCocoa::DrawUnifiedToolbar(CGContextRef cgContext, const HIRect& inB
CGFloat titlebarHeight = unifiedHeight - inBoxRect.size.height;
CGRect drawRect = CGRectMake(inBoxRect.origin.x, inBoxRect.origin.y - titlebarHeight,
inBoxRect.size.width, inBoxRect.size.height + titlebarHeight);
DrawNativeTitlebarToolbarWithSquareCorners(cgContext, drawRect, unifiedHeight, isMain);
DrawNativeTitlebarToolbarWithSquareCorners(cgContext, drawRect, unifiedHeight, isMain, YES);
CGContextRestoreGState(cgContext);
@ -2100,18 +2149,15 @@ nsNativeThemeCocoa::DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRec
const int extendUpwards = 40;
drawRect.origin.y -= extendUpwards;
drawRect.size.height += extendUpwards;
if (drawRect.size.width * drawRect.size.height <= CUIDRAW_MAX_AREA) {
CUIDraw([NSWindow coreUIRenderer], drawRect, cgContext,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
@"kCUIWidgetWindowFrame", @"widget",
@"regularwin", @"windowtype",
(IsActive(aFrame, YES) ? @"normal" : @"inactive"), @"state",
[NSNumber numberWithInt:inBoxRect.size.height], @"kCUIWindowFrameBottomBarHeightKey",
[NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawBottomBarSeparatorKey",
[NSNumber numberWithBool:YES], @"is.flipped",
nil],
nil);
}
RenderWithCoreUI(drawRect, cgContext,
[NSDictionary dictionaryWithObjectsAndKeys:
@"kCUIWidgetWindowFrame", @"widget",
@"regularwin", @"windowtype",
(IsActive(aFrame, YES) ? @"normal" : @"inactive"), @"state",
[NSNumber numberWithInt:inBoxRect.size.height], @"kCUIWindowFrameBottomBarHeightKey",
[NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawBottomBarSeparatorKey",
[NSNumber numberWithBool:YES], @"is.flipped",
nil]);
CGContextRestoreGState(cgContext);
@ -2120,10 +2166,10 @@ nsNativeThemeCocoa::DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRec
void
nsNativeThemeCocoa::DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
CGFloat aUnifiedHeight, BOOL aIsMain)
CGFloat aUnifiedHeight, BOOL aIsMain, BOOL aIsFlipped)
{
CGFloat unifiedHeight = std::max(aUnifiedHeight, aTitlebarRect.size.height);
DrawNativeTitlebarToolbarWithSquareCorners(aContext, aTitlebarRect, unifiedHeight, aIsMain);
DrawNativeTitlebarToolbarWithSquareCorners(aContext, aTitlebarRect, unifiedHeight, aIsMain, aIsFlipped);
}
static void
@ -2447,7 +2493,7 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
BOOL isMain = [win isMainWindow];
float unifiedToolbarHeight = [win isKindOfClass:[ToolbarWindow class]] ?
[(ToolbarWindow*)win unifiedToolbarHeight] : macRect.size.height;
DrawNativeTitlebar(cgContext, macRect, unifiedToolbarHeight, isMain);
DrawNativeTitlebar(cgContext, macRect, unifiedToolbarHeight, isMain, YES);
}
break;
@ -2633,8 +2679,10 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
}
}
const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
CUIDraw([NSWindow coreUIRenderer], macRect, cgContext,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
// Scrollbar thumbs have a too high minimum width when rendered through
// NSAppearance on 10.10, so we call RenderWithCoreUILegacy here.
RenderWithCoreUILegacy(macRect, cgContext,
[NSDictionary dictionaryWithObjectsAndKeys:
(isOverlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"), @"widget",
@"regular", @"size",
(isRolledOver ? @"rollover" : @"normal"), @"state",
@ -2643,8 +2691,7 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
[NSNumber numberWithBool:YES], @"indiconly",
[NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
[NSNumber numberWithBool:YES], @"is.flipped",
nil],
nil);
nil]);
}
break;
case NS_THEME_SCROLLBAR_BUTTON_UP:
@ -2682,8 +2729,8 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
}
}
const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
CUIDraw([NSWindow coreUIRenderer], macRect, cgContext,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
RenderWithCoreUILegacy(macRect, cgContext,
[NSDictionary dictionaryWithObjectsAndKeys:
(isOverlay ? @"kCUIWidgetOverlayScrollBar" : @"scrollbar"), @"widget",
@"regular", @"size",
(isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
@ -2691,8 +2738,7 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
[NSNumber numberWithBool:YES], @"noindicator",
[NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
[NSNumber numberWithBool:YES], @"is.flipped",
nil],
nil);
nil]);
}
}
break;

View File

@ -9,15 +9,6 @@
#include "nsCocoaFeatures.h"
#import <Cocoa/Cocoa.h>
extern "C" {
typedef CFTypeRef CUIRendererRef;
void CUIDraw(CUIRendererRef r, CGRect rect, CGContextRef ctx, CFDictionaryRef options, CFDictionaryRef* result);
}
@interface NSWindow(CoreUIRendererPrivate)
+ (CUIRendererRef)coreUIRenderer;
@end
enum ColorName {
toolbarTopBorderGrey,
toolbarFillGrey,