1231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block/*
2231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Copyright (C) 2009 Google Inc. All Rights Reserved.
4231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block *
5231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Redistribution and use in source and binary forms, with or without
6231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * modification, are permitted provided that the following conditions
7231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * are met:
8231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 1. Redistributions of source code must retain the above copyright
9231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block *    notice, this list of conditions and the following disclaimer.
10231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 2. Redistributions in binary form must reproduce the above copyright
11231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block *    notice, this list of conditions and the following disclaimer in the
12231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block *    documentation and/or other materials provided with the distribution.
13231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block *
14231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
245e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block */
26231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
27231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#import "config.h"
28231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#import "ThemeChromiumMac.h"
29231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
30231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#import "BlockExceptions.h"
31231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#import "GraphicsContext.h"
32231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#import "LocalCurrentGraphicsContext.h"
33231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#import "ScrollView.h"
34231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#import "WebCoreSystemInterface.h"
35967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#import <Carbon/Carbon.h>
36231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include <wtf/StdLibExtras.h>
378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#import <objc/runtime.h>
38231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
39231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockusing namespace std;
40231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
41231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// This file (and its associated .h file) is a clone of ThemeMac.mm.
42231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Because the original file is designed to run in-process inside a Cocoa view,
43231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// we must maintain a fork. Please maintain this file by performing parallel
44231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// changes to it.
45231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block//
46231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// The only changes from ThemeMac should be:
47231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// - The classname change from ThemeMac to ThemeChromiumMac.
48231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// - The import of FlippedView() and its use as the parent view for cell
49231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block//   rendering.
50231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// - In updateStates() the code to update the cells' inactive state.
51231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// - In paintButton() the code to save/restore the window's default button cell.
528a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// - The Snow Leopard focus ring bug fix and its use around every call to
538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block//   -[NSButtonCell drawWithFrame:inView:].
54231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block//
55231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// For all other differences, if it was introduced in this file, then the
56231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// maintainer forgot to include it in the list; otherwise it is an update that
57231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// should have been applied to this file but was not.
58231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
59231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// FIXME: Default buttons really should be more like push buttons and not like buttons.
60231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
618a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// --- START fix for Snow Leopard focus ring bug ---
628a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
638a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// There is a bug in the Cocoa focus ring drawing code. The code calls +[NSView
648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// focusView] (to get the currently focused view) and then calls an NSRect-
658a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// returning method on that view to obtain a clipping rect. However, if there is
668a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// no focused view (as there won't be if the destination is a context), the rect
678a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// returned from the method invocation on nil is garbage.
688a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block//
698a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// The garbage fortunately does not clip the focus ring on Leopard, but
708a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// unfortunately does so on Snow Leopard. Therefore, if a runtime test shows
718a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// that focus ring drawing fails, we swizzle NSView to ensure it returns a valid
728a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// view with a valid clipping rectangle.
738a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block//
748a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// FIXME: After the referenced bug is fixed on all supported platforms, remove
758a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// this code.
768a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block//
778a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// References:
788a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block//  <http://crbug.com/27493>
798a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block//  <rdar://problem/7604051> (<http://openradar.appspot.com/7604051>)
808a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
818a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@interface TCMVisibleView : NSView
828a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
838a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@end
848a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
858a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@implementation TCMVisibleView
868a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
878a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block- (struct CGRect)_focusRingVisibleRect
888a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
898a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return CGRectZero;
908a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
918a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block- (id)_focusRingClipAncestor
938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return self;
958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@end
988a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
998a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@interface NSView (TCMInterposing)
1008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block+ (NSView *)TCMInterposing_focusView;
1018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@end
1028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1038a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blocknamespace FocusIndicationFix {
1048a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1058a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockbool currentOSHasSetFocusRingStyleInBitmapBug()
1068a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
1078a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    UInt32 pixel = 0;
1088a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    UInt32* pixelPlane = &pixel;
1098a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    UInt32** pixelPlanes = &pixelPlane;
1108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(UInt8**)pixelPlanes
1118a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                       pixelsWide:1
1128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                       pixelsHigh:1
1138a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                    bitsPerSample:8
1148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                  samplesPerPixel:4
1158a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                         hasAlpha:YES
1168a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                         isPlanar:NO
1178a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                   colorSpaceName:NSCalibratedRGBColorSpace
1188a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                     bitmapFormat:NSAlphaFirstBitmapFormat
1198a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                      bytesPerRow:4
1208a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                                                     bitsPerPixel:32];
1218a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    [NSGraphicsContext saveGraphicsState];
1228a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]];
1238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    NSSetFocusRingStyle(NSFocusRingOnly);
1248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    NSRectFill(NSMakeRect(0, 0, 1, 1));
1258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    [NSGraphicsContext restoreGraphicsState];
1268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    [bitmap release];
1278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1288a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return !pixel;
1298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
1308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockbool swizzleFocusView()
1328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
1338a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    if (!currentOSHasSetFocusRingStyleInBitmapBug())
1348a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return false;
1358a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    Class nsview = [NSView class];
1378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    Method m1 = class_getClassMethod(nsview, @selector(focusView));
1388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    Method m2 = class_getClassMethod(nsview, @selector(TCMInterposing_focusView));
1398a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    if (m1 && m2) {
1408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        method_exchangeImplementations(m1, m2);
1418a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return true;
1428a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
1438a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return false;
1458a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
1468a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1478a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockstatic bool interpose = false;
1488a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1498a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// A class to restrict the amount of time spent messing with interposing. It
1508a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// only stacks one-deep.
1518a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockclass ScopedFixer {
1528a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockpublic:
1538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    ScopedFixer()
1548a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    {
1558a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        static bool swizzled = swizzleFocusView();
1568a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        interpose = swizzled;
1578a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
1588a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1598a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    ~ScopedFixer()
1608a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    {
1618a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        interpose = false;
1628a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
1638a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block};
1648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1658a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}  // namespace FocusIndicationFix
1668a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1678a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@implementation NSView (TCMInterposing)
1688a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1698a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block+ (NSView *)TCMInterposing_focusView
1708a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
1718a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    NSView *view = [self TCMInterposing_focusView];  // call original (was swizzled)
1728a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    if (!view && FocusIndicationFix::interpose) {
1738a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        static TCMVisibleView* fixedView = [[TCMVisibleView alloc] init];
1748a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        view = fixedView;
1758a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
1768a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1778a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return view;
1788a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
1798a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1808a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block@end
1818a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1828a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block// --- END fix for Snow Leopard focus ring bug ---
1838a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
184231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocknamespace WebCore {
185231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
186231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Pick up utility function from RenderThemeChromiumMac.
187231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockextern NSView* FlippedView();
188231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
189231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockenum {
190231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    topMargin,
191231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    rightMargin,
192231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bottomMargin,
193231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    leftMargin
194231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block};
195231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
196231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockTheme* platformTheme()
197231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
198231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    DEFINE_STATIC_LOCAL(ThemeChromiumMac, themeMac, ());
199231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return &themeMac;
200231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
201231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
202231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Helper functions used by a bunch of different control parts.
203231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
204231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic NSControlSize controlSizeForFont(const Font& font)
205231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
206231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    int fontSize = font.pixelSize();
207231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (fontSize >= 16)
208231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return NSRegularControlSize;
209231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (fontSize >= 11)
210231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return NSSmallControlSize;
211231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return NSMiniControlSize;
212231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
213231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
214967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic LengthSize sizeFromNSControlSize(NSControlSize nsControlSize, const LengthSize& zoomedSize, float zoomFactor, const IntSize* sizes)
215231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
216967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    IntSize controlSize = sizes[nsControlSize];
217231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (zoomFactor != 1.0f)
218231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        controlSize = IntSize(controlSize.width() * zoomFactor, controlSize.height() * zoomFactor);
219231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    LengthSize result = zoomedSize;
220231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (zoomedSize.width().isIntrinsicOrAuto() && controlSize.width() > 0)
221231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        result.setWidth(Length(controlSize.width(), Fixed));
222231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (zoomedSize.height().isIntrinsicOrAuto() && controlSize.height() > 0)
223231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        result.setHeight(Length(controlSize.height(), Fixed));
224231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return result;
225231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
226231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
227967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic LengthSize sizeFromFont(const Font& font, const LengthSize& zoomedSize, float zoomFactor, const IntSize* sizes)
228967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
229967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    return sizeFromNSControlSize(controlSizeForFont(font), zoomedSize, zoomFactor, sizes);
230967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
231967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
232967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic ControlSize controlSizeFromPixelSize(const IntSize* sizes, const IntSize& minZoomedSize, float zoomFactor)
233231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
234231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (minZoomedSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomFactor) &&
235231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        minZoomedSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomFactor))
236967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return NSRegularControlSize;
237967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (minZoomedSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomFactor) &&
238967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        minZoomedSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomFactor))
239967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return NSSmallControlSize;
240967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    return NSMiniControlSize;
241967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
242967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
243967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic void setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minZoomedSize, float zoomFactor)
244967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
245967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    ControlSize size = controlSizeFromPixelSize(sizes, minZoomedSize, zoomFactor);
246231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
247967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        [cell setControlSize:(NSControlSize)size];
248231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
249231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
250231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic void updateStates(NSCell* cell, ControlStates states)
251231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
252231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Hover state is not supported by Aqua.
2535e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
254231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Pressed state
255231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool oldPressed = [cell isHighlighted];
256231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool pressed = states & PressedState;
257231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (pressed != oldPressed)
258231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [cell setHighlighted:pressed];
2595e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
260231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Enabled state
261231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool oldEnabled = [cell isEnabled];
262231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool enabled = states & EnabledState;
263231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (enabled != oldEnabled)
264231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [cell setEnabled:enabled];
2655e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
266231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Focused state
267231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool oldFocused = [cell showsFirstResponder];
268231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool focused = states & FocusState;
269231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (focused != oldFocused)
270231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [cell setShowsFirstResponder:focused];
271231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
272231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Checked and Indeterminate
273231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool oldIndeterminate = [cell state] == NSMixedState;
274231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool indeterminate = (states & IndeterminateState);
275231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool checked = states & CheckedState;
276231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool oldChecked = [cell state] == NSOnState;
277231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (oldIndeterminate != indeterminate || checked != oldChecked)
278231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
2795e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
280231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Window Inactive state
281231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    NSControlTint oldTint = [cell controlTint];
282231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool windowInactive = (states & WindowInactiveState);
28306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    NSControlTint tint = windowInactive ? static_cast<NSControlTint>(NSClearControlTint)
28406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                                        : [NSColor currentControlTint];
285231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (tint != oldTint)
286231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [cell setControlTint:tint];
287231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
288231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
289967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic ThemeDrawState convertControlStatesToThemeDrawState(ThemeButtonKind kind, ControlStates states)
290967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
291967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (states & ReadOnlyState)
292967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return kThemeStateUnavailableInactive;
293967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (!(states & EnabledState))
294967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return kThemeStateUnavailableInactive;
295967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
296967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    // Do not process PressedState if !EnabledState or ReadOnlyState.
297967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (states & PressedState) {
298967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        if (kind == kThemeIncDecButton || kind == kThemeIncDecButtonSmall || kind == kThemeIncDecButtonMini)
299967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            return states & SpinUpState ? kThemeStatePressedUp : kThemeStatePressedDown;
300967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return kThemeStatePressed;
301967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    }
302967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    return kThemeStateActive;
303967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
304967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
305231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic IntRect inflateRect(const IntRect& zoomedRect, const IntSize& zoomedSize, const int* margins, float zoomFactor)
306231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Only do the inflation if the available width/height are too small.  Otherwise try to
308231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // fit the glow/check space into the available box's width/height.
309231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    int widthDelta = zoomedRect.width() - (zoomedSize.width() + margins[leftMargin] * zoomFactor + margins[rightMargin] * zoomFactor);
310231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    int heightDelta = zoomedRect.height() - (zoomedSize.height() + margins[topMargin] * zoomFactor + margins[bottomMargin] * zoomFactor);
311231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntRect result(zoomedRect);
312231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (widthDelta < 0) {
313231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        result.setX(result.x() - margins[leftMargin] * zoomFactor);
314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        result.setWidth(result.width() - widthDelta);
315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
316231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (heightDelta < 0) {
317231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        result.setY(result.y() - margins[topMargin] * zoomFactor);
318231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        result.setHeight(result.height() - heightDelta);
319231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
320231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return result;
321231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
322231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
323231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Checkboxes
324231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
325231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic const IntSize* checkboxSizes()
326231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
327231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
328231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return sizes;
329231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
330231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
331231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic const int* checkboxMargins(NSControlSize controlSize)
332231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
333231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static const int margins[3][4] =
334231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    {
335231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 3, 4, 4, 2 },
336231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 4, 3, 3, 3 },
337231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 4, 3, 3, 3 },
338231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    };
339231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return margins[controlSize];
340231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
341231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
342231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic LengthSize checkboxSize(const Font& font, const LengthSize& zoomedSize, float zoomFactor)
343231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
344231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // If the width and height are both specified, then we have nothing to do.
345231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto())
346231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return zoomedSize;
347231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
348231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Use the font size to determine the intrinsic width of the control.
349231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return sizeFromFont(font, zoomedSize, zoomFactor, checkboxSizes());
350231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
351231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3525e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockstatic NSButtonCell *checkbox(ControlStates states, const IntRect& zoomedRect, float zoomFactor)
353231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
3545e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    static NSButtonCell *checkboxCell;
355231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!checkboxCell) {
356231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        checkboxCell = [[NSButtonCell alloc] init];
357231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [checkboxCell setButtonType:NSSwitchButton];
358231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [checkboxCell setTitle:nil];
359231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [checkboxCell setAllowsMixedState:YES];
360231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [checkboxCell setFocusRingType:NSFocusRingTypeExterior];
361231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
3625e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
363231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Set the control size based off the rectangle we're painting into.
364231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    setControlSize(checkboxCell, checkboxSizes(), zoomedRect.size(), zoomFactor);
365231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
366231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Update the various states we respond to.
367231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    updateStates(checkboxCell, states);
3685e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
369231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return checkboxCell;
370231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
371231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
372231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// FIXME: Share more code with radio buttons.
373231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic void paintCheckbox(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView)
374231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
375231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    BEGIN_BLOCK_OBJC_EXCEPTIONS
376231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
377231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Determine the width and height needed for the control and prepare the cell for painting.
3785e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    NSButtonCell *checkboxCell = checkbox(states, zoomedRect, zoomFactor);
379a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    LocalCurrentGraphicsContext localContext(context);
380231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
381231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    context->save();
382231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
383231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    NSControlSize controlSize = [checkboxCell controlSize];
384231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntSize zoomedSize = checkboxSizes()[controlSize];
385231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
386231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
387231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntRect inflatedRect = inflateRect(zoomedRect, zoomedSize, checkboxMargins(controlSize), zoomFactor);
3885e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
389231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (zoomFactor != 1.0f) {
390231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        inflatedRect.setWidth(inflatedRect.width() / zoomFactor);
391231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        inflatedRect.setHeight(inflatedRect.height() / zoomFactor);
392231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context->translate(inflatedRect.x(), inflatedRect.y());
393231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context->scale(FloatSize(zoomFactor, zoomFactor));
394231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context->translate(-inflatedRect.x(), -inflatedRect.y());
395231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
3965e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
3978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    {
3988a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        FocusIndicationFix::ScopedFixer fix;
3998a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        [checkboxCell drawWithFrame:NSRect(inflatedRect) inView:FlippedView()];
4008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
401231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    [checkboxCell setControlView:nil];
402231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
403231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    context->restore();
4045e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
405231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    END_BLOCK_OBJC_EXCEPTIONS
406231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
407231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
408231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Radio Buttons
409231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
410231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic const IntSize* radioSizes()
411231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
412231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
413231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return sizes;
414231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
415231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
416231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic const int* radioMargins(NSControlSize controlSize)
417231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
418231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static const int margins[3][4] =
419231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    {
420231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 2, 2, 4, 2 },
421231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 3, 2, 3, 2 },
422231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 1, 0, 2, 0 },
423231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    };
424231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return margins[controlSize];
425231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
426231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
427231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic LengthSize radioSize(const Font& font, const LengthSize& zoomedSize, float zoomFactor)
428231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
429231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // If the width and height are both specified, then we have nothing to do.
430231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto())
431231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return zoomedSize;
432231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
433231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Use the font size to determine the intrinsic width of the control.
434231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return sizeFromFont(font, zoomedSize, zoomFactor, radioSizes());
435231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
436231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
4375e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockstatic NSButtonCell *radio(ControlStates states, const IntRect& zoomedRect, float zoomFactor)
438231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
4395e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    static NSButtonCell *radioCell;
440231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!radioCell) {
441231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        radioCell = [[NSButtonCell alloc] init];
442231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [radioCell setButtonType:NSRadioButton];
443231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [radioCell setTitle:nil];
444231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [radioCell setFocusRingType:NSFocusRingTypeExterior];
445231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
4465e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
447231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Set the control size based off the rectangle we're painting into.
448231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    setControlSize(radioCell, radioSizes(), zoomedRect.size(), zoomFactor);
449231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
450231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Update the various states we respond to.
451231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    updateStates(radioCell, states);
4525e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
453231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return radioCell;
454231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
455231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
456231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic void paintRadio(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView)
457231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
458231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Determine the width and height needed for the control and prepare the cell for painting.
4595e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    NSButtonCell *radioCell = radio(states, zoomedRect, zoomFactor);
460a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    LocalCurrentGraphicsContext localContext(context);
461231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
462231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    context->save();
463231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
464231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    NSControlSize controlSize = [radioCell controlSize];
465231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntSize zoomedSize = radioSizes()[controlSize];
466231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
467231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
468231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntRect inflatedRect = inflateRect(zoomedRect, zoomedSize, radioMargins(controlSize), zoomFactor);
4695e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
470231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (zoomFactor != 1.0f) {
471231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        inflatedRect.setWidth(inflatedRect.width() / zoomFactor);
472231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        inflatedRect.setHeight(inflatedRect.height() / zoomFactor);
473231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context->translate(inflatedRect.x(), inflatedRect.y());
474231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context->scale(FloatSize(zoomFactor, zoomFactor));
475231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context->translate(-inflatedRect.x(), -inflatedRect.y());
476231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
4775e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
478231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    BEGIN_BLOCK_OBJC_EXCEPTIONS
4798a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    {
4808a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        FocusIndicationFix::ScopedFixer fix;
4818a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        [radioCell drawWithFrame:NSRect(inflatedRect) inView:FlippedView()];
4828a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
483231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    [radioCell setControlView:nil];
484231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    END_BLOCK_OBJC_EXCEPTIONS
485231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
486231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    context->restore();
487231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
488231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
489231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Buttons
490231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
491231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Buttons really only constrain height. They respect width.
492231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic const IntSize* buttonSizes()
493231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
494231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
495231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return sizes;
496231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
497231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
4985e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#if ENABLE(DATALIST)
4995e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockstatic const IntSize* listButtonSizes()
5005e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{
5015e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    static const IntSize sizes[3] = { IntSize(21, 21), IntSize(19, 18), IntSize(17, 16) };
5025e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    return sizes;
5035e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block}
5045e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#endif
5055e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
506231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic const int* buttonMargins(NSControlSize controlSize)
507231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
508231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    static const int margins[3][4] =
509231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    {
510231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 4, 6, 7, 6 },
511231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 4, 5, 6, 5 },
512231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        { 0, 1, 1, 1 },
513231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    };
514231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return margins[controlSize];
515231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
516231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
5175e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockstatic void setupButtonCell(NSButtonCell *&buttonCell, ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor)
518231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
519231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!buttonCell) {
520231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        buttonCell = [[NSButtonCell alloc] init];
521231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [buttonCell setTitle:nil];
522231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [buttonCell setButtonType:NSMomentaryPushInButton];
5235e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        if (states & DefaultState)
5245e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block            [buttonCell setKeyEquivalent:@"\r"];
525231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
526231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
527231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Set the control size based off the rectangle we're painting into.
5285e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    const IntSize* sizes = buttonSizes();
5295e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#if ENABLE(DATALIST)
5305e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    if (part == ListButtonPart) {
5315e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        [buttonCell setBezelStyle:NSRoundedDisclosureBezelStyle];
5325e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        sizes = listButtonSizes();
5335e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    } else
5345e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#endif
535231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (part == SquareButtonPart || zoomedRect.height() > buttonSizes()[NSRegularControlSize].height() * zoomFactor) {
536231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        // Use the square button
537231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if ([buttonCell bezelStyle] != NSShadowlessSquareBezelStyle)
538231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            [buttonCell setBezelStyle:NSShadowlessSquareBezelStyle];
539231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    } else if ([buttonCell bezelStyle] != NSRoundedBezelStyle)
540231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        [buttonCell setBezelStyle:NSRoundedBezelStyle];
541231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
5425e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    setControlSize(buttonCell, sizes, zoomedRect.size(), zoomFactor);
543231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
544231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Update the various states we respond to.
545231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    updateStates(buttonCell, states);
5465e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block}
5475e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
5485e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockstatic NSButtonCell *button(ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor)
5495e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{
5505e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    bool isDefault = states & DefaultState;
5515e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    static NSButtonCell *cells[2];
5525e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    setupButtonCell(cells[isDefault], part, states, zoomedRect, zoomFactor);
5535e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    return cells[isDefault];
554231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
555231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
556231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic void paintButton(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView)
557231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
558231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    BEGIN_BLOCK_OBJC_EXCEPTIONS
5595e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
560231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Determine the width and height needed for the control and prepare the cell for painting.
561231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    NSButtonCell *buttonCell = button(part, states, zoomedRect, zoomFactor);
562231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    LocalCurrentGraphicsContext localContext(context);
563231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
564231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    NSControlSize controlSize = [buttonCell controlSize];
5655e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#if ENABLE(DATALIST)
5665e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    IntSize zoomedSize = (part == ListButtonPart ? listButtonSizes() : buttonSizes())[controlSize];
5675e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#else
568231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntSize zoomedSize = buttonSizes()[controlSize];
5695e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#endif
570231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    zoomedSize.setWidth(zoomedRect.width()); // Buttons don't ever constrain width, so the zoomed width can just be honored.
571231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
572231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntRect inflatedRect = zoomedRect;
573231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if ([buttonCell bezelStyle] == NSRoundedBezelStyle) {
574231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        // Center the button within the available space.
575231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (inflatedRect.height() > zoomedSize.height()) {
576231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - zoomedSize.height()) / 2);
577231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            inflatedRect.setHeight(zoomedSize.height());
578231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
579231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
580231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        // Now inflate it to account for the shadow.
581231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        inflatedRect = inflateRect(inflatedRect, zoomedSize, buttonMargins(controlSize), zoomFactor);
582231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
583231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (zoomFactor != 1.0f) {
584231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            inflatedRect.setWidth(inflatedRect.width() / zoomFactor);
585231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            inflatedRect.setHeight(inflatedRect.height() / zoomFactor);
586231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            context->translate(inflatedRect.x(), inflatedRect.y());
587231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            context->scale(FloatSize(zoomFactor, zoomFactor));
588231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            context->translate(-inflatedRect.x(), -inflatedRect.y());
589231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
5905e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    }
591231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
5928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    {
5938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        FocusIndicationFix::ScopedFixer fix;
5948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        [buttonCell drawWithFrame:NSRect(inflatedRect) inView:FlippedView()];
5958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
596231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    [buttonCell setControlView:nil];
597231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
598231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    END_BLOCK_OBJC_EXCEPTIONS
599231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
600231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
601967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch// Stepper
602967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
603967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic const IntSize* stepperSizes()
604967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
605967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    static const IntSize sizes[3] = { IntSize(19, 27), IntSize(15, 22), IntSize(13, 15) };
606967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    return sizes;
607967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
608967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
609967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch// We don't use controlSizeForFont() for steppers because the stepper height
610967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch// should be equal to or less than the corresponding text field height,
611967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic NSControlSize stepperControlSizeForFont(const Font& font)
612967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
613967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    int fontSize = font.pixelSize();
614967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (fontSize >= 18)
615967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return NSRegularControlSize;
616967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (fontSize >= 13)
617967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return NSSmallControlSize;
618967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    return NSMiniControlSize;
619967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
620967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
621967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic void paintStepper(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView*)
622967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
623967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    // We don't use NSStepperCell because there are no ways to draw an
624967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    // NSStepperCell with the up button highlighted.
625967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
626967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    HIThemeButtonDrawInfo drawInfo;
627967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    drawInfo.version = 0;
628967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    drawInfo.state = convertControlStatesToThemeDrawState(kThemeIncDecButton, states);
629967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    drawInfo.adornment = kThemeAdornmentDefault;
630967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    ControlSize controlSize = controlSizeFromPixelSize(stepperSizes(), zoomedRect.size(), zoomFactor);
631967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (controlSize == NSSmallControlSize)
632967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        drawInfo.kind = kThemeIncDecButtonSmall;
633967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    else if (controlSize == NSMiniControlSize)
634967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        drawInfo.kind = kThemeIncDecButtonMini;
635967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    else
636967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        drawInfo.kind = kThemeIncDecButton;
637967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
638967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    IntRect rect(zoomedRect);
639967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    context->save();
640967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (zoomFactor != 1.0f) {
641967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        rect.setWidth(rect.width() / zoomFactor);
642967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        rect.setHeight(rect.height() / zoomFactor);
643967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        context->translate(rect.x(), rect.y());
644967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        context->scale(FloatSize(zoomFactor, zoomFactor));
645967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        context->translate(-rect.x(), -rect.y());
646967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    }
647967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    CGRect bounds(rect);
648967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    // Adjust 'bounds' so that HIThemeDrawButton(bounds,...) draws exactly on 'rect'.
649967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    CGRect backgroundBounds;
650967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    HIThemeGetButtonBackgroundBounds(&bounds, &drawInfo, &backgroundBounds);
651967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (bounds.origin.x != backgroundBounds.origin.x)
652967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        bounds.origin.x += bounds.origin.x - backgroundBounds.origin.x;
653967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (bounds.origin.y != backgroundBounds.origin.y)
654967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        bounds.origin.y += bounds.origin.y - backgroundBounds.origin.y;
655967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    HIThemeDrawButton(&bounds, &drawInfo, context->platformContext(), kHIThemeOrientationNormal, 0);
656967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    context->restore();
657967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
658967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
659231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Theme overrides
660231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
661231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockint ThemeChromiumMac::baselinePositionAdjustment(ControlPart part) const
662231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
663231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (part == CheckboxPart || part == RadioPart)
664231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return -2;
665231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return Theme::baselinePositionAdjustment(part);
666231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
667231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
668231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockFontDescription ThemeChromiumMac::controlFont(ControlPart part, const Font& font, float zoomFactor) const
669231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
670231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    switch (part) {
671231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case PushButtonPart: {
672231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            FontDescription fontDescription;
673231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            fontDescription.setIsAbsoluteSize(true);
674231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            fontDescription.setGenericFamily(FontDescription::SerifFamily);
675231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
676231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            NSFont* nsFont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSizeForFont(font)]];
677231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            fontDescription.firstFamily().setFamily([nsFont familyName]);
678231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            fontDescription.setComputedSize([nsFont pointSize] * zoomFactor);
679231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            fontDescription.setSpecifiedSize([nsFont pointSize] * zoomFactor);
680231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return fontDescription;
681231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
682231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        default:
683231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return Theme::controlFont(part, font, zoomFactor);
684231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
685231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
686231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
687231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockLengthSize ThemeChromiumMac::controlSize(ControlPart part, const Font& font, const LengthSize& zoomedSize, float zoomFactor) const
688231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
689231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    switch (part) {
690231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case CheckboxPart:
691231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return checkboxSize(font, zoomedSize, zoomFactor);
692231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case RadioPart:
693231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return radioSize(font, zoomedSize, zoomFactor);
694231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case PushButtonPart:
695231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // Height is reset to auto so that specified heights can be ignored.
696231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return sizeFromFont(font, LengthSize(zoomedSize.width(), Length()), zoomFactor, buttonSizes());
6975e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#if ENABLE(DATALIST)
6985e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        case ListButtonPart:
6995e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block            return sizeFromFont(font, LengthSize(zoomedSize.width(), Length()), zoomFactor, listButtonSizes());
7005e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#endif
701967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        case InnerSpinButtonPart:
702967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            // We don't use inner spin buttons on Mac.
703967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            return LengthSize(Length(Fixed), Length(Fixed));
704967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        case OuterSpinButtonPart:
705967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto())
706967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                return zoomedSize;
707967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            return sizeFromNSControlSize(stepperControlSizeForFont(font), zoomedSize, zoomFactor, stepperSizes());
708231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        default:
709231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return zoomedSize;
710231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
711231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
712231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
713231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockLengthSize ThemeChromiumMac::minimumControlSize(ControlPart part, const Font& font, float zoomFactor) const
714231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
715231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    switch (part) {
716231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case SquareButtonPart:
717231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case DefaultButtonPart:
718231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case ButtonPart:
7195e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        case ListButtonPart:
720231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return LengthSize(Length(0, Fixed), Length(static_cast<int>(15 * zoomFactor), Fixed));
721967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        case InnerSpinButtonPart:
722967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            // We don't use inner spin buttons on Mac.
723967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            return LengthSize(Length(Fixed), Length(Fixed));
724967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        case OuterSpinButtonPart: {
725967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            IntSize base = stepperSizes()[NSMiniControlSize];
726967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            return LengthSize(Length(static_cast<int>(base.width() * zoomFactor), Fixed),
727967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                              Length(static_cast<int>(base.height() * zoomFactor), Fixed));
728967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        }
729231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        default:
730231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return Theme::minimumControlSize(part, font, zoomFactor);
731231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
732231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
733231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
734231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockLengthBox ThemeChromiumMac::controlBorder(ControlPart part, const Font& font, const LengthBox& zoomedBox, float zoomFactor) const
735231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
736231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    switch (part) {
737231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case SquareButtonPart:
738231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case DefaultButtonPart:
739231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case ButtonPart:
7405e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        case ListButtonPart:
741231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return LengthBox(0, zoomedBox.right().value(), 0, zoomedBox.left().value());
742231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        default:
743231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return Theme::controlBorder(part, font, zoomedBox, zoomFactor);
744231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
745231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
746231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
747231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockLengthBox ThemeChromiumMac::controlPadding(ControlPart part, const Font& font, const LengthBox& zoomedBox, float zoomFactor) const
748231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
749231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    switch (part) {
750231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case PushButtonPart: {
751231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // Just use 8px.  AppKit wants to use 11px for mini buttons, but that padding is just too large
752231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is
753231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // by definition constrained, since we select mini only for small cramped environments.
754231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // This also guarantees the HTML <button> will match our rendering by default, since we're using a consistent
755231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // padding.
756231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            const int padding = 8 * zoomFactor;
757231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return LengthBox(0, padding, 0, padding);
758231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
759231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        default:
760231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return Theme::controlPadding(part, font, zoomedBox, zoomFactor);
761231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
762231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
763231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
764231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid ThemeChromiumMac::inflateControlPaintRect(ControlPart part, ControlStates states, IntRect& zoomedRect, float zoomFactor) const
765231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
766231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    BEGIN_BLOCK_OBJC_EXCEPTIONS
767231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    switch (part) {
768231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case CheckboxPart: {
769231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
770231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // shadow" and the check.  We don't consider this part of the bounds of the control in WebKit.
771231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            NSCell *cell = checkbox(states, zoomedRect, zoomFactor);
772231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            NSControlSize controlSize = [cell controlSize];
773231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            IntSize zoomedSize = checkboxSizes()[controlSize];
774231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
775231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
776231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            zoomedRect = inflateRect(zoomedRect, zoomedSize, checkboxMargins(controlSize), zoomFactor);
777231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
778231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
779231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case RadioPart: {
780231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // We inflate the rect as needed to account for padding included in the cell to accommodate the radio button
781231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // shadow".  We don't consider this part of the bounds of the control in WebKit.
782231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            NSCell *cell = radio(states, zoomedRect, zoomFactor);
783231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            NSControlSize controlSize = [cell controlSize];
784231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            IntSize zoomedSize = radioSizes()[controlSize];
785231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
786231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
787231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            zoomedRect = inflateRect(zoomedRect, zoomedSize, radioMargins(controlSize), zoomFactor);
788231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
789231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
790231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case PushButtonPart:
791231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case DefaultButtonPart:
792231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case ButtonPart: {
793231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            NSButtonCell *cell = button(part, states, zoomedRect, zoomFactor);
794231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            NSControlSize controlSize = [cell controlSize];
795231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
796231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // We inflate the rect as needed to account for the Aqua button's shadow.
797231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if ([cell bezelStyle] == NSRoundedBezelStyle) {
798231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                IntSize zoomedSize = buttonSizes()[controlSize];
799231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
800231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                zoomedSize.setWidth(zoomedRect.width()); // Buttons don't ever constrain width, so the zoomed width can just be honored.
801231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                zoomedRect = inflateRect(zoomedRect, zoomedSize, buttonMargins(controlSize), zoomFactor);
802231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            }
803231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
804231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
805967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        case OuterSpinButtonPart: {
806967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            static const int stepperMargin[4] = { 0, 0, 0, 0 };
807967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            ControlSize controlSize = controlSizeFromPixelSize(stepperSizes(), zoomedRect.size(), zoomFactor);
808967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            IntSize zoomedSize = stepperSizes()[controlSize];
809967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
810967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
811967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            zoomedRect = inflateRect(zoomedRect, zoomedSize, stepperMargin, zoomFactor);
812967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            break;
813967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        }
814231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        default:
815231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
816231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
817231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    END_BLOCK_OBJC_EXCEPTIONS
818231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
819231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
820231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid ThemeChromiumMac::paint(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) const
821231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
822231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    switch (part) {
823231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case CheckboxPart:
824231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            paintCheckbox(states, context, zoomedRect, zoomFactor, scrollView);
825231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
826231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case RadioPart:
827231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            paintRadio(states, context, zoomedRect, zoomFactor, scrollView);
828231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
829231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case PushButtonPart:
830231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case DefaultButtonPart:
831231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case ButtonPart:
832231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        case SquareButtonPart:
8335e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        case ListButtonPart:
834231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            paintButton(part, states, context, zoomedRect, zoomFactor, scrollView);
835231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
836967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        case OuterSpinButtonPart:
837967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            paintStepper(states, context, zoomedRect, zoomFactor, scrollView);
838967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            break;
839231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        default:
840231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            break;
841231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
842231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
843231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
844231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
845