widget/cocoa/nsNativeThemeCocoa.mm

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsNativeThemeCocoa.h"
michael@0 7 #include "nsObjCExceptions.h"
michael@0 8 #include "nsNumberControlFrame.h"
michael@0 9 #include "nsRangeFrame.h"
michael@0 10 #include "nsRenderingContext.h"
michael@0 11 #include "nsRect.h"
michael@0 12 #include "nsSize.h"
michael@0 13 #include "nsThemeConstants.h"
michael@0 14 #include "nsIPresShell.h"
michael@0 15 #include "nsPresContext.h"
michael@0 16 #include "nsIContent.h"
michael@0 17 #include "nsIDocument.h"
michael@0 18 #include "nsIFrame.h"
michael@0 19 #include "nsIAtom.h"
michael@0 20 #include "nsNameSpaceManager.h"
michael@0 21 #include "nsPresContext.h"
michael@0 22 #include "nsGkAtoms.h"
michael@0 23 #include "nsCocoaFeatures.h"
michael@0 24 #include "nsCocoaWindow.h"
michael@0 25 #include "nsNativeThemeColors.h"
michael@0 26 #include "nsIScrollableFrame.h"
michael@0 27 #include "mozilla/EventStates.h"
michael@0 28 #include "mozilla/dom/Element.h"
michael@0 29 #include "mozilla/dom/HTMLMeterElement.h"
michael@0 30 #include "nsLookAndFeel.h"
michael@0 31
michael@0 32 #include "gfxContext.h"
michael@0 33 #include "gfxQuartzSurface.h"
michael@0 34 #include "gfxQuartzNativeDrawing.h"
michael@0 35 #include <algorithm>
michael@0 36
michael@0 37 using namespace mozilla;
michael@0 38 using namespace mozilla::gfx;
michael@0 39 using mozilla::dom::HTMLMeterElement;
michael@0 40
michael@0 41 #define DRAW_IN_FRAME_DEBUG 0
michael@0 42 #define SCROLLBARS_VISUAL_DEBUG 0
michael@0 43
michael@0 44 // private Quartz routines needed here
michael@0 45 extern "C" {
michael@0 46 CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
michael@0 47 }
michael@0 48
michael@0 49 // Workaround for NSCell control tint drawing
michael@0 50 // Without this workaround, NSCells are always drawn with the clear control tint
michael@0 51 // as long as they're not attached to an NSControl which is a subview of an active window.
michael@0 52 // XXXmstange Why doesn't Webkit need this?
michael@0 53 @implementation NSCell (ControlTintWorkaround)
michael@0 54 - (int)_realControlTint { return [self controlTint]; }
michael@0 55 @end
michael@0 56
michael@0 57 // The purpose of this class is to provide objects that can be used when drawing
michael@0 58 // NSCells using drawWithFrame:inView: without causing any harm. The only
michael@0 59 // messages that will be sent to such an object are "isFlipped" and
michael@0 60 // "currentEditor": isFlipped needs to return YES in order to avoid drawing bugs
michael@0 61 // on 10.4 (see bug 465069); currentEditor (which isn't even a method of
michael@0 62 // NSView) will be called when drawing search fields, and we only provide it in
michael@0 63 // order to prevent "unrecognized selector" exceptions.
michael@0 64 // There's no need to pass the actual NSView that we're drawing into to
michael@0 65 // drawWithFrame:inView:. What's more, doing so even causes unnecessary
michael@0 66 // invalidations as soon as we draw a focusring!
michael@0 67 @interface CellDrawView : NSView
michael@0 68
michael@0 69 @end;
michael@0 70
michael@0 71 @implementation CellDrawView
michael@0 72
michael@0 73 - (BOOL)isFlipped
michael@0 74 {
michael@0 75 return YES;
michael@0 76 }
michael@0 77
michael@0 78 - (NSText*)currentEditor
michael@0 79 {
michael@0 80 return nil;
michael@0 81 }
michael@0 82
michael@0 83 @end
michael@0 84
michael@0 85 static void
michael@0 86 DrawCellIncludingFocusRing(NSCell* aCell, NSRect aWithFrame, NSView* aInView)
michael@0 87 {
michael@0 88 [aCell drawWithFrame:aWithFrame inView:aInView];
michael@0 89
michael@0 90 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
michael@0 91 // When building with the 10.8 SDK or higher, focus rings don't draw as part
michael@0 92 // of -[NSCell drawWithFrame:inView:] and must be drawn by a separate call
michael@0 93 // to -[NSCell drawFocusRingMaskWithFrame:inView:]; .
michael@0 94 // See the NSButtonCell section under
michael@0 95 // https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKitOlderNotes/#X10_8Notes
michael@0 96 if ([aCell showsFirstResponder]) {
michael@0 97 CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
michael@0 98 CGContextSaveGState(cgContext);
michael@0 99
michael@0 100 // It's important to set the focus ring style before we enter the
michael@0 101 // transparency layer so that the transparency layer only contains
michael@0 102 // the normal button mask without the focus ring, and the conversion
michael@0 103 // to the focus ring shape happens only when the transparency layer is
michael@0 104 // ended.
michael@0 105 NSSetFocusRingStyle(NSFocusRingOnly);
michael@0 106
michael@0 107 // We need to draw the whole button into a transparency layer because
michael@0 108 // many button types are composed of multiple parts, and if these parts
michael@0 109 // were drawn while the focus ring style was active, each individual part
michael@0 110 // would produce a focus ring for itself. But we only want one focus ring
michael@0 111 // for the whole button. The transparency layer is a way to merge the
michael@0 112 // individual button parts together before the focus ring shape is
michael@0 113 // calculated.
michael@0 114 CGContextBeginTransparencyLayerWithRect(cgContext, NSRectToCGRect(aWithFrame), 0);
michael@0 115 [aCell drawFocusRingMaskWithFrame:aWithFrame inView:aInView];
michael@0 116 CGContextEndTransparencyLayer(cgContext);
michael@0 117
michael@0 118 CGContextRestoreGState(cgContext);
michael@0 119 }
michael@0 120 #endif
michael@0 121 }
michael@0 122
michael@0 123 /**
michael@0 124 * NSProgressBarCell is used to draw progress bars of any size.
michael@0 125 */
michael@0 126 @interface NSProgressBarCell : NSCell
michael@0 127 {
michael@0 128 /*All instance variables are private*/
michael@0 129 double mValue;
michael@0 130 double mMax;
michael@0 131 bool mIsIndeterminate;
michael@0 132 bool mIsHorizontal;
michael@0 133 }
michael@0 134
michael@0 135 - (void)setValue:(double)value;
michael@0 136 - (double)value;
michael@0 137 - (void)setMax:(double)max;
michael@0 138 - (double)max;
michael@0 139 - (void)setIndeterminate:(bool)aIndeterminate;
michael@0 140 - (bool)isIndeterminate;
michael@0 141 - (void)setHorizontal:(bool)aIsHorizontal;
michael@0 142 - (bool)isHorizontal;
michael@0 143 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;
michael@0 144 @end
michael@0 145
michael@0 146 @implementation NSProgressBarCell
michael@0 147
michael@0 148 - (void)setMax:(double)aMax
michael@0 149 {
michael@0 150 mMax = aMax;
michael@0 151 }
michael@0 152
michael@0 153 - (double)max
michael@0 154 {
michael@0 155 return mMax;
michael@0 156 }
michael@0 157
michael@0 158 - (void)setValue:(double)aValue
michael@0 159 {
michael@0 160 mValue = aValue;
michael@0 161 }
michael@0 162
michael@0 163 - (double)value
michael@0 164 {
michael@0 165 return mValue;
michael@0 166 }
michael@0 167
michael@0 168 - (void)setIndeterminate:(bool)aIndeterminate
michael@0 169 {
michael@0 170 mIsIndeterminate = aIndeterminate;
michael@0 171 }
michael@0 172
michael@0 173 - (bool)isIndeterminate
michael@0 174 {
michael@0 175 return mIsIndeterminate;
michael@0 176 }
michael@0 177
michael@0 178 - (void)setHorizontal:(bool)aIsHorizontal
michael@0 179 {
michael@0 180 mIsHorizontal = aIsHorizontal;
michael@0 181 }
michael@0 182
michael@0 183 - (bool)isHorizontal
michael@0 184 {
michael@0 185 return mIsHorizontal;
michael@0 186 }
michael@0 187
michael@0 188 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
michael@0 189 {
michael@0 190 CGContext* cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
michael@0 191
michael@0 192 HIThemeTrackDrawInfo tdi;
michael@0 193
michael@0 194 tdi.version = 0;
michael@0 195 tdi.min = 0;
michael@0 196
michael@0 197 tdi.value = INT32_MAX * (mValue / mMax);
michael@0 198 tdi.max = INT32_MAX;
michael@0 199 tdi.bounds = NSRectToCGRect(cellFrame);
michael@0 200 tdi.attributes = mIsHorizontal ? kThemeTrackHorizontal : 0;
michael@0 201 tdi.enableState = [self controlTint] == NSClearControlTint ? kThemeTrackInactive
michael@0 202 : kThemeTrackActive;
michael@0 203
michael@0 204 NSControlSize size = [self controlSize];
michael@0 205 if (size == NSRegularControlSize) {
michael@0 206 tdi.kind = mIsIndeterminate ? kThemeLargeIndeterminateBar
michael@0 207 : kThemeLargeProgressBar;
michael@0 208 } else {
michael@0 209 NS_ASSERTION(size == NSSmallControlSize,
michael@0 210 "We shouldn't have another size than small and regular for the moment");
michael@0 211 tdi.kind = mIsIndeterminate ? kThemeMediumIndeterminateBar
michael@0 212 : kThemeMediumProgressBar;
michael@0 213 }
michael@0 214
michael@0 215 int32_t stepsPerSecond = mIsIndeterminate ? 60 : 30;
michael@0 216 int32_t milliSecondsPerStep = 1000 / stepsPerSecond;
michael@0 217 tdi.trackInfo.progress.phase = uint8_t(PR_IntervalToMilliseconds(PR_IntervalNow()) /
michael@0 218 milliSecondsPerStep);
michael@0 219
michael@0 220 HIThemeDrawTrack(&tdi, NULL, cgContext, kHIThemeOrientationNormal);
michael@0 221 }
michael@0 222
michael@0 223 @end
michael@0 224
michael@0 225 @interface ContextAwareSearchFieldCell : NSSearchFieldCell
michael@0 226 {
michael@0 227 nsIFrame* mContext;
michael@0 228 }
michael@0 229
michael@0 230 // setContext: stores the searchfield nsIFrame so that it can be consulted
michael@0 231 // during painting. Please reset this by calling setContext:nullptr as soon as
michael@0 232 // you're done with painting because we don't want to keep a dangling pointer.
michael@0 233 - (void)setContext:(nsIFrame*)aContext;
michael@0 234 @end
michael@0 235
michael@0 236 @implementation ContextAwareSearchFieldCell
michael@0 237
michael@0 238 - (id)initTextCell:(NSString*)aString
michael@0 239 {
michael@0 240 if ((self = [super initTextCell:aString])) {
michael@0 241 mContext = nullptr;
michael@0 242 }
michael@0 243 return self;
michael@0 244 }
michael@0 245
michael@0 246 - (void)setContext:(nsIFrame*)aContext
michael@0 247 {
michael@0 248 mContext = aContext;
michael@0 249 }
michael@0 250
michael@0 251 static BOOL IsToolbarStyleContainer(nsIFrame* aFrame)
michael@0 252 {
michael@0 253 nsIContent* content = aFrame->GetContent();
michael@0 254 if (!content)
michael@0 255 return NO;
michael@0 256
michael@0 257 if (content->Tag() == nsGkAtoms::toolbar ||
michael@0 258 content->Tag() == nsGkAtoms::toolbox ||
michael@0 259 content->Tag() == nsGkAtoms::statusbar)
michael@0 260 return YES;
michael@0 261
michael@0 262 switch (aFrame->StyleDisplay()->mAppearance) {
michael@0 263 case NS_THEME_TOOLBAR:
michael@0 264 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
michael@0 265 case NS_THEME_STATUSBAR:
michael@0 266 return YES;
michael@0 267 default:
michael@0 268 return NO;
michael@0 269 }
michael@0 270 }
michael@0 271
michael@0 272 - (BOOL)_isToolbarMode
michael@0 273 {
michael@0 274 // On 10.7, searchfields have two different styles, depending on whether
michael@0 275 // the searchfield is on top of of window chrome. This function is called on
michael@0 276 // 10.7 during drawing in order to determine which style to use.
michael@0 277 for (nsIFrame* frame = mContext; frame; frame = frame->GetParent()) {
michael@0 278 if (IsToolbarStyleContainer(frame)) {
michael@0 279 return YES;
michael@0 280 }
michael@0 281 }
michael@0 282 return NO;
michael@0 283 }
michael@0 284
michael@0 285 @end
michael@0 286
michael@0 287 // Workaround for Bug 542048
michael@0 288 // On 64-bit, NSSearchFieldCells don't draw focus rings.
michael@0 289 #if defined(__x86_64__)
michael@0 290
michael@0 291 static void DrawFocusRing(NSRect rect, float radius)
michael@0 292 {
michael@0 293 NSSetFocusRingStyle(NSFocusRingOnly);
michael@0 294 NSBezierPath* path = [NSBezierPath bezierPath];
michael@0 295 rect = NSInsetRect(rect, radius, radius);
michael@0 296 [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMinY(rect)) radius:radius startAngle:180.0 endAngle:270.0];
michael@0 297 [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMinY(rect)) radius:radius startAngle:270.0 endAngle:360.0];
michael@0 298 [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMaxY(rect)) radius:radius startAngle: 0.0 endAngle: 90.0];
michael@0 299 [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMaxY(rect)) radius:radius startAngle: 90.0 endAngle:180.0];
michael@0 300 [path closePath];
michael@0 301 [path fill];
michael@0 302 }
michael@0 303
michael@0 304 @interface SearchFieldCellWithFocusRing : ContextAwareSearchFieldCell {} @end
michael@0 305
michael@0 306 @implementation SearchFieldCellWithFocusRing
michael@0 307
michael@0 308 - (void)drawWithFrame:(NSRect)rect inView:(NSView*)controlView
michael@0 309 {
michael@0 310 [super drawWithFrame:rect inView:controlView];
michael@0 311 if ([self showsFirstResponder]) {
michael@0 312 DrawFocusRing(rect, NSHeight(rect) / 2);
michael@0 313 }
michael@0 314 }
michael@0 315
michael@0 316 @end
michael@0 317
michael@0 318 #endif
michael@0 319
michael@0 320 // Copied from nsLookAndFeel.h
michael@0 321 // Apple hasn't defined a constant for scollbars with two arrows on each end, so we'll use this one.
michael@0 322 static const int kThemeScrollBarArrowsBoth = 2;
michael@0 323
michael@0 324 #define HITHEME_ORIENTATION kHIThemeOrientationNormal
michael@0 325 #define MAX_FOCUS_RING_WIDTH 4
michael@0 326
michael@0 327 // These enums are for indexing into the margin array.
michael@0 328 enum {
michael@0 329 leopardOS = 0
michael@0 330 };
michael@0 331
michael@0 332 enum {
michael@0 333 miniControlSize,
michael@0 334 smallControlSize,
michael@0 335 regularControlSize
michael@0 336 };
michael@0 337
michael@0 338 enum {
michael@0 339 leftMargin,
michael@0 340 topMargin,
michael@0 341 rightMargin,
michael@0 342 bottomMargin
michael@0 343 };
michael@0 344
michael@0 345 static int EnumSizeForCocoaSize(NSControlSize cocoaControlSize) {
michael@0 346 if (cocoaControlSize == NSMiniControlSize)
michael@0 347 return miniControlSize;
michael@0 348 else if (cocoaControlSize == NSSmallControlSize)
michael@0 349 return smallControlSize;
michael@0 350 else
michael@0 351 return regularControlSize;
michael@0 352 }
michael@0 353
michael@0 354 static NSControlSize CocoaSizeForEnum(int32_t enumControlSize) {
michael@0 355 if (enumControlSize == miniControlSize)
michael@0 356 return NSMiniControlSize;
michael@0 357 else if (enumControlSize == smallControlSize)
michael@0 358 return NSSmallControlSize;
michael@0 359 else
michael@0 360 return NSRegularControlSize;
michael@0 361 }
michael@0 362
michael@0 363 static NSString* CUIControlSizeForCocoaSize(NSControlSize aControlSize)
michael@0 364 {
michael@0 365 if (aControlSize == NSRegularControlSize)
michael@0 366 return @"regular";
michael@0 367 else if (aControlSize == NSSmallControlSize)
michael@0 368 return @"small";
michael@0 369 else
michael@0 370 return @"mini";
michael@0 371 }
michael@0 372
michael@0 373 static void InflateControlRect(NSRect* rect, NSControlSize cocoaControlSize, const float marginSet[][3][4])
michael@0 374 {
michael@0 375 if (!marginSet)
michael@0 376 return;
michael@0 377
michael@0 378 static int osIndex = leopardOS;
michael@0 379 int controlSize = EnumSizeForCocoaSize(cocoaControlSize);
michael@0 380 const float* buttonMargins = marginSet[osIndex][controlSize];
michael@0 381 rect->origin.x -= buttonMargins[leftMargin];
michael@0 382 rect->origin.y -= buttonMargins[bottomMargin];
michael@0 383 rect->size.width += buttonMargins[leftMargin] + buttonMargins[rightMargin];
michael@0 384 rect->size.height += buttonMargins[bottomMargin] + buttonMargins[topMargin];
michael@0 385 }
michael@0 386
michael@0 387 static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
michael@0 388 nsIWidget** aTopLevelWidget = NULL)
michael@0 389 {
michael@0 390 if (!aFrame)
michael@0 391 return nil;
michael@0 392
michael@0 393 nsIWidget* widget = aFrame->GetNearestWidget();
michael@0 394 if (!widget)
michael@0 395 return nil;
michael@0 396
michael@0 397 nsIWidget* topLevelWidget = widget->GetTopLevelWidget();
michael@0 398 if (aTopLevelWidget)
michael@0 399 *aTopLevelWidget = topLevelWidget;
michael@0 400
michael@0 401 return (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW);
michael@0 402 }
michael@0 403
michael@0 404 static NSSize
michael@0 405 WindowButtonsSize(nsIFrame* aFrame)
michael@0 406 {
michael@0 407 NSWindow* window = NativeWindowForFrame(aFrame);
michael@0 408 if (!window) {
michael@0 409 // Return fallback values.
michael@0 410 if (!nsCocoaFeatures::OnLionOrLater())
michael@0 411 return NSMakeSize(57, 16);
michael@0 412 return NSMakeSize(54, 16);
michael@0 413 }
michael@0 414
michael@0 415 NSRect buttonBox = NSZeroRect;
michael@0 416 NSButton* closeButton = [window standardWindowButton:NSWindowCloseButton];
michael@0 417 if (closeButton) {
michael@0 418 buttonBox = NSUnionRect(buttonBox, [closeButton frame]);
michael@0 419 }
michael@0 420 NSButton* minimizeButton = [window standardWindowButton:NSWindowMiniaturizeButton];
michael@0 421 if (minimizeButton) {
michael@0 422 buttonBox = NSUnionRect(buttonBox, [minimizeButton frame]);
michael@0 423 }
michael@0 424 NSButton* zoomButton = [window standardWindowButton:NSWindowZoomButton];
michael@0 425 if (zoomButton) {
michael@0 426 buttonBox = NSUnionRect(buttonBox, [zoomButton frame]);
michael@0 427 }
michael@0 428 return buttonBox.size;
michael@0 429 }
michael@0 430
michael@0 431 static BOOL FrameIsInActiveWindow(nsIFrame* aFrame)
michael@0 432 {
michael@0 433 nsIWidget* topLevelWidget = NULL;
michael@0 434 NSWindow* win = NativeWindowForFrame(aFrame, &topLevelWidget);
michael@0 435 if (!topLevelWidget || !win)
michael@0 436 return YES;
michael@0 437
michael@0 438 // XUL popups, e.g. the toolbar customization popup, can't become key windows,
michael@0 439 // but controls in these windows should still get the active look.
michael@0 440 if (topLevelWidget->WindowType() == eWindowType_popup)
michael@0 441 return YES;
michael@0 442 if ([win isSheet])
michael@0 443 return [win isKeyWindow];
michael@0 444 return [win isMainWindow] && ![win attachedSheet];
michael@0 445 }
michael@0 446
michael@0 447 // Toolbar controls and content controls respond to different window
michael@0 448 // activeness states.
michael@0 449 static BOOL IsActive(nsIFrame* aFrame, BOOL aIsToolbarControl)
michael@0 450 {
michael@0 451 if (aIsToolbarControl)
michael@0 452 return [NativeWindowForFrame(aFrame) isMainWindow];
michael@0 453 return FrameIsInActiveWindow(aFrame);
michael@0 454 }
michael@0 455
michael@0 456 NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeCocoa, nsNativeTheme, nsITheme)
michael@0 457
michael@0 458
michael@0 459 nsNativeThemeCocoa::nsNativeThemeCocoa()
michael@0 460 {
michael@0 461 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 462
michael@0 463 // provide a local autorelease pool, as this is called during startup
michael@0 464 // before the main event-loop pool is in place
michael@0 465 nsAutoreleasePool pool;
michael@0 466
michael@0 467 mHelpButtonCell = [[NSButtonCell alloc] initTextCell:nil];
michael@0 468 [mHelpButtonCell setBezelStyle:NSHelpButtonBezelStyle];
michael@0 469 [mHelpButtonCell setButtonType:NSMomentaryPushInButton];
michael@0 470 [mHelpButtonCell setHighlightsBy:NSPushInCellMask];
michael@0 471
michael@0 472 mPushButtonCell = [[NSButtonCell alloc] initTextCell:nil];
michael@0 473 [mPushButtonCell setButtonType:NSMomentaryPushInButton];
michael@0 474 [mPushButtonCell setHighlightsBy:NSPushInCellMask];
michael@0 475
michael@0 476 mRadioButtonCell = [[NSButtonCell alloc] initTextCell:nil];
michael@0 477 [mRadioButtonCell setButtonType:NSRadioButton];
michael@0 478
michael@0 479 mCheckboxCell = [[NSButtonCell alloc] initTextCell:nil];
michael@0 480 [mCheckboxCell setButtonType:NSSwitchButton];
michael@0 481 [mCheckboxCell setAllowsMixedState:YES];
michael@0 482
michael@0 483 #if defined(__x86_64__)
michael@0 484 mSearchFieldCell = [[SearchFieldCellWithFocusRing alloc] initTextCell:@""];
michael@0 485 #else
michael@0 486 mSearchFieldCell = [[ContextAwareSearchFieldCell alloc] initTextCell:@""];
michael@0 487 #endif
michael@0 488 [mSearchFieldCell setBezelStyle:NSTextFieldRoundedBezel];
michael@0 489 [mSearchFieldCell setBezeled:YES];
michael@0 490 [mSearchFieldCell setEditable:YES];
michael@0 491 [mSearchFieldCell setFocusRingType:NSFocusRingTypeExterior];
michael@0 492
michael@0 493 mDropdownCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
michael@0 494
michael@0 495 mComboBoxCell = [[NSComboBoxCell alloc] initTextCell:@""];
michael@0 496 [mComboBoxCell setBezeled:YES];
michael@0 497 [mComboBoxCell setEditable:YES];
michael@0 498 [mComboBoxCell setFocusRingType:NSFocusRingTypeExterior];
michael@0 499
michael@0 500 mProgressBarCell = [[NSProgressBarCell alloc] init];
michael@0 501
michael@0 502 mMeterBarCell = [[NSLevelIndicatorCell alloc]
michael@0 503 initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle];
michael@0 504
michael@0 505 mCellDrawView = [[CellDrawView alloc] init];
michael@0 506
michael@0 507 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 508 }
michael@0 509
michael@0 510 nsNativeThemeCocoa::~nsNativeThemeCocoa()
michael@0 511 {
michael@0 512 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 513
michael@0 514 [mMeterBarCell release];
michael@0 515 [mProgressBarCell release];
michael@0 516 [mHelpButtonCell release];
michael@0 517 [mPushButtonCell release];
michael@0 518 [mRadioButtonCell release];
michael@0 519 [mCheckboxCell release];
michael@0 520 [mSearchFieldCell release];
michael@0 521 [mDropdownCell release];
michael@0 522 [mComboBoxCell release];
michael@0 523 [mCellDrawView release];
michael@0 524
michael@0 525 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 526 }
michael@0 527
michael@0 528 // Limit on the area of the target rect (in pixels^2) in
michael@0 529 // DrawCellWithScaling(), DrawButton() and DrawScrollbar(), above which we
michael@0 530 // don't draw the object into a bitmap buffer. This is to avoid crashes in
michael@0 531 // [NSGraphicsContext graphicsContextWithGraphicsPort:flipped:] and
michael@0 532 // CGContextDrawImage(), and also to avoid very poor drawing performance in
michael@0 533 // CGContextDrawImage() when it scales the bitmap (particularly if xscale or
michael@0 534 // yscale is less than but near 1 -- e.g. 0.9). This value was determined
michael@0 535 // by trial and error, on OS X 10.4.11 and 10.5.4, and on systems with
michael@0 536 // different amounts of RAM.
michael@0 537 #define BITMAP_MAX_AREA 500000
michael@0 538
michael@0 539 static int
michael@0 540 GetBackingScaleFactorForRendering(CGContextRef cgContext)
michael@0 541 {
michael@0 542 CGAffineTransform ctm = CGContextGetUserSpaceToDeviceSpaceTransform(cgContext);
michael@0 543 CGRect transformedUserSpacePixel = CGRectApplyAffineTransform(CGRectMake(0, 0, 1, 1), ctm);
michael@0 544 float maxScale = std::max(fabs(transformedUserSpacePixel.size.width),
michael@0 545 fabs(transformedUserSpacePixel.size.height));
michael@0 546 return maxScale > 1.0 ? 2 : 1;
michael@0 547 }
michael@0 548
michael@0 549 /*
michael@0 550 * Draw the given NSCell into the given cgContext.
michael@0 551 *
michael@0 552 * destRect - the size and position of the resulting control rectangle
michael@0 553 * controlSize - the NSControlSize which will be given to the NSCell before
michael@0 554 * asking it to render
michael@0 555 * naturalSize - The natural dimensions of this control.
michael@0 556 * If the control rect size is not equal to either of these, a scale
michael@0 557 * will be applied to the context so that rendering the control at the
michael@0 558 * natural size will result in it filling the destRect space.
michael@0 559 * If a control has no natural dimensions in either/both axes, pass 0.0f.
michael@0 560 * minimumSize - The minimum dimensions of this control.
michael@0 561 * If the control rect size is less than the minimum for a given axis,
michael@0 562 * a scale will be applied to the context so that the minimum is used
michael@0 563 * for drawing. If a control has no minimum dimensions in either/both
michael@0 564 * axes, pass 0.0f.
michael@0 565 * marginSet - an array of margins; a multidimensional array of [2][3][4],
michael@0 566 * with the first dimension being the OS version (Tiger or Leopard),
michael@0 567 * the second being the control size (mini, small, regular), and the third
michael@0 568 * being the 4 margin values (left, top, right, bottom).
michael@0 569 * view - The NSView that we're drawing into. As far as I can tell, it doesn't
michael@0 570 * matter if this is really the right view; it just has to return YES when
michael@0 571 * asked for isFlipped. Otherwise we'll get drawing bugs on 10.4.
michael@0 572 * mirrorHorizontal - whether to mirror the cell horizontally
michael@0 573 */
michael@0 574 static void DrawCellWithScaling(NSCell *cell,
michael@0 575 CGContextRef cgContext,
michael@0 576 const HIRect& destRect,
michael@0 577 NSControlSize controlSize,
michael@0 578 NSSize naturalSize,
michael@0 579 NSSize minimumSize,
michael@0 580 const float marginSet[][3][4],
michael@0 581 NSView* view,
michael@0 582 BOOL mirrorHorizontal)
michael@0 583 {
michael@0 584 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 585
michael@0 586 NSRect drawRect = NSMakeRect(destRect.origin.x, destRect.origin.y, destRect.size.width, destRect.size.height);
michael@0 587
michael@0 588 if (naturalSize.width != 0.0f)
michael@0 589 drawRect.size.width = naturalSize.width;
michael@0 590 if (naturalSize.height != 0.0f)
michael@0 591 drawRect.size.height = naturalSize.height;
michael@0 592
michael@0 593 // Keep aspect ratio when scaling if one dimension is free.
michael@0 594 if (naturalSize.width == 0.0f && naturalSize.height != 0.0f)
michael@0 595 drawRect.size.width = destRect.size.width * naturalSize.height / destRect.size.height;
michael@0 596 if (naturalSize.height == 0.0f && naturalSize.width != 0.0f)
michael@0 597 drawRect.size.height = destRect.size.height * naturalSize.width / destRect.size.width;
michael@0 598
michael@0 599 // Honor minimum sizes.
michael@0 600 if (drawRect.size.width < minimumSize.width)
michael@0 601 drawRect.size.width = minimumSize.width;
michael@0 602 if (drawRect.size.height < minimumSize.height)
michael@0 603 drawRect.size.height = minimumSize.height;
michael@0 604
michael@0 605 [NSGraphicsContext saveGraphicsState];
michael@0 606
michael@0 607 // Only skip the buffer if the area of our cell (in pixels^2) is too large.
michael@0 608 if (drawRect.size.width * drawRect.size.height > BITMAP_MAX_AREA) {
michael@0 609 // Inflate the rect Gecko gave us by the margin for the control.
michael@0 610 InflateControlRect(&drawRect, controlSize, marginSet);
michael@0 611
michael@0 612 NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
michael@0 613 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]];
michael@0 614
michael@0 615 DrawCellIncludingFocusRing(cell, drawRect, view);
michael@0 616
michael@0 617 [NSGraphicsContext setCurrentContext:savedContext];
michael@0 618 }
michael@0 619 else {
michael@0 620 float w = ceil(drawRect.size.width);
michael@0 621 float h = ceil(drawRect.size.height);
michael@0 622 NSRect tmpRect = NSMakeRect(MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH, w, h);
michael@0 623
michael@0 624 // inflate to figure out the frame we need to tell NSCell to draw in, to get something that's 0,0,w,h
michael@0 625 InflateControlRect(&tmpRect, controlSize, marginSet);
michael@0 626
michael@0 627 // and then, expand by MAX_FOCUS_RING_WIDTH size to make sure we can capture any focus ring
michael@0 628 w += MAX_FOCUS_RING_WIDTH * 2.0;
michael@0 629 h += MAX_FOCUS_RING_WIDTH * 2.0;
michael@0 630
michael@0 631 int backingScaleFactor = GetBackingScaleFactorForRendering(cgContext);
michael@0 632 CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
michael@0 633 CGContextRef ctx = CGBitmapContextCreate(NULL,
michael@0 634 (int) w * backingScaleFactor, (int) h * backingScaleFactor,
michael@0 635 8, (int) w * backingScaleFactor * 4,
michael@0 636 rgb, kCGImageAlphaPremultipliedFirst);
michael@0 637 CGColorSpaceRelease(rgb);
michael@0 638
michael@0 639 // We need to flip the image twice in order to avoid drawing bugs on 10.4, see bug 465069.
michael@0 640 // This is the first flip transform, applied to cgContext.
michael@0 641 CGContextScaleCTM(cgContext, 1.0f, -1.0f);
michael@0 642 CGContextTranslateCTM(cgContext, 0.0f, -(2.0 * destRect.origin.y + destRect.size.height));
michael@0 643 if (mirrorHorizontal) {
michael@0 644 CGContextScaleCTM(cgContext, -1.0f, 1.0f);
michael@0 645 CGContextTranslateCTM(cgContext, -(2.0 * destRect.origin.x + destRect.size.width), 0.0f);
michael@0 646 }
michael@0 647
michael@0 648 NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
michael@0 649 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]];
michael@0 650
michael@0 651 CGContextScaleCTM(ctx, backingScaleFactor, backingScaleFactor);
michael@0 652
michael@0 653 // This is the second flip transform, applied to ctx.
michael@0 654 CGContextScaleCTM(ctx, 1.0f, -1.0f);
michael@0 655 CGContextTranslateCTM(ctx, 0.0f, -(2.0 * tmpRect.origin.y + tmpRect.size.height));
michael@0 656
michael@0 657 DrawCellIncludingFocusRing(cell, tmpRect, view);
michael@0 658
michael@0 659 [NSGraphicsContext setCurrentContext:savedContext];
michael@0 660
michael@0 661 CGImageRef img = CGBitmapContextCreateImage(ctx);
michael@0 662
michael@0 663 // Drop the image into the original destination rectangle, scaling to fit
michael@0 664 // Only scale MAX_FOCUS_RING_WIDTH by xscale/yscale when the resulting rect
michael@0 665 // doesn't extend beyond the overflow rect
michael@0 666 float xscale = destRect.size.width / drawRect.size.width;
michael@0 667 float yscale = destRect.size.height / drawRect.size.height;
michael@0 668 float scaledFocusRingX = xscale < 1.0f ? MAX_FOCUS_RING_WIDTH * xscale : MAX_FOCUS_RING_WIDTH;
michael@0 669 float scaledFocusRingY = yscale < 1.0f ? MAX_FOCUS_RING_WIDTH * yscale : MAX_FOCUS_RING_WIDTH;
michael@0 670 CGContextDrawImage(cgContext, CGRectMake(destRect.origin.x - scaledFocusRingX,
michael@0 671 destRect.origin.y - scaledFocusRingY,
michael@0 672 destRect.size.width + scaledFocusRingX * 2,
michael@0 673 destRect.size.height + scaledFocusRingY * 2),
michael@0 674 img);
michael@0 675
michael@0 676 CGImageRelease(img);
michael@0 677 CGContextRelease(ctx);
michael@0 678 }
michael@0 679
michael@0 680 [NSGraphicsContext restoreGraphicsState];
michael@0 681
michael@0 682 #if DRAW_IN_FRAME_DEBUG
michael@0 683 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
michael@0 684 CGContextFillRect(cgContext, destRect);
michael@0 685 #endif
michael@0 686
michael@0 687 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 688 }
michael@0 689
michael@0 690 struct CellRenderSettings {
michael@0 691 // The natural dimensions of the control.
michael@0 692 // If a control has no natural dimensions in either/both axes, set to 0.0f.
michael@0 693 NSSize naturalSizes[3];
michael@0 694
michael@0 695 // The minimum dimensions of the control.
michael@0 696 // If a control has no minimum dimensions in either/both axes, set to 0.0f.
michael@0 697 NSSize minimumSizes[3];
michael@0 698
michael@0 699 // A three-dimensional array,
michael@0 700 // with the first dimension being the OS version (only Leopard for the moment),
michael@0 701 // the second being the control size (mini, small, regular), and the third
michael@0 702 // being the 4 margin values (left, top, right, bottom).
michael@0 703 float margins[1][3][4];
michael@0 704 };
michael@0 705
michael@0 706 /*
michael@0 707 * This is a helper method that returns the required NSControlSize given a size
michael@0 708 * and the size of the three controls plus a tolerance.
michael@0 709 * size - The width or the height of the element to draw.
michael@0 710 * sizes - An array with the all the width/height of the element for its
michael@0 711 * different sizes.
michael@0 712 * tolerance - The tolerance as passed to DrawCellWithSnapping.
michael@0 713 * NOTE: returns NSRegularControlSize if all values in 'sizes' are zero.
michael@0 714 */
michael@0 715 static NSControlSize FindControlSize(CGFloat size, const CGFloat* sizes, CGFloat tolerance)
michael@0 716 {
michael@0 717 for (uint32_t i = miniControlSize; i <= regularControlSize; ++i) {
michael@0 718 if (sizes[i] == 0) {
michael@0 719 continue;
michael@0 720 }
michael@0 721
michael@0 722 CGFloat next = 0;
michael@0 723 // Find next value.
michael@0 724 for (uint32_t j = i+1; j <= regularControlSize; ++j) {
michael@0 725 if (sizes[j] != 0) {
michael@0 726 next = sizes[j];
michael@0 727 break;
michael@0 728 }
michael@0 729 }
michael@0 730
michael@0 731 // If it's the latest value, we pick it.
michael@0 732 if (next == 0) {
michael@0 733 return CocoaSizeForEnum(i);
michael@0 734 }
michael@0 735
michael@0 736 if (size <= sizes[i] + tolerance && size < next) {
michael@0 737 return CocoaSizeForEnum(i);
michael@0 738 }
michael@0 739 }
michael@0 740
michael@0 741 // If we are here, that means sizes[] was an array with only empty values
michael@0 742 // or the algorithm above is wrong.
michael@0 743 // The former can happen but the later would be wrong.
michael@0 744 NS_ASSERTION(sizes[0] == 0 && sizes[1] == 0 && sizes[2] == 0,
michael@0 745 "We found no control! We shouldn't be there!");
michael@0 746 return CocoaSizeForEnum(regularControlSize);
michael@0 747 }
michael@0 748
michael@0 749 /*
michael@0 750 * Draw the given NSCell into the given cgContext with a nice control size.
michael@0 751 *
michael@0 752 * This function is similar to DrawCellWithScaling, but it decides what
michael@0 753 * control size to use based on the destRect's size.
michael@0 754 * Scaling is only applied when the difference between the destRect's size
michael@0 755 * and the next smaller natural size is greater than snapTolerance. Otherwise
michael@0 756 * it snaps to the next smaller control size without scaling because unscaled
michael@0 757 * controls look nicer.
michael@0 758 */
michael@0 759 static void DrawCellWithSnapping(NSCell *cell,
michael@0 760 CGContextRef cgContext,
michael@0 761 const HIRect& destRect,
michael@0 762 const CellRenderSettings settings,
michael@0 763 float verticalAlignFactor,
michael@0 764 NSView* view,
michael@0 765 BOOL mirrorHorizontal,
michael@0 766 float snapTolerance = 2.0f)
michael@0 767 {
michael@0 768 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 769
michael@0 770 const float rectWidth = destRect.size.width, rectHeight = destRect.size.height;
michael@0 771 const NSSize *sizes = settings.naturalSizes;
michael@0 772 const NSSize miniSize = sizes[EnumSizeForCocoaSize(NSMiniControlSize)];
michael@0 773 const NSSize smallSize = sizes[EnumSizeForCocoaSize(NSSmallControlSize)];
michael@0 774 const NSSize regularSize = sizes[EnumSizeForCocoaSize(NSRegularControlSize)];
michael@0 775
michael@0 776 HIRect drawRect = destRect;
michael@0 777
michael@0 778 CGFloat controlWidths[3] = { miniSize.width, smallSize.width, regularSize.width };
michael@0 779 NSControlSize controlSizeX = FindControlSize(rectWidth, controlWidths, snapTolerance);
michael@0 780 CGFloat controlHeights[3] = { miniSize.height, smallSize.height, regularSize.height };
michael@0 781 NSControlSize controlSizeY = FindControlSize(rectHeight, controlHeights, snapTolerance);
michael@0 782
michael@0 783 NSControlSize controlSize = NSRegularControlSize;
michael@0 784 int sizeIndex = 0;
michael@0 785
michael@0 786 // At some sizes, don't scale but snap.
michael@0 787 const NSControlSize smallerControlSize =
michael@0 788 EnumSizeForCocoaSize(controlSizeX) < EnumSizeForCocoaSize(controlSizeY) ?
michael@0 789 controlSizeX : controlSizeY;
michael@0 790 const int smallerControlSizeIndex = EnumSizeForCocoaSize(smallerControlSize);
michael@0 791 const NSSize size = sizes[smallerControlSizeIndex];
michael@0 792 float diffWidth = size.width ? rectWidth - size.width : 0.0f;
michael@0 793 float diffHeight = size.height ? rectHeight - size.height : 0.0f;
michael@0 794 if (diffWidth >= 0.0f && diffHeight >= 0.0f &&
michael@0 795 diffWidth <= snapTolerance && diffHeight <= snapTolerance) {
michael@0 796 // Snap to the smaller control size.
michael@0 797 controlSize = smallerControlSize;
michael@0 798 sizeIndex = smallerControlSizeIndex;
michael@0 799 // Resize and center the drawRect.
michael@0 800 if (sizes[sizeIndex].width) {
michael@0 801 drawRect.origin.x += ceil((destRect.size.width - sizes[sizeIndex].width) / 2);
michael@0 802 drawRect.size.width = sizes[sizeIndex].width;
michael@0 803 }
michael@0 804 if (sizes[sizeIndex].height) {
michael@0 805 drawRect.origin.y += floor((destRect.size.height - sizes[sizeIndex].height) * verticalAlignFactor);
michael@0 806 drawRect.size.height = sizes[sizeIndex].height;
michael@0 807 }
michael@0 808 } else {
michael@0 809 // Use the larger control size.
michael@0 810 controlSize = EnumSizeForCocoaSize(controlSizeX) > EnumSizeForCocoaSize(controlSizeY) ?
michael@0 811 controlSizeX : controlSizeY;
michael@0 812 sizeIndex = EnumSizeForCocoaSize(controlSize);
michael@0 813 }
michael@0 814
michael@0 815 [cell setControlSize:controlSize];
michael@0 816
michael@0 817 NSSize minimumSize = settings.minimumSizes ? settings.minimumSizes[sizeIndex] : NSZeroSize;
michael@0 818 DrawCellWithScaling(cell, cgContext, drawRect, controlSize, sizes[sizeIndex],
michael@0 819 minimumSize, settings.margins, view, mirrorHorizontal);
michael@0 820
michael@0 821 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 822 }
michael@0 823
michael@0 824 static float VerticalAlignFactor(nsIFrame *aFrame)
michael@0 825 {
michael@0 826 if (!aFrame)
michael@0 827 return 0.5f; // default: center
michael@0 828
michael@0 829 const nsStyleCoord& va = aFrame->StyleTextReset()->mVerticalAlign;
michael@0 830 uint8_t intval = (va.GetUnit() == eStyleUnit_Enumerated)
michael@0 831 ? va.GetIntValue()
michael@0 832 : NS_STYLE_VERTICAL_ALIGN_MIDDLE;
michael@0 833 switch (intval) {
michael@0 834 case NS_STYLE_VERTICAL_ALIGN_TOP:
michael@0 835 case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
michael@0 836 return 0.0f;
michael@0 837
michael@0 838 case NS_STYLE_VERTICAL_ALIGN_SUB:
michael@0 839 case NS_STYLE_VERTICAL_ALIGN_SUPER:
michael@0 840 case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
michael@0 841 case NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE:
michael@0 842 return 0.5f;
michael@0 843
michael@0 844 case NS_STYLE_VERTICAL_ALIGN_BASELINE:
michael@0 845 case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
michael@0 846 case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
michael@0 847 return 1.0f;
michael@0 848
michael@0 849 default:
michael@0 850 NS_NOTREACHED("invalid vertical-align");
michael@0 851 return 0.5f;
michael@0 852 }
michael@0 853 }
michael@0 854
michael@0 855 // These are the sizes that Gecko needs to request to draw if it wants
michael@0 856 // to get a standard-sized Aqua radio button drawn. Note that the rects
michael@0 857 // that draw these are actually a little bigger.
michael@0 858 static const CellRenderSettings radioSettings = {
michael@0 859 {
michael@0 860 NSMakeSize(11, 11), // mini
michael@0 861 NSMakeSize(13, 13), // small
michael@0 862 NSMakeSize(16, 16) // regular
michael@0 863 },
michael@0 864 {
michael@0 865 NSZeroSize, NSZeroSize, NSZeroSize
michael@0 866 },
michael@0 867 {
michael@0 868 { // Leopard
michael@0 869 {0, 0, 0, 0}, // mini
michael@0 870 {0, 1, 1, 1}, // small
michael@0 871 {0, 0, 0, 0} // regular
michael@0 872 }
michael@0 873 }
michael@0 874 };
michael@0 875
michael@0 876 static const CellRenderSettings checkboxSettings = {
michael@0 877 {
michael@0 878 NSMakeSize(11, 11), // mini
michael@0 879 NSMakeSize(13, 13), // small
michael@0 880 NSMakeSize(16, 16) // regular
michael@0 881 },
michael@0 882 {
michael@0 883 NSZeroSize, NSZeroSize, NSZeroSize
michael@0 884 },
michael@0 885 {
michael@0 886 { // Leopard
michael@0 887 {0, 1, 0, 0}, // mini
michael@0 888 {0, 1, 0, 1}, // small
michael@0 889 {0, 1, 0, 1} // regular
michael@0 890 }
michael@0 891 }
michael@0 892 };
michael@0 893
michael@0 894 void
michael@0 895 nsNativeThemeCocoa::DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox,
michael@0 896 const HIRect& inBoxRect, bool inSelected,
michael@0 897 EventStates inState, nsIFrame* aFrame)
michael@0 898 {
michael@0 899 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 900
michael@0 901 NSButtonCell *cell = inCheckbox ? mCheckboxCell : mRadioButtonCell;
michael@0 902 NSCellStateValue state = inSelected ? NSOnState : NSOffState;
michael@0 903
michael@0 904 // Check if we have an indeterminate checkbox
michael@0 905 if (inCheckbox && GetIndeterminate(aFrame))
michael@0 906 state = NSMixedState;
michael@0 907
michael@0 908 [cell setEnabled:!IsDisabled(aFrame, inState)];
michael@0 909 [cell setShowsFirstResponder:inState.HasState(NS_EVENT_STATE_FOCUS)];
michael@0 910 [cell setState:state];
michael@0 911 [cell setHighlighted:inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)];
michael@0 912 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
michael@0 913
michael@0 914 // Ensure that the control is square.
michael@0 915 float length = std::min(inBoxRect.size.width, inBoxRect.size.height);
michael@0 916 HIRect drawRect = CGRectMake(inBoxRect.origin.x + (int)((inBoxRect.size.width - length) / 2.0f),
michael@0 917 inBoxRect.origin.y + (int)((inBoxRect.size.height - length) / 2.0f),
michael@0 918 length, length);
michael@0 919
michael@0 920 DrawCellWithSnapping(cell, cgContext, drawRect,
michael@0 921 inCheckbox ? checkboxSettings : radioSettings,
michael@0 922 VerticalAlignFactor(aFrame), mCellDrawView, NO);
michael@0 923
michael@0 924 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 925 }
michael@0 926
michael@0 927 static const CellRenderSettings searchFieldSettings = {
michael@0 928 {
michael@0 929 NSMakeSize(0, 16), // mini
michael@0 930 NSMakeSize(0, 19), // small
michael@0 931 NSMakeSize(0, 22) // regular
michael@0 932 },
michael@0 933 {
michael@0 934 NSMakeSize(32, 0), // mini
michael@0 935 NSMakeSize(38, 0), // small
michael@0 936 NSMakeSize(44, 0) // regular
michael@0 937 },
michael@0 938 {
michael@0 939 { // Leopard
michael@0 940 {0, 0, 0, 0}, // mini
michael@0 941 {0, 0, 0, 0}, // small
michael@0 942 {0, 0, 0, 0} // regular
michael@0 943 }
michael@0 944 }
michael@0 945 };
michael@0 946
michael@0 947 void
michael@0 948 nsNativeThemeCocoa::DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 949 nsIFrame* aFrame, EventStates inState)
michael@0 950 {
michael@0 951 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 952
michael@0 953 ContextAwareSearchFieldCell* cell = mSearchFieldCell;
michael@0 954 [cell setContext:aFrame];
michael@0 955 [cell setEnabled:!IsDisabled(aFrame, inState)];
michael@0 956 // NOTE: this could probably use inState
michael@0 957 [cell setShowsFirstResponder:IsFocused(aFrame)];
michael@0 958
michael@0 959 DrawCellWithSnapping(cell, cgContext, inBoxRect, searchFieldSettings,
michael@0 960 VerticalAlignFactor(aFrame), mCellDrawView,
michael@0 961 IsFrameRTL(aFrame));
michael@0 962
michael@0 963 [cell setContext:nullptr];
michael@0 964
michael@0 965 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 966 }
michael@0 967
michael@0 968 static const NSSize kHelpButtonSize = NSMakeSize(20, 20);
michael@0 969
michael@0 970 static const CellRenderSettings pushButtonSettings = {
michael@0 971 {
michael@0 972 NSMakeSize(0, 16), // mini
michael@0 973 NSMakeSize(0, 19), // small
michael@0 974 NSMakeSize(0, 22) // regular
michael@0 975 },
michael@0 976 {
michael@0 977 NSMakeSize(18, 0), // mini
michael@0 978 NSMakeSize(26, 0), // small
michael@0 979 NSMakeSize(30, 0) // regular
michael@0 980 },
michael@0 981 {
michael@0 982 { // Leopard
michael@0 983 {0, 0, 0, 0}, // mini
michael@0 984 {4, 0, 4, 1}, // small
michael@0 985 {5, 0, 5, 2} // regular
michael@0 986 }
michael@0 987 }
michael@0 988 };
michael@0 989
michael@0 990 // The height at which we start doing square buttons instead of rounded buttons
michael@0 991 // Rounded buttons look bad if drawn at a height greater than 26, so at that point
michael@0 992 // we switch over to doing square buttons which looks fine at any size.
michael@0 993 #define DO_SQUARE_BUTTON_HEIGHT 26
michael@0 994
michael@0 995 void
michael@0 996 nsNativeThemeCocoa::DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 997 EventStates inState, uint8_t aWidgetType,
michael@0 998 nsIFrame* aFrame)
michael@0 999 {
michael@0 1000 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1001
michael@0 1002 BOOL isActive = FrameIsInActiveWindow(aFrame);
michael@0 1003 BOOL isDisabled = IsDisabled(aFrame, inState);
michael@0 1004
michael@0 1005 NSButtonCell* cell = (aWidgetType == NS_THEME_MOZ_MAC_HELP_BUTTON) ? mHelpButtonCell : mPushButtonCell;
michael@0 1006 [cell setEnabled:!isDisabled];
michael@0 1007 [cell setHighlighted:isActive &&
michael@0 1008 inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)];
michael@0 1009 [cell setShowsFirstResponder:inState.HasState(NS_EVENT_STATE_FOCUS) && !isDisabled && isActive];
michael@0 1010
michael@0 1011 if (aWidgetType == NS_THEME_MOZ_MAC_HELP_BUTTON) {
michael@0 1012 DrawCellWithScaling(cell, cgContext, inBoxRect, NSRegularControlSize,
michael@0 1013 NSZeroSize, kHelpButtonSize, NULL, mCellDrawView,
michael@0 1014 false); // Don't mirror icon in RTL.
michael@0 1015 } else {
michael@0 1016 // If the button is tall enough, draw the square button style so that
michael@0 1017 // buttons with non-standard content look good. Otherwise draw normal
michael@0 1018 // rounded aqua buttons.
michael@0 1019 if (inBoxRect.size.height > DO_SQUARE_BUTTON_HEIGHT) {
michael@0 1020 [cell setBezelStyle:NSShadowlessSquareBezelStyle];
michael@0 1021 DrawCellWithScaling(cell, cgContext, inBoxRect, NSRegularControlSize,
michael@0 1022 NSZeroSize, NSMakeSize(14, 0), NULL, mCellDrawView,
michael@0 1023 IsFrameRTL(aFrame));
michael@0 1024 } else {
michael@0 1025 [cell setBezelStyle:NSRoundedBezelStyle];
michael@0 1026 DrawCellWithSnapping(cell, cgContext, inBoxRect, pushButtonSettings, 0.5f,
michael@0 1027 mCellDrawView, IsFrameRTL(aFrame), 1.0f);
michael@0 1028 }
michael@0 1029 }
michael@0 1030
michael@0 1031 #if DRAW_IN_FRAME_DEBUG
michael@0 1032 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
michael@0 1033 CGContextFillRect(cgContext, inBoxRect);
michael@0 1034 #endif
michael@0 1035
michael@0 1036 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1037 }
michael@0 1038
michael@0 1039 typedef void (*RenderHIThemeControlFunction)(CGContextRef cgContext, const HIRect& aRenderRect, void* aData);
michael@0 1040
michael@0 1041 static void
michael@0 1042 RenderTransformedHIThemeControl(CGContextRef aCGContext, const HIRect& aRect,
michael@0 1043 RenderHIThemeControlFunction aFunc, void* aData,
michael@0 1044 BOOL mirrorHorizontally = NO)
michael@0 1045 {
michael@0 1046 CGAffineTransform savedCTM = CGContextGetCTM(aCGContext);
michael@0 1047 CGContextTranslateCTM(aCGContext, aRect.origin.x, aRect.origin.y);
michael@0 1048
michael@0 1049 bool drawDirect;
michael@0 1050 HIRect drawRect = aRect;
michael@0 1051 drawRect.origin = CGPointZero;
michael@0 1052
michael@0 1053 if (!mirrorHorizontally && savedCTM.a == 1.0f && savedCTM.b == 0.0f &&
michael@0 1054 savedCTM.c == 0.0f && (savedCTM.d == 1.0f || savedCTM.d == -1.0f)) {
michael@0 1055 drawDirect = TRUE;
michael@0 1056 } else {
michael@0 1057 drawDirect = FALSE;
michael@0 1058 }
michael@0 1059
michael@0 1060 // Fall back to no bitmap buffer if the area of our control (in pixels^2)
michael@0 1061 // is too large.
michael@0 1062 if (drawDirect || (aRect.size.width * aRect.size.height > BITMAP_MAX_AREA)) {
michael@0 1063 aFunc(aCGContext, drawRect, aData);
michael@0 1064 } else {
michael@0 1065 // Inflate the buffer to capture focus rings.
michael@0 1066 int w = ceil(drawRect.size.width) + 2 * MAX_FOCUS_RING_WIDTH;
michael@0 1067 int h = ceil(drawRect.size.height) + 2 * MAX_FOCUS_RING_WIDTH;
michael@0 1068
michael@0 1069 int backingScaleFactor = GetBackingScaleFactorForRendering(aCGContext);
michael@0 1070 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
michael@0 1071 CGContextRef bitmapctx = CGBitmapContextCreate(NULL,
michael@0 1072 w * backingScaleFactor,
michael@0 1073 h * backingScaleFactor,
michael@0 1074 8,
michael@0 1075 w * backingScaleFactor * 4,
michael@0 1076 colorSpace,
michael@0 1077 kCGImageAlphaPremultipliedFirst);
michael@0 1078 CGColorSpaceRelease(colorSpace);
michael@0 1079
michael@0 1080 CGContextScaleCTM(bitmapctx, backingScaleFactor, backingScaleFactor);
michael@0 1081 CGContextTranslateCTM(bitmapctx, MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH);
michael@0 1082
michael@0 1083 // HITheme always wants to draw into a flipped context, or things
michael@0 1084 // get confused.
michael@0 1085 CGContextTranslateCTM(bitmapctx, 0.0f, aRect.size.height);
michael@0 1086 CGContextScaleCTM(bitmapctx, 1.0f, -1.0f);
michael@0 1087
michael@0 1088 aFunc(bitmapctx, drawRect, aData);
michael@0 1089
michael@0 1090 CGImageRef bitmap = CGBitmapContextCreateImage(bitmapctx);
michael@0 1091
michael@0 1092 CGAffineTransform ctm = CGContextGetCTM(aCGContext);
michael@0 1093
michael@0 1094 // We need to unflip, so that we can do a DrawImage without getting a flipped image.
michael@0 1095 CGContextTranslateCTM(aCGContext, 0.0f, aRect.size.height);
michael@0 1096 CGContextScaleCTM(aCGContext, 1.0f, -1.0f);
michael@0 1097
michael@0 1098 if (mirrorHorizontally) {
michael@0 1099 CGContextTranslateCTM(aCGContext, aRect.size.width, 0);
michael@0 1100 CGContextScaleCTM(aCGContext, -1.0f, 1.0f);
michael@0 1101 }
michael@0 1102
michael@0 1103 HIRect inflatedDrawRect = CGRectMake(-MAX_FOCUS_RING_WIDTH, -MAX_FOCUS_RING_WIDTH, w, h);
michael@0 1104 CGContextDrawImage(aCGContext, inflatedDrawRect, bitmap);
michael@0 1105
michael@0 1106 CGContextSetCTM(aCGContext, ctm);
michael@0 1107
michael@0 1108 CGImageRelease(bitmap);
michael@0 1109 CGContextRelease(bitmapctx);
michael@0 1110 }
michael@0 1111
michael@0 1112 CGContextSetCTM(aCGContext, savedCTM);
michael@0 1113 }
michael@0 1114
michael@0 1115 static void
michael@0 1116 RenderButton(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
michael@0 1117 {
michael@0 1118 HIThemeButtonDrawInfo* bdi = (HIThemeButtonDrawInfo*)aData;
michael@0 1119 HIThemeDrawButton(&aRenderRect, bdi, cgContext, kHIThemeOrientationNormal, NULL);
michael@0 1120 }
michael@0 1121
michael@0 1122 void
michael@0 1123 nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, ThemeButtonKind inKind,
michael@0 1124 const HIRect& inBoxRect, bool inIsDefault,
michael@0 1125 ThemeButtonValue inValue, ThemeButtonAdornment inAdornment,
michael@0 1126 EventStates inState, nsIFrame* aFrame)
michael@0 1127 {
michael@0 1128 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1129
michael@0 1130 BOOL isActive = FrameIsInActiveWindow(aFrame);
michael@0 1131 BOOL isDisabled = IsDisabled(aFrame, inState);
michael@0 1132
michael@0 1133 HIThemeButtonDrawInfo bdi;
michael@0 1134 bdi.version = 0;
michael@0 1135 bdi.kind = inKind;
michael@0 1136 bdi.value = inValue;
michael@0 1137 bdi.adornment = inAdornment;
michael@0 1138
michael@0 1139 if (isDisabled) {
michael@0 1140 bdi.state = kThemeStateUnavailable;
michael@0 1141 }
michael@0 1142 else if (inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) {
michael@0 1143 bdi.state = kThemeStatePressed;
michael@0 1144 }
michael@0 1145 else {
michael@0 1146 if (inKind == kThemeArrowButton)
michael@0 1147 bdi.state = kThemeStateUnavailable; // these are always drawn as unavailable
michael@0 1148 else if (!isActive && inKind == kThemeListHeaderButton)
michael@0 1149 bdi.state = kThemeStateInactive;
michael@0 1150 else
michael@0 1151 bdi.state = kThemeStateActive;
michael@0 1152 }
michael@0 1153
michael@0 1154 if (inState.HasState(NS_EVENT_STATE_FOCUS) && isActive)
michael@0 1155 bdi.adornment |= kThemeAdornmentFocus;
michael@0 1156
michael@0 1157 if (inIsDefault && !isDisabled && isActive &&
michael@0 1158 !inState.HasState(NS_EVENT_STATE_ACTIVE)) {
michael@0 1159 bdi.adornment |= kThemeAdornmentDefault;
michael@0 1160 bdi.animation.time.start = 0;
michael@0 1161 bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
michael@0 1162 }
michael@0 1163
michael@0 1164 HIRect drawFrame = inBoxRect;
michael@0 1165
michael@0 1166 if (inKind == kThemePushButton) {
michael@0 1167 drawFrame.size.height -= 2;
michael@0 1168 if (inBoxRect.size.height < pushButtonSettings.naturalSizes[smallControlSize].height) {
michael@0 1169 bdi.kind = kThemePushButtonMini;
michael@0 1170 }
michael@0 1171 else if (inBoxRect.size.height < pushButtonSettings.naturalSizes[regularControlSize].height) {
michael@0 1172 bdi.kind = kThemePushButtonSmall;
michael@0 1173 drawFrame.origin.y -= 1;
michael@0 1174 drawFrame.origin.x += 1;
michael@0 1175 drawFrame.size.width -= 2;
michael@0 1176 }
michael@0 1177 }
michael@0 1178 else if (inKind == kThemeListHeaderButton) {
michael@0 1179 CGContextClipToRect(cgContext, inBoxRect);
michael@0 1180 // Always remove the top border.
michael@0 1181 drawFrame.origin.y -= 1;
michael@0 1182 drawFrame.size.height += 1;
michael@0 1183 // Remove the left border in LTR mode and the right border in RTL mode.
michael@0 1184 drawFrame.size.width += 1;
michael@0 1185 bool isLast = IsLastTreeHeaderCell(aFrame);
michael@0 1186 if (isLast)
michael@0 1187 drawFrame.size.width += 1; // Also remove the other border.
michael@0 1188 if (!IsFrameRTL(aFrame) || isLast)
michael@0 1189 drawFrame.origin.x -= 1;
michael@0 1190 }
michael@0 1191
michael@0 1192 RenderTransformedHIThemeControl(cgContext, drawFrame, RenderButton, &bdi,
michael@0 1193 IsFrameRTL(aFrame));
michael@0 1194
michael@0 1195 #if DRAW_IN_FRAME_DEBUG
michael@0 1196 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
michael@0 1197 CGContextFillRect(cgContext, inBoxRect);
michael@0 1198 #endif
michael@0 1199
michael@0 1200 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1201 }
michael@0 1202
michael@0 1203 static const CellRenderSettings dropdownSettings = {
michael@0 1204 {
michael@0 1205 NSMakeSize(0, 16), // mini
michael@0 1206 NSMakeSize(0, 19), // small
michael@0 1207 NSMakeSize(0, 22) // regular
michael@0 1208 },
michael@0 1209 {
michael@0 1210 NSMakeSize(18, 0), // mini
michael@0 1211 NSMakeSize(38, 0), // small
michael@0 1212 NSMakeSize(44, 0) // regular
michael@0 1213 },
michael@0 1214 {
michael@0 1215 { // Leopard
michael@0 1216 {1, 1, 2, 1}, // mini
michael@0 1217 {3, 0, 3, 1}, // small
michael@0 1218 {3, 0, 3, 0} // regular
michael@0 1219 }
michael@0 1220 }
michael@0 1221 };
michael@0 1222
michael@0 1223 static const CellRenderSettings editableMenulistSettings = {
michael@0 1224 {
michael@0 1225 NSMakeSize(0, 15), // mini
michael@0 1226 NSMakeSize(0, 18), // small
michael@0 1227 NSMakeSize(0, 21) // regular
michael@0 1228 },
michael@0 1229 {
michael@0 1230 NSMakeSize(18, 0), // mini
michael@0 1231 NSMakeSize(38, 0), // small
michael@0 1232 NSMakeSize(44, 0) // regular
michael@0 1233 },
michael@0 1234 {
michael@0 1235 { // Leopard
michael@0 1236 {0, 0, 2, 2}, // mini
michael@0 1237 {0, 0, 3, 2}, // small
michael@0 1238 {0, 1, 3, 3} // regular
michael@0 1239 }
michael@0 1240 }
michael@0 1241 };
michael@0 1242
michael@0 1243 void
michael@0 1244 nsNativeThemeCocoa::DrawDropdown(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 1245 EventStates inState, uint8_t aWidgetType,
michael@0 1246 nsIFrame* aFrame)
michael@0 1247 {
michael@0 1248 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1249
michael@0 1250 [mDropdownCell setPullsDown:(aWidgetType == NS_THEME_BUTTON)];
michael@0 1251
michael@0 1252 BOOL isEditable = (aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD);
michael@0 1253 NSCell* cell = isEditable ? (NSCell*)mComboBoxCell : (NSCell*)mDropdownCell;
michael@0 1254
michael@0 1255 [cell setEnabled:!IsDisabled(aFrame, inState)];
michael@0 1256 [cell setShowsFirstResponder:(IsFocused(aFrame) || inState.HasState(NS_EVENT_STATE_FOCUS))];
michael@0 1257 [cell setHighlighted:IsOpenButton(aFrame)];
michael@0 1258 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
michael@0 1259
michael@0 1260 const CellRenderSettings& settings = isEditable ? editableMenulistSettings : dropdownSettings;
michael@0 1261 DrawCellWithSnapping(cell, cgContext, inBoxRect, settings,
michael@0 1262 0.5f, mCellDrawView, IsFrameRTL(aFrame));
michael@0 1263
michael@0 1264 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1265 }
michael@0 1266
michael@0 1267 static const CellRenderSettings spinnerSettings = {
michael@0 1268 {
michael@0 1269 NSMakeSize(11, 16), // mini (width trimmed by 2px to reduce blank border)
michael@0 1270 NSMakeSize(15, 22), // small
michael@0 1271 NSMakeSize(19, 27) // regular
michael@0 1272 },
michael@0 1273 {
michael@0 1274 NSMakeSize(11, 16), // mini (width trimmed by 2px to reduce blank border)
michael@0 1275 NSMakeSize(15, 22), // small
michael@0 1276 NSMakeSize(19, 27) // regular
michael@0 1277 },
michael@0 1278 {
michael@0 1279 { // Leopard
michael@0 1280 {0, 0, 0, 0}, // mini
michael@0 1281 {0, 0, 0, 0}, // small
michael@0 1282 {0, 0, 0, 0} // regular
michael@0 1283 }
michael@0 1284 }
michael@0 1285 };
michael@0 1286
michael@0 1287 void
michael@0 1288 nsNativeThemeCocoa::DrawSpinButtons(CGContextRef cgContext, ThemeButtonKind inKind,
michael@0 1289 const HIRect& inBoxRect, ThemeDrawState inDrawState,
michael@0 1290 ThemeButtonAdornment inAdornment,
michael@0 1291 EventStates inState, nsIFrame* aFrame)
michael@0 1292 {
michael@0 1293 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1294
michael@0 1295 HIThemeButtonDrawInfo bdi;
michael@0 1296 bdi.version = 0;
michael@0 1297 bdi.kind = inKind;
michael@0 1298 bdi.value = kThemeButtonOff;
michael@0 1299 bdi.adornment = inAdornment;
michael@0 1300
michael@0 1301 if (IsDisabled(aFrame, inState))
michael@0 1302 bdi.state = kThemeStateUnavailable;
michael@0 1303 else
michael@0 1304 bdi.state = FrameIsInActiveWindow(aFrame) ? inDrawState : kThemeStateActive;
michael@0 1305
michael@0 1306 HIThemeDrawButton(&inBoxRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
michael@0 1307
michael@0 1308 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1309 }
michael@0 1310
michael@0 1311 void
michael@0 1312 nsNativeThemeCocoa::DrawSpinButton(CGContextRef cgContext,
michael@0 1313 ThemeButtonKind inKind,
michael@0 1314 const HIRect& inBoxRect,
michael@0 1315 ThemeDrawState inDrawState,
michael@0 1316 ThemeButtonAdornment inAdornment,
michael@0 1317 EventStates inState,
michael@0 1318 nsIFrame* aFrame,
michael@0 1319 uint8_t aWidgetType)
michael@0 1320 {
michael@0 1321 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1322
michael@0 1323 MOZ_ASSERT(aWidgetType == NS_THEME_SPINNER_UP_BUTTON ||
michael@0 1324 aWidgetType == NS_THEME_SPINNER_DOWN_BUTTON);
michael@0 1325
michael@0 1326 HIThemeButtonDrawInfo bdi;
michael@0 1327 bdi.version = 0;
michael@0 1328 bdi.kind = inKind;
michael@0 1329 bdi.value = kThemeButtonOff;
michael@0 1330 bdi.adornment = inAdornment;
michael@0 1331
michael@0 1332 if (IsDisabled(aFrame, inState))
michael@0 1333 bdi.state = kThemeStateUnavailable;
michael@0 1334 else
michael@0 1335 bdi.state = FrameIsInActiveWindow(aFrame) ? inDrawState : kThemeStateActive;
michael@0 1336
michael@0 1337 // Cocoa only allows kThemeIncDecButton to paint the up and down spin buttons
michael@0 1338 // together as a single unit (presumably because when one button is active,
michael@0 1339 // the appearance of both changes (in different ways)). Here we have to paint
michael@0 1340 // both buttons, using clip to hide the one we don't want to paint.
michael@0 1341 HIRect drawRect = inBoxRect;
michael@0 1342 drawRect.size.height *= 2;
michael@0 1343 if (aWidgetType == NS_THEME_SPINNER_DOWN_BUTTON) {
michael@0 1344 drawRect.origin.y -= inBoxRect.size.height;
michael@0 1345 }
michael@0 1346
michael@0 1347 // Shift the drawing a little to the left, since cocoa paints with more
michael@0 1348 // blank space around the visual buttons than we'd like:
michael@0 1349 drawRect.origin.x -= 1;
michael@0 1350
michael@0 1351 CGContextSaveGState(cgContext);
michael@0 1352 CGContextClipToRect(cgContext, inBoxRect);
michael@0 1353
michael@0 1354 HIThemeDrawButton(&drawRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
michael@0 1355
michael@0 1356 CGContextRestoreGState(cgContext);
michael@0 1357
michael@0 1358 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1359 }
michael@0 1360
michael@0 1361 void
michael@0 1362 nsNativeThemeCocoa::DrawFrame(CGContextRef cgContext, HIThemeFrameKind inKind,
michael@0 1363 const HIRect& inBoxRect, bool inDisabled,
michael@0 1364 EventStates inState)
michael@0 1365 {
michael@0 1366 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1367
michael@0 1368 HIThemeFrameDrawInfo fdi;
michael@0 1369 fdi.version = 0;
michael@0 1370 fdi.kind = inKind;
michael@0 1371
michael@0 1372 // We don't ever set an inactive state for this because it doesn't
michael@0 1373 // look right (see other apps).
michael@0 1374 fdi.state = inDisabled ? kThemeStateUnavailable : kThemeStateActive;
michael@0 1375
michael@0 1376 // for some reason focus rings on listboxes draw incorrectly
michael@0 1377 if (inKind == kHIThemeFrameListBox)
michael@0 1378 fdi.isFocused = 0;
michael@0 1379 else
michael@0 1380 fdi.isFocused = inState.HasState(NS_EVENT_STATE_FOCUS);
michael@0 1381
michael@0 1382 // HIThemeDrawFrame takes the rect for the content area of the frame, not
michael@0 1383 // the bounding rect for the frame. Here we reduce the size of the rect we
michael@0 1384 // will pass to make it the size of the content.
michael@0 1385 HIRect drawRect = inBoxRect;
michael@0 1386 if (inKind == kHIThemeFrameTextFieldSquare) {
michael@0 1387 SInt32 frameOutset = 0;
michael@0 1388 ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
michael@0 1389 drawRect.origin.x += frameOutset;
michael@0 1390 drawRect.origin.y += frameOutset;
michael@0 1391 drawRect.size.width -= frameOutset * 2;
michael@0 1392 drawRect.size.height -= frameOutset * 2;
michael@0 1393 }
michael@0 1394 else if (inKind == kHIThemeFrameListBox) {
michael@0 1395 SInt32 frameOutset = 0;
michael@0 1396 ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
michael@0 1397 drawRect.origin.x += frameOutset;
michael@0 1398 drawRect.origin.y += frameOutset;
michael@0 1399 drawRect.size.width -= frameOutset * 2;
michael@0 1400 drawRect.size.height -= frameOutset * 2;
michael@0 1401 }
michael@0 1402
michael@0 1403 #if DRAW_IN_FRAME_DEBUG
michael@0 1404 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
michael@0 1405 CGContextFillRect(cgContext, inBoxRect);
michael@0 1406 #endif
michael@0 1407
michael@0 1408 HIThemeDrawFrame(&drawRect, &fdi, cgContext, HITHEME_ORIENTATION);
michael@0 1409
michael@0 1410 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1411 }
michael@0 1412
michael@0 1413 static const CellRenderSettings progressSettings[2][2] = {
michael@0 1414 // Vertical progress bar.
michael@0 1415 {
michael@0 1416 // Determined settings.
michael@0 1417 {
michael@0 1418 {
michael@0 1419 NSZeroSize, // mini
michael@0 1420 NSMakeSize(10, 0), // small
michael@0 1421 NSMakeSize(16, 0) // regular
michael@0 1422 },
michael@0 1423 {
michael@0 1424 NSZeroSize, NSZeroSize, NSZeroSize
michael@0 1425 },
michael@0 1426 {
michael@0 1427 { // Leopard
michael@0 1428 {0, 0, 0, 0}, // mini
michael@0 1429 {1, 1, 1, 1}, // small
michael@0 1430 {1, 1, 1, 1} // regular
michael@0 1431 }
michael@0 1432 }
michael@0 1433 },
michael@0 1434 // There is no horizontal margin in regular undetermined size.
michael@0 1435 {
michael@0 1436 {
michael@0 1437 NSZeroSize, // mini
michael@0 1438 NSMakeSize(10, 0), // small
michael@0 1439 NSMakeSize(16, 0) // regular
michael@0 1440 },
michael@0 1441 {
michael@0 1442 NSZeroSize, NSZeroSize, NSZeroSize
michael@0 1443 },
michael@0 1444 {
michael@0 1445 { // Leopard
michael@0 1446 {0, 0, 0, 0}, // mini
michael@0 1447 {1, 1, 1, 1}, // small
michael@0 1448 {1, 0, 1, 0} // regular
michael@0 1449 }
michael@0 1450 }
michael@0 1451 }
michael@0 1452 },
michael@0 1453 // Horizontal progress bar.
michael@0 1454 {
michael@0 1455 // Determined settings.
michael@0 1456 {
michael@0 1457 {
michael@0 1458 NSZeroSize, // mini
michael@0 1459 NSMakeSize(0, 10), // small
michael@0 1460 NSMakeSize(0, 16) // regular
michael@0 1461 },
michael@0 1462 {
michael@0 1463 NSZeroSize, NSZeroSize, NSZeroSize
michael@0 1464 },
michael@0 1465 {
michael@0 1466 { // Leopard
michael@0 1467 {0, 0, 0, 0}, // mini
michael@0 1468 {1, 1, 1, 1}, // small
michael@0 1469 {1, 1, 1, 1} // regular
michael@0 1470 }
michael@0 1471 }
michael@0 1472 },
michael@0 1473 // There is no horizontal margin in regular undetermined size.
michael@0 1474 {
michael@0 1475 {
michael@0 1476 NSZeroSize, // mini
michael@0 1477 NSMakeSize(0, 10), // small
michael@0 1478 NSMakeSize(0, 16) // regular
michael@0 1479 },
michael@0 1480 {
michael@0 1481 NSZeroSize, NSZeroSize, NSZeroSize
michael@0 1482 },
michael@0 1483 {
michael@0 1484 { // Leopard
michael@0 1485 {0, 0, 0, 0}, // mini
michael@0 1486 {1, 1, 1, 1}, // small
michael@0 1487 {0, 1, 0, 1} // regular
michael@0 1488 }
michael@0 1489 }
michael@0 1490 }
michael@0 1491 }
michael@0 1492 };
michael@0 1493
michael@0 1494 void
michael@0 1495 nsNativeThemeCocoa::DrawProgress(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 1496 bool inIsIndeterminate, bool inIsHorizontal,
michael@0 1497 double inValue, double inMaxValue,
michael@0 1498 nsIFrame* aFrame)
michael@0 1499 {
michael@0 1500 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1501
michael@0 1502 NSProgressBarCell* cell = mProgressBarCell;
michael@0 1503
michael@0 1504 [cell setValue:inValue];
michael@0 1505 [cell setMax:inMaxValue];
michael@0 1506 [cell setIndeterminate:inIsIndeterminate];
michael@0 1507 [cell setHorizontal:inIsHorizontal];
michael@0 1508 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint]
michael@0 1509 : NSClearControlTint)];
michael@0 1510
michael@0 1511 DrawCellWithSnapping(cell, cgContext, inBoxRect,
michael@0 1512 progressSettings[inIsHorizontal][inIsIndeterminate],
michael@0 1513 VerticalAlignFactor(aFrame), mCellDrawView,
michael@0 1514 IsFrameRTL(aFrame));
michael@0 1515
michael@0 1516 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1517 }
michael@0 1518
michael@0 1519 static const CellRenderSettings meterSetting = {
michael@0 1520 {
michael@0 1521 NSMakeSize(0, 16), // mini
michael@0 1522 NSMakeSize(0, 16), // small
michael@0 1523 NSMakeSize(0, 16) // regular
michael@0 1524 },
michael@0 1525 {
michael@0 1526 NSZeroSize, NSZeroSize, NSZeroSize
michael@0 1527 },
michael@0 1528 {
michael@0 1529 { // Leopard
michael@0 1530 {1, 1, 1, 1}, // mini
michael@0 1531 {1, 1, 1, 1}, // small
michael@0 1532 {1, 1, 1, 1} // regular
michael@0 1533 }
michael@0 1534 }
michael@0 1535 };
michael@0 1536
michael@0 1537 void
michael@0 1538 nsNativeThemeCocoa::DrawMeter(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 1539 nsIFrame* aFrame)
michael@0 1540 {
michael@0 1541 NS_OBJC_BEGIN_TRY_ABORT_BLOCK
michael@0 1542
michael@0 1543 NS_PRECONDITION(aFrame, "aFrame should not be null here!");
michael@0 1544
michael@0 1545 // When using -moz-meterbar on an non meter element, we will not be able to
michael@0 1546 // get all the needed information so we just draw an empty meter.
michael@0 1547 nsIContent* content = aFrame->GetContent();
michael@0 1548 if (!(content && content->IsHTML(nsGkAtoms::meter))) {
michael@0 1549 DrawCellWithSnapping(mMeterBarCell, cgContext, inBoxRect,
michael@0 1550 meterSetting, VerticalAlignFactor(aFrame),
michael@0 1551 mCellDrawView, IsFrameRTL(aFrame));
michael@0 1552 return;
michael@0 1553 }
michael@0 1554
michael@0 1555 HTMLMeterElement* meterElement = static_cast<HTMLMeterElement*>(content);
michael@0 1556 double value = meterElement->Value();
michael@0 1557 double min = meterElement->Min();
michael@0 1558 double max = meterElement->Max();
michael@0 1559
michael@0 1560 NSLevelIndicatorCell* cell = mMeterBarCell;
michael@0 1561
michael@0 1562 [cell setMinValue:min];
michael@0 1563 [cell setMaxValue:max];
michael@0 1564 [cell setDoubleValue:value];
michael@0 1565
michael@0 1566 /**
michael@0 1567 * The way HTML and Cocoa defines the meter/indicator widget are different.
michael@0 1568 * So, we are going to use a trick to get the Cocoa widget showing what we
michael@0 1569 * are expecting: we set the warningValue or criticalValue to the current
michael@0 1570 * value when we want to have the widget to be in the warning or critical
michael@0 1571 * state.
michael@0 1572 */
michael@0 1573 EventStates states = aFrame->GetContent()->AsElement()->State();
michael@0 1574
michael@0 1575 // Reset previously set warning and critical values.
michael@0 1576 [cell setWarningValue:max+1];
michael@0 1577 [cell setCriticalValue:max+1];
michael@0 1578
michael@0 1579 if (states.HasState(NS_EVENT_STATE_SUB_OPTIMUM)) {
michael@0 1580 [cell setWarningValue:value];
michael@0 1581 } else if (states.HasState(NS_EVENT_STATE_SUB_SUB_OPTIMUM)) {
michael@0 1582 [cell setCriticalValue:value];
michael@0 1583 }
michael@0 1584
michael@0 1585 HIRect rect = CGRectStandardize(inBoxRect);
michael@0 1586 BOOL vertical = IsVerticalMeter(aFrame);
michael@0 1587
michael@0 1588 CGContextSaveGState(cgContext);
michael@0 1589
michael@0 1590 if (vertical) {
michael@0 1591 /**
michael@0 1592 * Cocoa doesn't provide a vertical meter bar so to show one, we have to
michael@0 1593 * show a rotated horizontal meter bar.
michael@0 1594 * Given that we want to show a vertical meter bar, we assume that the rect
michael@0 1595 * has vertical dimensions but we can't correctly draw a meter widget inside
michael@0 1596 * such a rectangle so we need to inverse width and height (and re-position)
michael@0 1597 * to get a rectangle with horizontal dimensions.
michael@0 1598 * Finally, we want to show a vertical meter so we want to rotate the result
michael@0 1599 * so it is vertical. We do that by changing the context.
michael@0 1600 */
michael@0 1601 CGFloat tmp = rect.size.width;
michael@0 1602 rect.size.width = rect.size.height;
michael@0 1603 rect.size.height = tmp;
michael@0 1604 rect.origin.x += rect.size.height / 2.f - rect.size.width / 2.f;
michael@0 1605 rect.origin.y += rect.size.width / 2.f - rect.size.height / 2.f;
michael@0 1606
michael@0 1607 CGContextTranslateCTM(cgContext, CGRectGetMidX(rect), CGRectGetMidY(rect));
michael@0 1608 CGContextRotateCTM(cgContext, -M_PI / 2.f);
michael@0 1609 CGContextTranslateCTM(cgContext, -CGRectGetMidX(rect), -CGRectGetMidY(rect));
michael@0 1610 }
michael@0 1611
michael@0 1612 DrawCellWithSnapping(cell, cgContext, rect,
michael@0 1613 meterSetting, VerticalAlignFactor(aFrame),
michael@0 1614 mCellDrawView, !vertical && IsFrameRTL(aFrame));
michael@0 1615
michael@0 1616 CGContextRestoreGState(cgContext);
michael@0 1617
michael@0 1618 NS_OBJC_END_TRY_ABORT_BLOCK
michael@0 1619 }
michael@0 1620
michael@0 1621 void
michael@0 1622 nsNativeThemeCocoa::DrawTabPanel(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 1623 nsIFrame* aFrame)
michael@0 1624 {
michael@0 1625 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1626
michael@0 1627 HIThemeTabPaneDrawInfo tpdi;
michael@0 1628
michael@0 1629 tpdi.version = 1;
michael@0 1630 tpdi.state = FrameIsInActiveWindow(aFrame) ? kThemeStateActive : kThemeStateInactive;
michael@0 1631 tpdi.direction = kThemeTabNorth;
michael@0 1632 tpdi.size = kHIThemeTabSizeNormal;
michael@0 1633 tpdi.kind = kHIThemeTabKindNormal;
michael@0 1634
michael@0 1635 HIThemeDrawTabPane(&inBoxRect, &tpdi, cgContext, HITHEME_ORIENTATION);
michael@0 1636
michael@0 1637 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1638 }
michael@0 1639
michael@0 1640 void
michael@0 1641 nsNativeThemeCocoa::DrawScale(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 1642 EventStates inState, bool inIsVertical,
michael@0 1643 bool inIsReverse, int32_t inCurrentValue,
michael@0 1644 int32_t inMinValue, int32_t inMaxValue,
michael@0 1645 nsIFrame* aFrame)
michael@0 1646 {
michael@0 1647 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1648
michael@0 1649 HIThemeTrackDrawInfo tdi;
michael@0 1650
michael@0 1651 tdi.version = 0;
michael@0 1652 tdi.kind = kThemeMediumSlider;
michael@0 1653 tdi.bounds = inBoxRect;
michael@0 1654 tdi.min = inMinValue;
michael@0 1655 tdi.max = inMaxValue;
michael@0 1656 tdi.value = inCurrentValue;
michael@0 1657 tdi.attributes = kThemeTrackShowThumb;
michael@0 1658 if (!inIsVertical)
michael@0 1659 tdi.attributes |= kThemeTrackHorizontal;
michael@0 1660 if (inIsReverse)
michael@0 1661 tdi.attributes |= kThemeTrackRightToLeft;
michael@0 1662 if (inState.HasState(NS_EVENT_STATE_FOCUS))
michael@0 1663 tdi.attributes |= kThemeTrackHasFocus;
michael@0 1664 if (IsDisabled(aFrame, inState))
michael@0 1665 tdi.enableState = kThemeTrackDisabled;
michael@0 1666 else
michael@0 1667 tdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
michael@0 1668 tdi.trackInfo.slider.thumbDir = kThemeThumbPlain;
michael@0 1669 tdi.trackInfo.slider.pressState = 0;
michael@0 1670
michael@0 1671 HIThemeDrawTrack(&tdi, NULL, cgContext, HITHEME_ORIENTATION);
michael@0 1672
michael@0 1673 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1674 }
michael@0 1675
michael@0 1676 nsIFrame*
michael@0 1677 nsNativeThemeCocoa::SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter)
michael@0 1678 {
michael@0 1679 // Usually a separator is drawn by the segment to the right of the
michael@0 1680 // separator, but pressed and selected segments have higher priority.
michael@0 1681 if (!aBefore || !aAfter)
michael@0 1682 return nullptr;
michael@0 1683 if (IsSelectedButton(aAfter))
michael@0 1684 return aAfter;
michael@0 1685 if (IsSelectedButton(aBefore) || IsPressedButton(aBefore))
michael@0 1686 return aBefore;
michael@0 1687 return aAfter;
michael@0 1688 }
michael@0 1689
michael@0 1690 CGRect
michael@0 1691 nsNativeThemeCocoa::SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
michael@0 1692 nsIFrame* aCurrent, nsIFrame* aRight)
michael@0 1693 {
michael@0 1694 // A separator between two segments should always be located in the leftmost
michael@0 1695 // pixel column of the segment to the right of the separator, regardless of
michael@0 1696 // who ends up drawing it.
michael@0 1697 // CoreUI draws the separators inside the drawing rect.
michael@0 1698 if (aLeft && SeparatorResponsibility(aLeft, aCurrent) == aLeft) {
michael@0 1699 // The left button draws the separator, so we need to make room for it.
michael@0 1700 aRect.origin.x += 1;
michael@0 1701 aRect.size.width -= 1;
michael@0 1702 }
michael@0 1703 if (SeparatorResponsibility(aCurrent, aRight) == aCurrent) {
michael@0 1704 // We draw the right separator, so we need to extend the draw rect into the
michael@0 1705 // segment to our right.
michael@0 1706 aRect.size.width += 1;
michael@0 1707 }
michael@0 1708 return aRect;
michael@0 1709 }
michael@0 1710
michael@0 1711 static NSString* ToolbarButtonPosition(BOOL aIsFirst, BOOL aIsLast)
michael@0 1712 {
michael@0 1713 if (aIsFirst) {
michael@0 1714 if (aIsLast)
michael@0 1715 return @"kCUISegmentPositionOnly";
michael@0 1716 return @"kCUISegmentPositionFirst";
michael@0 1717 }
michael@0 1718 if (aIsLast)
michael@0 1719 return @"kCUISegmentPositionLast";
michael@0 1720 return @"kCUISegmentPositionMiddle";
michael@0 1721 }
michael@0 1722
michael@0 1723 struct SegmentedControlRenderSettings {
michael@0 1724 const CGFloat* heights;
michael@0 1725 const NSString* widgetName;
michael@0 1726 const BOOL ignoresPressedWhenSelected;
michael@0 1727 const BOOL isToolbarControl;
michael@0 1728 };
michael@0 1729
michael@0 1730 static const CGFloat tabHeights[3] = { 17, 20, 23 };
michael@0 1731
michael@0 1732 static const SegmentedControlRenderSettings tabRenderSettings = {
michael@0 1733 tabHeights, @"tab", YES, NO
michael@0 1734 };
michael@0 1735
michael@0 1736 static const CGFloat toolbarButtonHeights[3] = { 15, 18, 22 };
michael@0 1737
michael@0 1738 static const SegmentedControlRenderSettings toolbarButtonRenderSettings = {
michael@0 1739 toolbarButtonHeights, @"kCUIWidgetButtonSegmentedSCurve", NO, YES
michael@0 1740 };
michael@0 1741
michael@0 1742 void
michael@0 1743 nsNativeThemeCocoa::DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 1744 EventStates inState, nsIFrame* aFrame,
michael@0 1745 const SegmentedControlRenderSettings& aSettings)
michael@0 1746 {
michael@0 1747 BOOL isActive = IsActive(aFrame, aSettings.isToolbarControl);
michael@0 1748 BOOL isFocused = inState.HasState(NS_EVENT_STATE_FOCUS);
michael@0 1749 BOOL isSelected = IsSelectedButton(aFrame);
michael@0 1750 BOOL isPressed = IsPressedButton(aFrame);
michael@0 1751 if (isSelected && aSettings.ignoresPressedWhenSelected) {
michael@0 1752 isPressed = NO;
michael@0 1753 }
michael@0 1754
michael@0 1755 BOOL isRTL = IsFrameRTL(aFrame);
michael@0 1756 nsIFrame* left = GetAdjacentSiblingFrameWithSameAppearance(aFrame, isRTL);
michael@0 1757 nsIFrame* right = GetAdjacentSiblingFrameWithSameAppearance(aFrame, !isRTL);
michael@0 1758 CGRect drawRect = SeparatorAdjustedRect(inBoxRect, left, aFrame, right);
michael@0 1759 if (drawRect.size.width * drawRect.size.height > CUIDRAW_MAX_AREA) {
michael@0 1760 return;
michael@0 1761 }
michael@0 1762 BOOL drawLeftSeparator = SeparatorResponsibility(left, aFrame) == aFrame;
michael@0 1763 BOOL drawRightSeparator = SeparatorResponsibility(aFrame, right) == aFrame;
michael@0 1764 NSControlSize controlSize = FindControlSize(drawRect.size.height, aSettings.heights, 4.0f);
michael@0 1765
michael@0 1766 CUIDraw([NSWindow coreUIRenderer], drawRect, cgContext,
michael@0 1767 (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
michael@0 1768 aSettings.widgetName, @"widget",
michael@0 1769 ToolbarButtonPosition(!left, !right), @"kCUIPositionKey",
michael@0 1770 [NSNumber numberWithBool:drawLeftSeparator], @"kCUISegmentLeadingSeparatorKey",
michael@0 1771 [NSNumber numberWithBool:drawRightSeparator], @"kCUISegmentTrailingSeparatorKey",
michael@0 1772 [NSNumber numberWithBool:isSelected], @"value",
michael@0 1773 (isPressed ? @"pressed" : (isActive ? @"normal" : @"inactive")), @"state",
michael@0 1774 [NSNumber numberWithBool:isFocused], @"focus",
michael@0 1775 CUIControlSizeForCocoaSize(controlSize), @"size",
michael@0 1776 [NSNumber numberWithBool:YES], @"is.flipped",
michael@0 1777 @"up", @"direction",
michael@0 1778 nil],
michael@0 1779 nil);
michael@0 1780 }
michael@0 1781
michael@0 1782 static inline UInt8
michael@0 1783 ConvertToPressState(EventStates aButtonState, UInt8 aPressState)
michael@0 1784 {
michael@0 1785 // If the button is pressed, return the press state passed in. Otherwise, return 0.
michael@0 1786 return aButtonState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER) ? aPressState : 0;
michael@0 1787 }
michael@0 1788
michael@0 1789 void
michael@0 1790 nsNativeThemeCocoa::GetScrollbarPressStates(nsIFrame* aFrame,
michael@0 1791 EventStates aButtonStates[])
michael@0 1792 {
michael@0 1793 static nsIContent::AttrValuesArray attributeValues[] = {
michael@0 1794 &nsGkAtoms::scrollbarUpTop,
michael@0 1795 &nsGkAtoms::scrollbarDownTop,
michael@0 1796 &nsGkAtoms::scrollbarUpBottom,
michael@0 1797 &nsGkAtoms::scrollbarDownBottom,
michael@0 1798 nullptr
michael@0 1799 };
michael@0 1800
michael@0 1801 // Get the state of any scrollbar buttons in our child frames
michael@0 1802 for (nsIFrame *childFrame = aFrame->GetFirstPrincipalChild();
michael@0 1803 childFrame;
michael@0 1804 childFrame = childFrame->GetNextSibling()) {
michael@0 1805
michael@0 1806 nsIContent *childContent = childFrame->GetContent();
michael@0 1807 if (!childContent) continue;
michael@0 1808 int32_t attrIndex = childContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::sbattr,
michael@0 1809 attributeValues, eCaseMatters);
michael@0 1810 if (attrIndex < 0) continue;
michael@0 1811
michael@0 1812 aButtonStates[attrIndex] = GetContentState(childFrame, NS_THEME_BUTTON);
michael@0 1813 }
michael@0 1814 }
michael@0 1815
michael@0 1816 // Both of the following sets of numbers were derived by loading the testcase in
michael@0 1817 // bmo bug 380185 in Safari and observing its behavior for various heights of scrollbar.
michael@0 1818 // These magic numbers are the minimum sizes we can draw a scrollbar and still
michael@0 1819 // have room for everything to display, including the thumb
michael@0 1820 #define MIN_SCROLLBAR_SIZE_WITH_THUMB 61
michael@0 1821 #define MIN_SMALL_SCROLLBAR_SIZE_WITH_THUMB 49
michael@0 1822 // And these are the minimum sizes if we don't draw the thumb
michael@0 1823 #define MIN_SCROLLBAR_SIZE 56
michael@0 1824 #define MIN_SMALL_SCROLLBAR_SIZE 46
michael@0 1825
michael@0 1826 void
michael@0 1827 nsNativeThemeCocoa::GetScrollbarDrawInfo(HIThemeTrackDrawInfo& aTdi, nsIFrame *aFrame,
michael@0 1828 const CGSize& aSize, bool aShouldGetButtonStates)
michael@0 1829 {
michael@0 1830 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1831
michael@0 1832 int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
michael@0 1833 int32_t minpos = CheckIntAttr(aFrame, nsGkAtoms::minpos, 0);
michael@0 1834 int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
michael@0 1835 int32_t thumbSize = CheckIntAttr(aFrame, nsGkAtoms::pageincrement, 10);
michael@0 1836
michael@0 1837 bool isHorizontal = aFrame->GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
michael@0 1838 nsGkAtoms::horizontal, eCaseMatters);
michael@0 1839 bool isSmall = aFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL;
michael@0 1840
michael@0 1841 aTdi.version = 0;
michael@0 1842 aTdi.kind = isSmall ? kThemeSmallScrollBar : kThemeMediumScrollBar;
michael@0 1843 aTdi.bounds.origin = CGPointZero;
michael@0 1844 aTdi.bounds.size = aSize;
michael@0 1845 aTdi.min = minpos;
michael@0 1846 aTdi.max = maxpos;
michael@0 1847 aTdi.value = curpos;
michael@0 1848 aTdi.attributes = 0;
michael@0 1849 aTdi.enableState = kThemeTrackActive;
michael@0 1850 if (isHorizontal)
michael@0 1851 aTdi.attributes |= kThemeTrackHorizontal;
michael@0 1852
michael@0 1853 aTdi.trackInfo.scrollbar.viewsize = (SInt32)thumbSize;
michael@0 1854
michael@0 1855 // This should be done early on so things like "kThemeTrackNothingToScroll" can
michael@0 1856 // override the active enable state.
michael@0 1857 aTdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
michael@0 1858
michael@0 1859 /* Only display features if we have enough room for them.
michael@0 1860 * Gecko still maintains the scrollbar info; this is just a visual issue (bug 380185).
michael@0 1861 */
michael@0 1862 int32_t longSideLength = (int32_t)(isHorizontal ? (aSize.width) : (aSize.height));
michael@0 1863 if (longSideLength >= (isSmall ? MIN_SMALL_SCROLLBAR_SIZE_WITH_THUMB : MIN_SCROLLBAR_SIZE_WITH_THUMB)) {
michael@0 1864 aTdi.attributes |= kThemeTrackShowThumb;
michael@0 1865 }
michael@0 1866 else if (longSideLength < (isSmall ? MIN_SMALL_SCROLLBAR_SIZE : MIN_SCROLLBAR_SIZE)) {
michael@0 1867 aTdi.enableState = kThemeTrackNothingToScroll;
michael@0 1868 return;
michael@0 1869 }
michael@0 1870
michael@0 1871 aTdi.trackInfo.scrollbar.pressState = 0;
michael@0 1872
michael@0 1873 // Only go get these scrollbar button states if we need it. For example,
michael@0 1874 // there's no reason to look up scrollbar button states when we're only
michael@0 1875 // creating a TrackDrawInfo to determine the size of the thumb. There's
michael@0 1876 // also no reason to do this on Lion or later, whose scrollbars have no
michael@0 1877 // arrow buttons.
michael@0 1878 if (aShouldGetButtonStates && !nsCocoaFeatures::OnLionOrLater()) {
michael@0 1879 EventStates buttonStates[4];
michael@0 1880 GetScrollbarPressStates(aFrame, buttonStates);
michael@0 1881 NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
michael@0 1882 // It seems that unless all four buttons are showing, kThemeTopOutsideArrowPressed is the correct constant for
michael@0 1883 // the up scrollbar button.
michael@0 1884 if ([buttonPlacement isEqualToString:@"DoubleBoth"]) {
michael@0 1885 aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
michael@0 1886 ConvertToPressState(buttonStates[1], kThemeTopInsideArrowPressed) |
michael@0 1887 ConvertToPressState(buttonStates[2], kThemeBottomInsideArrowPressed) |
michael@0 1888 ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
michael@0 1889 } else {
michael@0 1890 aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
michael@0 1891 ConvertToPressState(buttonStates[1], kThemeBottomOutsideArrowPressed) |
michael@0 1892 ConvertToPressState(buttonStates[2], kThemeTopOutsideArrowPressed) |
michael@0 1893 ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
michael@0 1894 }
michael@0 1895 }
michael@0 1896
michael@0 1897 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1898 }
michael@0 1899
michael@0 1900 static void
michael@0 1901 RenderScrollbar(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
michael@0 1902 {
michael@0 1903 HIThemeTrackDrawInfo* tdi = (HIThemeTrackDrawInfo*)aData;
michael@0 1904 HIThemeDrawTrack(tdi, NULL, cgContext, HITHEME_ORIENTATION);
michael@0 1905 }
michael@0 1906
michael@0 1907 void
michael@0 1908 nsNativeThemeCocoa::DrawScrollbar(CGContextRef aCGContext, const HIRect& aBoxRect, nsIFrame *aFrame)
michael@0 1909 {
michael@0 1910 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1911
michael@0 1912 HIThemeTrackDrawInfo tdi;
michael@0 1913 GetScrollbarDrawInfo(tdi, aFrame, aBoxRect.size, true); // True means we want the press states
michael@0 1914 RenderTransformedHIThemeControl(aCGContext, aBoxRect, RenderScrollbar, &tdi);
michael@0 1915
michael@0 1916 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1917 }
michael@0 1918
michael@0 1919 nsIFrame*
michael@0 1920 nsNativeThemeCocoa::GetParentScrollbarFrame(nsIFrame *aFrame)
michael@0 1921 {
michael@0 1922 // Walk our parents to find a scrollbar frame
michael@0 1923 nsIFrame *scrollbarFrame = aFrame;
michael@0 1924 do {
michael@0 1925 if (scrollbarFrame->GetType() == nsGkAtoms::scrollbarFrame) break;
michael@0 1926 } while ((scrollbarFrame = scrollbarFrame->GetParent()));
michael@0 1927
michael@0 1928 // We return null if we can't find a parent scrollbar frame
michael@0 1929 return scrollbarFrame;
michael@0 1930 }
michael@0 1931
michael@0 1932 static bool
michael@0 1933 ToolbarCanBeUnified(CGContextRef cgContext, const HIRect& inBoxRect, NSWindow* aWindow)
michael@0 1934 {
michael@0 1935 if (![aWindow isKindOfClass:[ToolbarWindow class]])
michael@0 1936 return false;
michael@0 1937
michael@0 1938 ToolbarWindow* win = (ToolbarWindow*)aWindow;
michael@0 1939 float unifiedToolbarHeight = [win unifiedToolbarHeight];
michael@0 1940 return inBoxRect.origin.x == 0 &&
michael@0 1941 inBoxRect.size.width >= [win frame].size.width &&
michael@0 1942 CGRectGetMaxY(inBoxRect) <= unifiedToolbarHeight;
michael@0 1943 }
michael@0 1944
michael@0 1945 // By default, kCUIWidgetWindowFrame drawing draws rounded corners in the
michael@0 1946 // upper corners. Depending on the context type, it fills the background in
michael@0 1947 // the corners with black or leaves it transparent. Unfortunately, this corner
michael@0 1948 // rounding interacts poorly with the window corner masking we apply during
michael@0 1949 // titlebar drawing and results in small remnants of the corner background
michael@0 1950 // appearing at the rounded edge.
michael@0 1951 // So we draw square corners.
michael@0 1952 static void
michael@0 1953 DrawNativeTitlebarToolbarWithSquareCorners(CGContextRef aContext, const CGRect& aRect,
michael@0 1954 CGFloat aUnifiedHeight, BOOL aIsMain)
michael@0 1955 {
michael@0 1956 // We extend the draw rect horizontally and clip away the rounded corners.
michael@0 1957 const CGFloat extendHorizontal = 10;
michael@0 1958 CGRect drawRect = CGRectInset(aRect, -extendHorizontal, 0);
michael@0 1959 if (drawRect.size.width * drawRect.size.height <= CUIDRAW_MAX_AREA) {
michael@0 1960 CGContextSaveGState(aContext);
michael@0 1961 CGContextClipToRect(aContext, aRect);
michael@0 1962
michael@0 1963 CUIDraw([NSWindow coreUIRenderer], drawRect, aContext,
michael@0 1964 (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
michael@0 1965 @"kCUIWidgetWindowFrame", @"widget",
michael@0 1966 @"regularwin", @"windowtype",
michael@0 1967 (aIsMain ? @"normal" : @"inactive"), @"state",
michael@0 1968 [NSNumber numberWithDouble:aUnifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
michael@0 1969 [NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawTitleSeparatorKey",
michael@0 1970 [NSNumber numberWithBool:YES], @"is.flipped",
michael@0 1971 nil],
michael@0 1972 nil);
michael@0 1973
michael@0 1974 CGContextRestoreGState(aContext);
michael@0 1975 }
michael@0 1976 }
michael@0 1977
michael@0 1978 void
michael@0 1979 nsNativeThemeCocoa::DrawUnifiedToolbar(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 1980 NSWindow* aWindow)
michael@0 1981 {
michael@0 1982 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 1983
michael@0 1984 CGContextSaveGState(cgContext);
michael@0 1985 CGContextClipToRect(cgContext, inBoxRect);
michael@0 1986
michael@0 1987 CGFloat unifiedHeight = std::max([(ToolbarWindow*)aWindow unifiedToolbarHeight],
michael@0 1988 inBoxRect.size.height);
michael@0 1989 BOOL isMain = [aWindow isMainWindow];
michael@0 1990 CGFloat titlebarHeight = unifiedHeight - inBoxRect.size.height;
michael@0 1991 CGRect drawRect = CGRectMake(inBoxRect.origin.x, inBoxRect.origin.y - titlebarHeight,
michael@0 1992 inBoxRect.size.width, inBoxRect.size.height + titlebarHeight);
michael@0 1993 DrawNativeTitlebarToolbarWithSquareCorners(cgContext, drawRect, unifiedHeight, isMain);
michael@0 1994
michael@0 1995 CGContextRestoreGState(cgContext);
michael@0 1996
michael@0 1997 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 1998 }
michael@0 1999
michael@0 2000 void
michael@0 2001 nsNativeThemeCocoa::DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect,
michael@0 2002 nsIFrame *aFrame)
michael@0 2003 {
michael@0 2004 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 2005
michael@0 2006 if (inBoxRect.size.height < 2.0f)
michael@0 2007 return;
michael@0 2008
michael@0 2009 CGContextSaveGState(cgContext);
michael@0 2010 CGContextClipToRect(cgContext, inBoxRect);
michael@0 2011
michael@0 2012 // kCUIWidgetWindowFrame draws a complete window frame with both title bar
michael@0 2013 // and bottom bar. We only want the bottom bar, so we extend the draw rect
michael@0 2014 // upwards to make space for the title bar, and then we clip it away.
michael@0 2015 CGRect drawRect = inBoxRect;
michael@0 2016 const int extendUpwards = 40;
michael@0 2017 drawRect.origin.y -= extendUpwards;
michael@0 2018 drawRect.size.height += extendUpwards;
michael@0 2019 if (drawRect.size.width * drawRect.size.height <= CUIDRAW_MAX_AREA) {
michael@0 2020 CUIDraw([NSWindow coreUIRenderer], drawRect, cgContext,
michael@0 2021 (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
michael@0 2022 @"kCUIWidgetWindowFrame", @"widget",
michael@0 2023 @"regularwin", @"windowtype",
michael@0 2024 (IsActive(aFrame, YES) ? @"normal" : @"inactive"), @"state",
michael@0 2025 [NSNumber numberWithInt:inBoxRect.size.height], @"kCUIWindowFrameBottomBarHeightKey",
michael@0 2026 [NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawBottomBarSeparatorKey",
michael@0 2027 [NSNumber numberWithBool:YES], @"is.flipped",
michael@0 2028 nil],
michael@0 2029 nil);
michael@0 2030 }
michael@0 2031
michael@0 2032 CGContextRestoreGState(cgContext);
michael@0 2033
michael@0 2034 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 2035 }
michael@0 2036
michael@0 2037 void
michael@0 2038 nsNativeThemeCocoa::DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
michael@0 2039 CGFloat aUnifiedHeight, BOOL aIsMain)
michael@0 2040 {
michael@0 2041 CGFloat unifiedHeight = std::max(aUnifiedHeight, aTitlebarRect.size.height);
michael@0 2042 DrawNativeTitlebarToolbarWithSquareCorners(aContext, aTitlebarRect, unifiedHeight, aIsMain);
michael@0 2043 }
michael@0 2044
michael@0 2045 static void
michael@0 2046 RenderResizer(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
michael@0 2047 {
michael@0 2048 HIThemeGrowBoxDrawInfo* drawInfo = (HIThemeGrowBoxDrawInfo*)aData;
michael@0 2049 HIThemeDrawGrowBox(&CGPointZero, drawInfo, cgContext, kHIThemeOrientationNormal);
michael@0 2050 }
michael@0 2051
michael@0 2052 void
michael@0 2053 nsNativeThemeCocoa::DrawResizer(CGContextRef cgContext, const HIRect& aRect,
michael@0 2054 nsIFrame *aFrame)
michael@0 2055 {
michael@0 2056 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 2057
michael@0 2058 HIThemeGrowBoxDrawInfo drawInfo;
michael@0 2059 drawInfo.version = 0;
michael@0 2060 drawInfo.state = kThemeStateActive;
michael@0 2061 drawInfo.kind = kHIThemeGrowBoxKindNormal;
michael@0 2062 drawInfo.direction = kThemeGrowRight | kThemeGrowDown;
michael@0 2063 drawInfo.size = kHIThemeGrowBoxSizeNormal;
michael@0 2064
michael@0 2065 RenderTransformedHIThemeControl(cgContext, aRect, RenderResizer, &drawInfo,
michael@0 2066 IsFrameRTL(aFrame));
michael@0 2067
michael@0 2068 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 2069 }
michael@0 2070
michael@0 2071 static bool
michael@0 2072 IsHiDPIContext(nsDeviceContext* aContext)
michael@0 2073 {
michael@0 2074 return nsPresContext::AppUnitsPerCSSPixel() >=
michael@0 2075 2 * aContext->UnscaledAppUnitsPerDevPixel();
michael@0 2076 }
michael@0 2077
michael@0 2078 NS_IMETHODIMP
michael@0 2079 nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
michael@0 2080 nsIFrame* aFrame,
michael@0 2081 uint8_t aWidgetType,
michael@0 2082 const nsRect& aRect,
michael@0 2083 const nsRect& aDirtyRect)
michael@0 2084 {
michael@0 2085 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 2086
michael@0 2087 // setup to draw into the correct port
michael@0 2088 int32_t p2a = aContext->AppUnitsPerDevPixel();
michael@0 2089
michael@0 2090 gfxRect nativeDirtyRect(aDirtyRect.x, aDirtyRect.y,
michael@0 2091 aDirtyRect.width, aDirtyRect.height);
michael@0 2092 gfxRect nativeWidgetRect(aRect.x, aRect.y, aRect.width, aRect.height);
michael@0 2093 nativeWidgetRect.ScaleInverse(gfxFloat(p2a));
michael@0 2094 nativeDirtyRect.ScaleInverse(gfxFloat(p2a));
michael@0 2095 nativeWidgetRect.Round();
michael@0 2096 if (nativeWidgetRect.IsEmpty())
michael@0 2097 return NS_OK; // Don't attempt to draw invisible widgets.
michael@0 2098
michael@0 2099 gfxContext* thebesCtx = aContext->ThebesContext();
michael@0 2100 if (!thebesCtx)
michael@0 2101 return NS_ERROR_FAILURE;
michael@0 2102
michael@0 2103 gfxContextMatrixAutoSaveRestore save(thebesCtx);
michael@0 2104
michael@0 2105 bool hidpi = IsHiDPIContext(aContext->DeviceContext());
michael@0 2106 if (hidpi) {
michael@0 2107 // Use high-resolution drawing.
michael@0 2108 nativeWidgetRect.ScaleInverse(2.0f);
michael@0 2109 nativeDirtyRect.ScaleInverse(2.0f);
michael@0 2110 thebesCtx->Scale(2.0f, 2.0f);
michael@0 2111 }
michael@0 2112
michael@0 2113 gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect,
michael@0 2114 hidpi ? 2.0f : 1.0f);
michael@0 2115
michael@0 2116 CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
michael@0 2117 if (cgContext == nullptr) {
michael@0 2118 // The Quartz surface handles 0x0 surfaces by internally
michael@0 2119 // making all operations no-ops; there's no cgcontext created for them.
michael@0 2120 // Unfortunately, this means that callers that want to render
michael@0 2121 // directly to the CGContext need to be aware of this quirk.
michael@0 2122 return NS_OK;
michael@0 2123 }
michael@0 2124
michael@0 2125 #if 0
michael@0 2126 if (1 /*aWidgetType == NS_THEME_TEXTFIELD*/) {
michael@0 2127 fprintf(stderr, "Native theme drawing widget %d [%p] dis:%d in rect [%d %d %d %d]\n",
michael@0 2128 aWidgetType, aFrame, IsDisabled(aFrame), aRect.x, aRect.y, aRect.width, aRect.height);
michael@0 2129 fprintf(stderr, "Cairo matrix: [%f %f %f %f %f %f]\n",
michael@0 2130 mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0);
michael@0 2131 fprintf(stderr, "Native theme xform[0]: [%f %f %f %f %f %f]\n",
michael@0 2132 mm0.a, mm0.b, mm0.c, mm0.d, mm0.tx, mm0.ty);
michael@0 2133 CGAffineTransform mm = CGContextGetCTM(cgContext);
michael@0 2134 fprintf(stderr, "Native theme xform[1]: [%f %f %f %f %f %f]\n",
michael@0 2135 mm.a, mm.b, mm.c, mm.d, mm.tx, mm.ty);
michael@0 2136 }
michael@0 2137 #endif
michael@0 2138
michael@0 2139 CGRect macRect = CGRectMake(nativeWidgetRect.X(), nativeWidgetRect.Y(),
michael@0 2140 nativeWidgetRect.Width(), nativeWidgetRect.Height());
michael@0 2141
michael@0 2142 #if 0
michael@0 2143 fprintf(stderr, " --> macRect %f %f %f %f\n",
michael@0 2144 macRect.origin.x, macRect.origin.y, macRect.size.width, macRect.size.height);
michael@0 2145 CGRect bounds = CGContextGetClipBoundingBox(cgContext);
michael@0 2146 fprintf(stderr, " --> clip bounds: %f %f %f %f\n",
michael@0 2147 bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
michael@0 2148
michael@0 2149 //CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 1.0, 0.1);
michael@0 2150 //CGContextFillRect(cgContext, bounds);
michael@0 2151 #endif
michael@0 2152
michael@0 2153 EventStates eventState = GetContentState(aFrame, aWidgetType);
michael@0 2154
michael@0 2155 switch (aWidgetType) {
michael@0 2156 case NS_THEME_DIALOG: {
michael@0 2157 HIThemeSetFill(kThemeBrushDialogBackgroundActive, NULL, cgContext, HITHEME_ORIENTATION);
michael@0 2158 CGContextFillRect(cgContext, macRect);
michael@0 2159 }
michael@0 2160 break;
michael@0 2161
michael@0 2162 case NS_THEME_MENUPOPUP: {
michael@0 2163 HIThemeMenuDrawInfo mdi;
michael@0 2164 memset(&mdi, 0, sizeof(mdi));
michael@0 2165 mdi.version = 0;
michael@0 2166 mdi.menuType = IsDisabled(aFrame, eventState) ?
michael@0 2167 static_cast<ThemeMenuType>(kThemeMenuTypeInactive) :
michael@0 2168 static_cast<ThemeMenuType>(kThemeMenuTypePopUp);
michael@0 2169
michael@0 2170 bool isLeftOfParent = false;
michael@0 2171 if (IsSubmenu(aFrame, &isLeftOfParent) && !isLeftOfParent) {
michael@0 2172 mdi.menuType = kThemeMenuTypeHierarchical;
michael@0 2173 }
michael@0 2174
michael@0 2175 // The rounded corners draw outside the frame.
michael@0 2176 CGRect deflatedRect = CGRectMake(macRect.origin.x, macRect.origin.y + 4,
michael@0 2177 macRect.size.width, macRect.size.height - 8);
michael@0 2178 HIThemeDrawMenuBackground(&deflatedRect, &mdi, cgContext, HITHEME_ORIENTATION);
michael@0 2179 }
michael@0 2180 break;
michael@0 2181
michael@0 2182 case NS_THEME_MENUITEM: {
michael@0 2183 bool isTransparent;
michael@0 2184 if (thebesCtx->IsCairo()) {
michael@0 2185 isTransparent = thebesCtx->OriginalSurface()->GetContentType() == gfxContentType::COLOR_ALPHA;
michael@0 2186 } else {
michael@0 2187 SurfaceFormat format = thebesCtx->GetDrawTarget()->GetFormat();
michael@0 2188 isTransparent = (format == SurfaceFormat::R8G8B8A8) ||
michael@0 2189 (format == SurfaceFormat::B8G8R8A8);
michael@0 2190 }
michael@0 2191 if (isTransparent) {
michael@0 2192 // Clear the background to get correct transparency.
michael@0 2193 CGContextClearRect(cgContext, macRect);
michael@0 2194 }
michael@0 2195
michael@0 2196 // maybe use kThemeMenuItemHierBackground or PopUpBackground instead of just Plain?
michael@0 2197 HIThemeMenuItemDrawInfo drawInfo;
michael@0 2198 memset(&drawInfo, 0, sizeof(drawInfo));
michael@0 2199 drawInfo.version = 0;
michael@0 2200 drawInfo.itemType = kThemeMenuItemPlain;
michael@0 2201 drawInfo.state = (IsDisabled(aFrame, eventState) ?
michael@0 2202 static_cast<ThemeMenuState>(kThemeMenuDisabled) :
michael@0 2203 CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ?
michael@0 2204 static_cast<ThemeMenuState>(kThemeMenuSelected) :
michael@0 2205 static_cast<ThemeMenuState>(kThemeMenuActive));
michael@0 2206
michael@0 2207 // XXX pass in the menu rect instead of always using the item rect
michael@0 2208 HIRect ignored;
michael@0 2209 HIThemeDrawMenuItem(&macRect, &macRect, &drawInfo, cgContext, HITHEME_ORIENTATION, &ignored);
michael@0 2210 }
michael@0 2211 break;
michael@0 2212
michael@0 2213 case NS_THEME_MENUSEPARATOR: {
michael@0 2214 ThemeMenuState menuState;
michael@0 2215 if (IsDisabled(aFrame, eventState)) {
michael@0 2216 menuState = kThemeMenuDisabled;
michael@0 2217 }
michael@0 2218 else {
michael@0 2219 menuState = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ?
michael@0 2220 kThemeMenuSelected : kThemeMenuActive;
michael@0 2221 }
michael@0 2222
michael@0 2223 HIThemeMenuItemDrawInfo midi = { 0, kThemeMenuItemPlain, menuState };
michael@0 2224 HIThemeDrawMenuSeparator(&macRect, &macRect, &midi, cgContext, HITHEME_ORIENTATION);
michael@0 2225 }
michael@0 2226 break;
michael@0 2227
michael@0 2228 case NS_THEME_TOOLTIP:
michael@0 2229 CGContextSetRGBFillColor(cgContext, 0.996, 1.000, 0.792, 0.950);
michael@0 2230 CGContextFillRect(cgContext, macRect);
michael@0 2231 break;
michael@0 2232
michael@0 2233 case NS_THEME_CHECKBOX:
michael@0 2234 case NS_THEME_RADIO: {
michael@0 2235 bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX);
michael@0 2236 DrawCheckboxOrRadio(cgContext, isCheckbox, macRect, GetCheckedOrSelected(aFrame, !isCheckbox),
michael@0 2237 eventState, aFrame);
michael@0 2238 }
michael@0 2239 break;
michael@0 2240
michael@0 2241 case NS_THEME_BUTTON:
michael@0 2242 if (IsDefaultButton(aFrame)) {
michael@0 2243 if (!IsDisabled(aFrame, eventState) && FrameIsInActiveWindow(aFrame) &&
michael@0 2244 !QueueAnimatedContentForRefresh(aFrame->GetContent(), 10)) {
michael@0 2245 NS_WARNING("Unable to animate button!");
michael@0 2246 }
michael@0 2247 DrawButton(cgContext, kThemePushButton, macRect, true,
michael@0 2248 kThemeButtonOff, kThemeAdornmentNone, eventState, aFrame);
michael@0 2249 } else if (IsButtonTypeMenu(aFrame)) {
michael@0 2250 DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
michael@0 2251 } else {
michael@0 2252 DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame);
michael@0 2253 }
michael@0 2254 break;
michael@0 2255
michael@0 2256 case NS_THEME_MOZ_MAC_HELP_BUTTON:
michael@0 2257 DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame);
michael@0 2258 break;
michael@0 2259
michael@0 2260 case NS_THEME_BUTTON_BEVEL:
michael@0 2261 DrawButton(cgContext, kThemeMediumBevelButton, macRect,
michael@0 2262 IsDefaultButton(aFrame), kThemeButtonOff, kThemeAdornmentNone,
michael@0 2263 eventState, aFrame);
michael@0 2264 break;
michael@0 2265
michael@0 2266 case NS_THEME_SPINNER: {
michael@0 2267 nsIContent* content = aFrame->GetContent();
michael@0 2268 if (content->IsHTML()) {
michael@0 2269 // In HTML the theming for the spin buttons is drawn individually into
michael@0 2270 // their own backgrounds instead of being drawn into the background of
michael@0 2271 // their spinner parent as it is for XUL.
michael@0 2272 break;
michael@0 2273 }
michael@0 2274 ThemeDrawState state = kThemeStateActive;
michael@0 2275 if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::state,
michael@0 2276 NS_LITERAL_STRING("up"), eCaseMatters)) {
michael@0 2277 state = kThemeStatePressedUp;
michael@0 2278 }
michael@0 2279 else if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::state,
michael@0 2280 NS_LITERAL_STRING("down"), eCaseMatters)) {
michael@0 2281 state = kThemeStatePressedDown;
michael@0 2282 }
michael@0 2283
michael@0 2284 DrawSpinButtons(cgContext, kThemeIncDecButton, macRect, state,
michael@0 2285 kThemeAdornmentNone, eventState, aFrame);
michael@0 2286 }
michael@0 2287 break;
michael@0 2288
michael@0 2289 case NS_THEME_SPINNER_UP_BUTTON:
michael@0 2290 case NS_THEME_SPINNER_DOWN_BUTTON: {
michael@0 2291 nsNumberControlFrame* numberControlFrame =
michael@0 2292 nsNumberControlFrame::GetNumberControlFrameForSpinButton(aFrame);
michael@0 2293 if (numberControlFrame) {
michael@0 2294 ThemeDrawState state = kThemeStateActive;
michael@0 2295 if (numberControlFrame->SpinnerUpButtonIsDepressed()) {
michael@0 2296 state = kThemeStatePressedUp;
michael@0 2297 } else if (numberControlFrame->SpinnerDownButtonIsDepressed()) {
michael@0 2298 state = kThemeStatePressedDown;
michael@0 2299 }
michael@0 2300 DrawSpinButton(cgContext, kThemeIncDecButtonMini, macRect, state,
michael@0 2301 kThemeAdornmentNone, eventState, aFrame, aWidgetType);
michael@0 2302 }
michael@0 2303 }
michael@0 2304 break;
michael@0 2305
michael@0 2306 case NS_THEME_TOOLBAR_BUTTON:
michael@0 2307 DrawSegment(cgContext, macRect, eventState, aFrame, toolbarButtonRenderSettings);
michael@0 2308 break;
michael@0 2309
michael@0 2310 case NS_THEME_TOOLBAR_SEPARATOR: {
michael@0 2311 HIThemeSeparatorDrawInfo sdi = { 0, kThemeStateActive };
michael@0 2312 HIThemeDrawSeparator(&macRect, &sdi, cgContext, HITHEME_ORIENTATION);
michael@0 2313 }
michael@0 2314 break;
michael@0 2315
michael@0 2316 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
michael@0 2317 case NS_THEME_TOOLBAR: {
michael@0 2318 NSWindow* win = NativeWindowForFrame(aFrame);
michael@0 2319 if (ToolbarCanBeUnified(cgContext, macRect, win)) {
michael@0 2320 DrawUnifiedToolbar(cgContext, macRect, win);
michael@0 2321 break;
michael@0 2322 }
michael@0 2323 BOOL isMain = [win isMainWindow];
michael@0 2324 CGRect drawRect = macRect;
michael@0 2325
michael@0 2326 // top border
michael@0 2327 drawRect.size.height = 1.0f;
michael@0 2328 DrawNativeGreyColorInRect(cgContext, toolbarTopBorderGrey, drawRect, isMain);
michael@0 2329
michael@0 2330 // background
michael@0 2331 drawRect.origin.y += drawRect.size.height;
michael@0 2332 drawRect.size.height = macRect.size.height - 2.0f;
michael@0 2333 DrawNativeGreyColorInRect(cgContext, toolbarFillGrey, drawRect, isMain);
michael@0 2334
michael@0 2335 // bottom border
michael@0 2336 drawRect.origin.y += drawRect.size.height;
michael@0 2337 drawRect.size.height = 1.0f;
michael@0 2338 DrawNativeGreyColorInRect(cgContext, toolbarBottomBorderGrey, drawRect, isMain);
michael@0 2339 }
michael@0 2340 break;
michael@0 2341
michael@0 2342 case NS_THEME_WINDOW_TITLEBAR: {
michael@0 2343 NSWindow* win = NativeWindowForFrame(aFrame);
michael@0 2344 BOOL isMain = [win isMainWindow];
michael@0 2345 float unifiedToolbarHeight = [win isKindOfClass:[ToolbarWindow class]] ?
michael@0 2346 [(ToolbarWindow*)win unifiedToolbarHeight] : macRect.size.height;
michael@0 2347 DrawNativeTitlebar(cgContext, macRect, unifiedToolbarHeight, isMain);
michael@0 2348 }
michael@0 2349 break;
michael@0 2350
michael@0 2351 case NS_THEME_TOOLBOX: {
michael@0 2352 HIThemeHeaderDrawInfo hdi = { 0, kThemeStateActive, kHIThemeHeaderKindWindow };
michael@0 2353 HIThemeDrawHeader(&macRect, &hdi, cgContext, HITHEME_ORIENTATION);
michael@0 2354 }
michael@0 2355 break;
michael@0 2356
michael@0 2357 case NS_THEME_STATUSBAR:
michael@0 2358 DrawStatusBar(cgContext, macRect, aFrame);
michael@0 2359 break;
michael@0 2360
michael@0 2361 case NS_THEME_DROPDOWN:
michael@0 2362 case NS_THEME_DROPDOWN_TEXTFIELD:
michael@0 2363 DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
michael@0 2364 break;
michael@0 2365
michael@0 2366 case NS_THEME_DROPDOWN_BUTTON:
michael@0 2367 DrawButton(cgContext, kThemeArrowButton, macRect, false, kThemeButtonOn,
michael@0 2368 kThemeAdornmentArrowDownArrow, eventState, aFrame);
michael@0 2369 break;
michael@0 2370
michael@0 2371 case NS_THEME_GROUPBOX: {
michael@0 2372 HIThemeGroupBoxDrawInfo gdi = { 0, kThemeStateActive, kHIThemeGroupBoxKindPrimary };
michael@0 2373 HIThemeDrawGroupBox(&macRect, &gdi, cgContext, HITHEME_ORIENTATION);
michael@0 2374 break;
michael@0 2375 }
michael@0 2376
michael@0 2377 case NS_THEME_TEXTFIELD:
michael@0 2378 case NS_THEME_NUMBER_INPUT:
michael@0 2379 // HIThemeSetFill is not available on 10.3
michael@0 2380 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
michael@0 2381 CGContextFillRect(cgContext, macRect);
michael@0 2382
michael@0 2383 // XUL textboxes set the native appearance on the containing box, while
michael@0 2384 // concrete focus is set on the html:input element within it. We can
michael@0 2385 // though, check the focused attribute of xul textboxes in this case.
michael@0 2386 // On Mac, focus rings are always shown for textboxes, so we do not need
michael@0 2387 // to check the window's focus ring state here
michael@0 2388 if (aFrame->GetContent()->IsXUL() && IsFocused(aFrame)) {
michael@0 2389 eventState |= NS_EVENT_STATE_FOCUS;
michael@0 2390 }
michael@0 2391
michael@0 2392 DrawFrame(cgContext, kHIThemeFrameTextFieldSquare, macRect,
michael@0 2393 IsDisabled(aFrame, eventState) || IsReadOnly(aFrame), eventState);
michael@0 2394 break;
michael@0 2395
michael@0 2396 case NS_THEME_SEARCHFIELD:
michael@0 2397 DrawSearchField(cgContext, macRect, aFrame, eventState);
michael@0 2398 break;
michael@0 2399
michael@0 2400 case NS_THEME_PROGRESSBAR:
michael@0 2401 if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) {
michael@0 2402 NS_WARNING("Unable to animate progressbar!");
michael@0 2403 }
michael@0 2404 DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame, eventState),
michael@0 2405 aFrame->StyleDisplay()->mOrient != NS_STYLE_ORIENT_VERTICAL,
michael@0 2406 GetProgressValue(aFrame), GetProgressMaxValue(aFrame), aFrame);
michael@0 2407 break;
michael@0 2408
michael@0 2409 case NS_THEME_PROGRESSBAR_VERTICAL:
michael@0 2410 DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame, eventState),
michael@0 2411 false, GetProgressValue(aFrame),
michael@0 2412 GetProgressMaxValue(aFrame), aFrame);
michael@0 2413 break;
michael@0 2414
michael@0 2415 case NS_THEME_METERBAR:
michael@0 2416 DrawMeter(cgContext, macRect, aFrame);
michael@0 2417 break;
michael@0 2418
michael@0 2419 case NS_THEME_PROGRESSBAR_CHUNK:
michael@0 2420 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
michael@0 2421 case NS_THEME_METERBAR_CHUNK:
michael@0 2422 // Do nothing: progress and meter bars cases will draw chunks.
michael@0 2423 break;
michael@0 2424
michael@0 2425 case NS_THEME_TREEVIEW_TWISTY:
michael@0 2426 DrawButton(cgContext, kThemeDisclosureButton, macRect, false,
michael@0 2427 kThemeDisclosureRight, kThemeAdornmentNone, eventState, aFrame);
michael@0 2428 break;
michael@0 2429
michael@0 2430 case NS_THEME_TREEVIEW_TWISTY_OPEN:
michael@0 2431 DrawButton(cgContext, kThemeDisclosureButton, macRect, false,
michael@0 2432 kThemeDisclosureDown, kThemeAdornmentNone, eventState, aFrame);
michael@0 2433 break;
michael@0 2434
michael@0 2435 case NS_THEME_TREEVIEW_HEADER_CELL: {
michael@0 2436 TreeSortDirection sortDirection = GetTreeSortDirection(aFrame);
michael@0 2437 DrawButton(cgContext, kThemeListHeaderButton, macRect, false,
michael@0 2438 sortDirection == eTreeSortDirection_Natural ? kThemeButtonOff : kThemeButtonOn,
michael@0 2439 sortDirection == eTreeSortDirection_Ascending ?
michael@0 2440 kThemeAdornmentHeaderButtonSortUp : kThemeAdornmentNone, eventState, aFrame);
michael@0 2441 }
michael@0 2442 break;
michael@0 2443
michael@0 2444 case NS_THEME_TREEVIEW_TREEITEM:
michael@0 2445 case NS_THEME_TREEVIEW:
michael@0 2446 // HIThemeSetFill is not available on 10.3
michael@0 2447 // HIThemeSetFill(kThemeBrushWhite, NULL, cgContext, HITHEME_ORIENTATION);
michael@0 2448 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
michael@0 2449 CGContextFillRect(cgContext, macRect);
michael@0 2450 break;
michael@0 2451
michael@0 2452 case NS_THEME_TREEVIEW_HEADER:
michael@0 2453 // do nothing, taken care of by individual header cells
michael@0 2454 case NS_THEME_TREEVIEW_HEADER_SORTARROW:
michael@0 2455 // do nothing, taken care of by treeview header
michael@0 2456 case NS_THEME_TREEVIEW_LINE:
michael@0 2457 // do nothing, these lines don't exist on macos
michael@0 2458 break;
michael@0 2459
michael@0 2460 case NS_THEME_SCALE_HORIZONTAL:
michael@0 2461 case NS_THEME_SCALE_VERTICAL: {
michael@0 2462 int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
michael@0 2463 int32_t minpos = CheckIntAttr(aFrame, nsGkAtoms::minpos, 0);
michael@0 2464 int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
michael@0 2465 if (!maxpos)
michael@0 2466 maxpos = 100;
michael@0 2467
michael@0 2468 bool reverse = aFrame->GetContent()->
michael@0 2469 AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
michael@0 2470 NS_LITERAL_STRING("reverse"), eCaseMatters);
michael@0 2471 DrawScale(cgContext, macRect, eventState,
michael@0 2472 (aWidgetType == NS_THEME_SCALE_VERTICAL), reverse,
michael@0 2473 curpos, minpos, maxpos, aFrame);
michael@0 2474 }
michael@0 2475 break;
michael@0 2476
michael@0 2477 case NS_THEME_SCALE_THUMB_HORIZONTAL:
michael@0 2478 case NS_THEME_SCALE_THUMB_VERTICAL:
michael@0 2479 // do nothing, drawn by scale
michael@0 2480 break;
michael@0 2481
michael@0 2482 case NS_THEME_RANGE: {
michael@0 2483 nsRangeFrame *rangeFrame = do_QueryFrame(aFrame);
michael@0 2484 if (!rangeFrame) {
michael@0 2485 break;
michael@0 2486 }
michael@0 2487 // DrawScale requires integer min, max and value. This is purely for
michael@0 2488 // drawing, so we normalize to a range 0-1000 here.
michael@0 2489 int32_t value = int32_t(rangeFrame->GetValueAsFractionOfRange() * 1000);
michael@0 2490 int32_t min = 0;
michael@0 2491 int32_t max = 1000;
michael@0 2492 bool isVertical = !IsRangeHorizontal(aFrame);
michael@0 2493 bool reverseDir =
michael@0 2494 isVertical ||
michael@0 2495 rangeFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
michael@0 2496 DrawScale(cgContext, macRect, eventState, isVertical, reverseDir,
michael@0 2497 value, min, max, aFrame);
michael@0 2498 break;
michael@0 2499 }
michael@0 2500
michael@0 2501 case NS_THEME_SCROLLBAR_SMALL:
michael@0 2502 case NS_THEME_SCROLLBAR:
michael@0 2503 if (!nsLookAndFeel::UseOverlayScrollbars()) {
michael@0 2504 DrawScrollbar(cgContext, macRect, aFrame);
michael@0 2505 }
michael@0 2506 break;
michael@0 2507 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
michael@0 2508 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
michael@0 2509 if (nsLookAndFeel::UseOverlayScrollbars()) {
michael@0 2510 BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL);
michael@0 2511 BOOL isRolledOver = CheckBooleanAttr(GetParentScrollbarFrame(aFrame),
michael@0 2512 nsGkAtoms::hover);
michael@0 2513 if (!nsCocoaFeatures::OnMountainLionOrLater() || !isRolledOver) {
michael@0 2514 if (isHorizontal) {
michael@0 2515 macRect.origin.y += 4;
michael@0 2516 macRect.size.height -= 4;
michael@0 2517 } else {
michael@0 2518 if (aFrame->StyleVisibility()->mDirection !=
michael@0 2519 NS_STYLE_DIRECTION_RTL) {
michael@0 2520 macRect.origin.x += 4;
michael@0 2521 }
michael@0 2522 macRect.size.width -= 4;
michael@0 2523 }
michael@0 2524 }
michael@0 2525 const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
michael@0 2526 CUIDraw([NSWindow coreUIRenderer], macRect, cgContext,
michael@0 2527 (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
michael@0 2528 @"kCUIWidgetOverlayScrollBar", @"widget",
michael@0 2529 @"regular", @"size",
michael@0 2530 (isRolledOver ? @"rollover" : @""), @"state",
michael@0 2531 (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
michael@0 2532 (isOnTopOfDarkBackground ? @"kCUIVariantWhite" : @""), @"kCUIVariantKey",
michael@0 2533 [NSNumber numberWithBool:YES], @"indiconly",
michael@0 2534 [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
michael@0 2535 [NSNumber numberWithBool:YES], @"is.flipped",
michael@0 2536 nil],
michael@0 2537 nil);
michael@0 2538 }
michael@0 2539 break;
michael@0 2540 case NS_THEME_SCROLLBAR_BUTTON_UP:
michael@0 2541 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
michael@0 2542 #if SCROLLBARS_VISUAL_DEBUG
michael@0 2543 CGContextSetRGBFillColor(cgContext, 1.0, 0, 0, 0.6);
michael@0 2544 CGContextFillRect(cgContext, macRect);
michael@0 2545 #endif
michael@0 2546 break;
michael@0 2547 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
michael@0 2548 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
michael@0 2549 #if SCROLLBARS_VISUAL_DEBUG
michael@0 2550 CGContextSetRGBFillColor(cgContext, 0, 1.0, 0, 0.6);
michael@0 2551 CGContextFillRect(cgContext, macRect);
michael@0 2552 #endif
michael@0 2553 break;
michael@0 2554 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
michael@0 2555 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
michael@0 2556 if (nsLookAndFeel::UseOverlayScrollbars() &&
michael@0 2557 CheckBooleanAttr(GetParentScrollbarFrame(aFrame), nsGkAtoms::hover)) {
michael@0 2558 BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
michael@0 2559 if (!nsCocoaFeatures::OnMountainLionOrLater()) {
michael@0 2560 // On OSX 10.7, scrollbars don't grow when hovered. The adjustments
michael@0 2561 // below were obtained by trial and error.
michael@0 2562 if (isHorizontal) {
michael@0 2563 macRect.origin.y += 2.0;
michael@0 2564 } else {
michael@0 2565 if (aFrame->StyleVisibility()->mDirection !=
michael@0 2566 NS_STYLE_DIRECTION_RTL) {
michael@0 2567 macRect.origin.x += 3.0;
michael@0 2568 } else {
michael@0 2569 macRect.origin.x -= 1.0;
michael@0 2570 }
michael@0 2571 }
michael@0 2572 }
michael@0 2573 const BOOL isOnTopOfDarkBackground = IsDarkBackground(aFrame);
michael@0 2574 CUIDraw([NSWindow coreUIRenderer], macRect, cgContext,
michael@0 2575 (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
michael@0 2576 @"kCUIWidgetOverlayScrollBar", @"widget",
michael@0 2577 @"regular", @"size",
michael@0 2578 (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
michael@0 2579 (isOnTopOfDarkBackground ? @"kCUIVariantWhite" : @""), @"kCUIVariantKey",
michael@0 2580 [NSNumber numberWithBool:YES], @"noindicator",
michael@0 2581 [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
michael@0 2582 [NSNumber numberWithBool:YES], @"is.flipped",
michael@0 2583 nil],
michael@0 2584 nil);
michael@0 2585 }
michael@0 2586 break;
michael@0 2587
michael@0 2588 case NS_THEME_TEXTFIELD_MULTILINE: {
michael@0 2589 // we have to draw this by hand because there is no HITheme value for it
michael@0 2590 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
michael@0 2591
michael@0 2592 CGContextFillRect(cgContext, macRect);
michael@0 2593
michael@0 2594 CGContextSetLineWidth(cgContext, 1.0);
michael@0 2595 CGContextSetShouldAntialias(cgContext, false);
michael@0 2596
michael@0 2597 // stroke everything but the top line of the text area
michael@0 2598 CGContextSetRGBStrokeColor(cgContext, 0.6, 0.6, 0.6, 1.0);
michael@0 2599 CGContextBeginPath(cgContext);
michael@0 2600 CGContextMoveToPoint(cgContext, macRect.origin.x, macRect.origin.y + 1);
michael@0 2601 CGContextAddLineToPoint(cgContext, macRect.origin.x, macRect.origin.y + macRect.size.height);
michael@0 2602 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + macRect.size.height);
michael@0 2603 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + 1);
michael@0 2604 CGContextStrokePath(cgContext);
michael@0 2605
michael@0 2606 // stroke the line across the top of the text area
michael@0 2607 CGContextSetRGBStrokeColor(cgContext, 0.4510, 0.4510, 0.4510, 1.0);
michael@0 2608 CGContextBeginPath(cgContext);
michael@0 2609 CGContextMoveToPoint(cgContext, macRect.origin.x, macRect.origin.y + 1);
michael@0 2610 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + 1);
michael@0 2611 CGContextStrokePath(cgContext);
michael@0 2612
michael@0 2613 // draw a focus ring
michael@0 2614 if (eventState.HasState(NS_EVENT_STATE_FOCUS)) {
michael@0 2615 // We need to bring the rectangle in by 1 pixel on each side.
michael@0 2616 CGRect cgr = CGRectMake(macRect.origin.x + 1,
michael@0 2617 macRect.origin.y + 1,
michael@0 2618 macRect.size.width - 2,
michael@0 2619 macRect.size.height - 2);
michael@0 2620 HIThemeDrawFocusRect(&cgr, true, cgContext, kHIThemeOrientationNormal);
michael@0 2621 }
michael@0 2622 }
michael@0 2623 break;
michael@0 2624
michael@0 2625 case NS_THEME_LISTBOX: {
michael@0 2626 // We have to draw this by hand because kHIThemeFrameListBox drawing
michael@0 2627 // is buggy on 10.5, see bug 579259.
michael@0 2628 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
michael@0 2629 CGContextFillRect(cgContext, macRect);
michael@0 2630
michael@0 2631 // #8E8E8E for the top border, #BEBEBE for the rest.
michael@0 2632 float x = macRect.origin.x, y = macRect.origin.y;
michael@0 2633 float w = macRect.size.width, h = macRect.size.height;
michael@0 2634 CGContextSetRGBFillColor(cgContext, 0.557, 0.557, 0.557, 1.0);
michael@0 2635 CGContextFillRect(cgContext, CGRectMake(x, y, w, 1));
michael@0 2636 CGContextSetRGBFillColor(cgContext, 0.745, 0.745, 0.745, 1.0);
michael@0 2637 CGContextFillRect(cgContext, CGRectMake(x, y + 1, 1, h - 1));
michael@0 2638 CGContextFillRect(cgContext, CGRectMake(x + w - 1, y + 1, 1, h - 1));
michael@0 2639 CGContextFillRect(cgContext, CGRectMake(x + 1, y + h - 1, w - 2, 1));
michael@0 2640 }
michael@0 2641 break;
michael@0 2642
michael@0 2643 case NS_THEME_TAB:
michael@0 2644 DrawSegment(cgContext, macRect, eventState, aFrame, tabRenderSettings);
michael@0 2645 break;
michael@0 2646
michael@0 2647 case NS_THEME_TAB_PANELS:
michael@0 2648 DrawTabPanel(cgContext, macRect, aFrame);
michael@0 2649 break;
michael@0 2650
michael@0 2651 case NS_THEME_RESIZER:
michael@0 2652 DrawResizer(cgContext, macRect, aFrame);
michael@0 2653 break;
michael@0 2654 }
michael@0 2655
michael@0 2656 nativeDrawing.EndNativeDrawing();
michael@0 2657
michael@0 2658 return NS_OK;
michael@0 2659
michael@0 2660 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 2661 }
michael@0 2662
michael@0 2663 nsIntMargin
michael@0 2664 nsNativeThemeCocoa::RTLAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame)
michael@0 2665 {
michael@0 2666 if (IsFrameRTL(aFrame)) {
michael@0 2667 // Return a copy of aMargin w/ right & left reversed:
michael@0 2668 return nsIntMargin(aMargin.top, aMargin.left,
michael@0 2669 aMargin.bottom, aMargin.right);
michael@0 2670 }
michael@0 2671
michael@0 2672 return aMargin;
michael@0 2673 }
michael@0 2674
michael@0 2675 static const nsIntMargin kAquaDropdownBorder(1, 22, 2, 5);
michael@0 2676 static const nsIntMargin kAquaComboboxBorder(3, 20, 3, 4);
michael@0 2677 static const nsIntMargin kAquaSearchfieldBorder(3, 5, 2, 19);
michael@0 2678
michael@0 2679 NS_IMETHODIMP
michael@0 2680 nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext,
michael@0 2681 nsIFrame* aFrame,
michael@0 2682 uint8_t aWidgetType,
michael@0 2683 nsIntMargin* aResult)
michael@0 2684 {
michael@0 2685 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 2686
michael@0 2687 aResult->SizeTo(0, 0, 0, 0);
michael@0 2688
michael@0 2689 switch (aWidgetType) {
michael@0 2690 case NS_THEME_BUTTON:
michael@0 2691 {
michael@0 2692 if (IsButtonTypeMenu(aFrame)) {
michael@0 2693 *aResult = RTLAwareMargin(kAquaDropdownBorder, aFrame);
michael@0 2694 } else {
michael@0 2695 aResult->SizeTo(1, 7, 3, 7);
michael@0 2696 }
michael@0 2697 break;
michael@0 2698 }
michael@0 2699
michael@0 2700 case NS_THEME_TOOLBAR_BUTTON:
michael@0 2701 {
michael@0 2702 aResult->SizeTo(1, 4, 1, 4);
michael@0 2703 break;
michael@0 2704 }
michael@0 2705
michael@0 2706 case NS_THEME_CHECKBOX:
michael@0 2707 case NS_THEME_RADIO:
michael@0 2708 {
michael@0 2709 // nsFormControlFrame::GetIntrinsicWidth and nsFormControlFrame::GetIntrinsicHeight
michael@0 2710 // assume a border width of 2px.
michael@0 2711 aResult->SizeTo(2, 2, 2, 2);
michael@0 2712 break;
michael@0 2713 }
michael@0 2714
michael@0 2715 case NS_THEME_DROPDOWN:
michael@0 2716 case NS_THEME_DROPDOWN_BUTTON:
michael@0 2717 *aResult = RTLAwareMargin(kAquaDropdownBorder, aFrame);
michael@0 2718 break;
michael@0 2719
michael@0 2720 case NS_THEME_DROPDOWN_TEXTFIELD:
michael@0 2721 *aResult = RTLAwareMargin(kAquaComboboxBorder, aFrame);
michael@0 2722 break;
michael@0 2723
michael@0 2724 case NS_THEME_NUMBER_INPUT:
michael@0 2725 case NS_THEME_TEXTFIELD:
michael@0 2726 {
michael@0 2727 SInt32 frameOutset = 0;
michael@0 2728 ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
michael@0 2729
michael@0 2730 SInt32 textPadding = 0;
michael@0 2731 ::GetThemeMetric(kThemeMetricEditTextWhitespace, &textPadding);
michael@0 2732
michael@0 2733 frameOutset += textPadding;
michael@0 2734
michael@0 2735 aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
michael@0 2736 break;
michael@0 2737 }
michael@0 2738
michael@0 2739 case NS_THEME_TEXTFIELD_MULTILINE:
michael@0 2740 aResult->SizeTo(1, 1, 1, 1);
michael@0 2741 break;
michael@0 2742
michael@0 2743 case NS_THEME_SEARCHFIELD:
michael@0 2744 *aResult = RTLAwareMargin(kAquaSearchfieldBorder, aFrame);
michael@0 2745 break;
michael@0 2746
michael@0 2747 case NS_THEME_LISTBOX:
michael@0 2748 {
michael@0 2749 SInt32 frameOutset = 0;
michael@0 2750 ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
michael@0 2751 aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
michael@0 2752 break;
michael@0 2753 }
michael@0 2754
michael@0 2755 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
michael@0 2756 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
michael@0 2757 {
michael@0 2758 bool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
michael@0 2759
michael@0 2760 // On Lion and later, scrollbars have no arrows.
michael@0 2761 if (!nsCocoaFeatures::OnLionOrLater()) {
michael@0 2762 // There's only an endcap to worry about when both arrows are on the bottom
michael@0 2763 NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
michael@0 2764 if (!buttonPlacement || [buttonPlacement isEqualToString:@"DoubleMax"]) {
michael@0 2765 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
michael@0 2766 if (!scrollbarFrame) return NS_ERROR_FAILURE;
michael@0 2767 bool isSmall = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
michael@0 2768
michael@0 2769 // There isn't a metric for this, so just hardcode a best guess at the value.
michael@0 2770 // This value is even less exact due to the fact that the endcap is partially concave.
michael@0 2771 int32_t endcapSize = isSmall ? 5 : 6;
michael@0 2772
michael@0 2773 if (isHorizontal)
michael@0 2774 aResult->SizeTo(0, 0, 0, endcapSize);
michael@0 2775 else
michael@0 2776 aResult->SizeTo(endcapSize, 0, 0, 0);
michael@0 2777 }
michael@0 2778 }
michael@0 2779
michael@0 2780 if (nsLookAndFeel::UseOverlayScrollbars()) {
michael@0 2781 if (isHorizontal) {
michael@0 2782 aResult->SizeTo(2, 1, 1, 1);
michael@0 2783 } else {
michael@0 2784 aResult->SizeTo(1, 1, 1, 2);
michael@0 2785 }
michael@0 2786 }
michael@0 2787
michael@0 2788 break;
michael@0 2789 }
michael@0 2790
michael@0 2791 case NS_THEME_STATUSBAR:
michael@0 2792 aResult->SizeTo(1, 0, 0, 0);
michael@0 2793 break;
michael@0 2794 }
michael@0 2795
michael@0 2796 if (IsHiDPIContext(aContext)) {
michael@0 2797 *aResult = *aResult + *aResult; // doubled
michael@0 2798 }
michael@0 2799
michael@0 2800 return NS_OK;
michael@0 2801
michael@0 2802 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 2803 }
michael@0 2804
michael@0 2805 // Return false here to indicate that CSS padding values should be used. There is
michael@0 2806 // no reason to make a distinction between padding and border values, just specify
michael@0 2807 // whatever values you want in GetWidgetBorder and only use this to return true
michael@0 2808 // if you want to override CSS padding values.
michael@0 2809 bool
michael@0 2810 nsNativeThemeCocoa::GetWidgetPadding(nsDeviceContext* aContext,
michael@0 2811 nsIFrame* aFrame,
michael@0 2812 uint8_t aWidgetType,
michael@0 2813 nsIntMargin* aResult)
michael@0 2814 {
michael@0 2815 // We don't want CSS padding being used for certain widgets.
michael@0 2816 // See bug 381639 for an example of why.
michael@0 2817 switch (aWidgetType) {
michael@0 2818 case NS_THEME_BUTTON:
michael@0 2819 // Radios and checkboxes return a fixed size in GetMinimumWidgetSize
michael@0 2820 // and have a meaningful baseline, so they can't have
michael@0 2821 // author-specified padding.
michael@0 2822 case NS_THEME_CHECKBOX:
michael@0 2823 case NS_THEME_RADIO:
michael@0 2824 aResult->SizeTo(0, 0, 0, 0);
michael@0 2825 return true;
michael@0 2826 }
michael@0 2827 return false;
michael@0 2828 }
michael@0 2829
michael@0 2830 bool
michael@0 2831 nsNativeThemeCocoa::GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
michael@0 2832 uint8_t aWidgetType, nsRect* aOverflowRect)
michael@0 2833 {
michael@0 2834 int32_t p2a = aContext->AppUnitsPerDevPixel();
michael@0 2835 switch (aWidgetType) {
michael@0 2836 case NS_THEME_BUTTON:
michael@0 2837 case NS_THEME_MOZ_MAC_HELP_BUTTON:
michael@0 2838 case NS_THEME_TOOLBAR_BUTTON:
michael@0 2839 case NS_THEME_NUMBER_INPUT:
michael@0 2840 case NS_THEME_TEXTFIELD:
michael@0 2841 case NS_THEME_TEXTFIELD_MULTILINE:
michael@0 2842 case NS_THEME_SEARCHFIELD:
michael@0 2843 case NS_THEME_LISTBOX:
michael@0 2844 case NS_THEME_DROPDOWN:
michael@0 2845 case NS_THEME_DROPDOWN_BUTTON:
michael@0 2846 case NS_THEME_DROPDOWN_TEXTFIELD:
michael@0 2847 case NS_THEME_CHECKBOX:
michael@0 2848 case NS_THEME_RADIO:
michael@0 2849 case NS_THEME_TAB:
michael@0 2850 {
michael@0 2851 // We assume that the above widgets can draw a focus ring that will be less than
michael@0 2852 // or equal to 4 pixels thick.
michael@0 2853 nsIntMargin extraSize = nsIntMargin(MAX_FOCUS_RING_WIDTH,
michael@0 2854 MAX_FOCUS_RING_WIDTH,
michael@0 2855 MAX_FOCUS_RING_WIDTH,
michael@0 2856 MAX_FOCUS_RING_WIDTH);
michael@0 2857 nsMargin m(NSIntPixelsToAppUnits(extraSize.top, p2a),
michael@0 2858 NSIntPixelsToAppUnits(extraSize.right, p2a),
michael@0 2859 NSIntPixelsToAppUnits(extraSize.bottom, p2a),
michael@0 2860 NSIntPixelsToAppUnits(extraSize.left, p2a));
michael@0 2861 aOverflowRect->Inflate(m);
michael@0 2862 return true;
michael@0 2863 }
michael@0 2864 case NS_THEME_PROGRESSBAR:
michael@0 2865 {
michael@0 2866 // Progress bars draw a 2 pixel white shadow under their progress indicators
michael@0 2867 nsMargin m(0, 0, NSIntPixelsToAppUnits(2, p2a), 0);
michael@0 2868 aOverflowRect->Inflate(m);
michael@0 2869 return true;
michael@0 2870 }
michael@0 2871 }
michael@0 2872
michael@0 2873 return false;
michael@0 2874 }
michael@0 2875
michael@0 2876 static const int32_t kRegularScrollbarThumbMinSize = 26;
michael@0 2877 static const int32_t kSmallScrollbarThumbMinSize = 26;
michael@0 2878
michael@0 2879 NS_IMETHODIMP
michael@0 2880 nsNativeThemeCocoa::GetMinimumWidgetSize(nsRenderingContext* aContext,
michael@0 2881 nsIFrame* aFrame,
michael@0 2882 uint8_t aWidgetType,
michael@0 2883 nsIntSize* aResult,
michael@0 2884 bool* aIsOverridable)
michael@0 2885 {
michael@0 2886 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 2887
michael@0 2888 aResult->SizeTo(0,0);
michael@0 2889 *aIsOverridable = true;
michael@0 2890
michael@0 2891 switch (aWidgetType) {
michael@0 2892 case NS_THEME_BUTTON:
michael@0 2893 {
michael@0 2894 aResult->SizeTo(pushButtonSettings.minimumSizes[miniControlSize].width,
michael@0 2895 pushButtonSettings.naturalSizes[miniControlSize].height);
michael@0 2896 break;
michael@0 2897 }
michael@0 2898
michael@0 2899 case NS_THEME_MOZ_MAC_HELP_BUTTON:
michael@0 2900 {
michael@0 2901 aResult->SizeTo(kHelpButtonSize.width, kHelpButtonSize.height);
michael@0 2902 *aIsOverridable = false;
michael@0 2903 break;
michael@0 2904 }
michael@0 2905
michael@0 2906 case NS_THEME_TOOLBAR_BUTTON:
michael@0 2907 {
michael@0 2908 aResult->SizeTo(0, toolbarButtonHeights[miniControlSize]);
michael@0 2909 break;
michael@0 2910 }
michael@0 2911
michael@0 2912 case NS_THEME_SPINNER:
michael@0 2913 case NS_THEME_SPINNER_UP_BUTTON:
michael@0 2914 case NS_THEME_SPINNER_DOWN_BUTTON:
michael@0 2915 {
michael@0 2916 SInt32 buttonHeight = 0, buttonWidth = 0;
michael@0 2917 if (aFrame->GetContent()->IsXUL()) {
michael@0 2918 ::GetThemeMetric(kThemeMetricLittleArrowsWidth, &buttonWidth);
michael@0 2919 ::GetThemeMetric(kThemeMetricLittleArrowsHeight, &buttonHeight);
michael@0 2920 } else {
michael@0 2921 NSSize size =
michael@0 2922 spinnerSettings.minimumSizes[EnumSizeForCocoaSize(NSMiniControlSize)];
michael@0 2923 buttonWidth = size.width;
michael@0 2924 buttonHeight = size.height;
michael@0 2925 if (aWidgetType != NS_THEME_SPINNER) {
michael@0 2926 // the buttons are half the height of the spinner
michael@0 2927 buttonHeight /= 2;
michael@0 2928 }
michael@0 2929 }
michael@0 2930 aResult->SizeTo(buttonWidth, buttonHeight);
michael@0 2931 *aIsOverridable = true;
michael@0 2932 break;
michael@0 2933 }
michael@0 2934
michael@0 2935 case NS_THEME_DROPDOWN:
michael@0 2936 case NS_THEME_DROPDOWN_BUTTON:
michael@0 2937 {
michael@0 2938 SInt32 popupHeight = 0;
michael@0 2939 ::GetThemeMetric(kThemeMetricPopupButtonHeight, &popupHeight);
michael@0 2940 aResult->SizeTo(0, popupHeight);
michael@0 2941 break;
michael@0 2942 }
michael@0 2943
michael@0 2944 case NS_THEME_NUMBER_INPUT:
michael@0 2945 case NS_THEME_TEXTFIELD:
michael@0 2946 case NS_THEME_TEXTFIELD_MULTILINE:
michael@0 2947 case NS_THEME_SEARCHFIELD:
michael@0 2948 {
michael@0 2949 // at minimum, we should be tall enough for 9pt text.
michael@0 2950 // I'm using hardcoded values here because the appearance manager
michael@0 2951 // values for the frame size are incorrect.
michael@0 2952 aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */);
michael@0 2953 break;
michael@0 2954 }
michael@0 2955
michael@0 2956 case NS_THEME_WINDOW_BUTTON_BOX: {
michael@0 2957 NSSize size = WindowButtonsSize(aFrame);
michael@0 2958 aResult->SizeTo(size.width, size.height);
michael@0 2959 *aIsOverridable = false;
michael@0 2960 break;
michael@0 2961 }
michael@0 2962
michael@0 2963 case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: {
michael@0 2964 if ([NativeWindowForFrame(aFrame) respondsToSelector:@selector(toggleFullScreen:)]) {
michael@0 2965 // This value is hardcoded because it's needed before we can measure the
michael@0 2966 // position and size of the fullscreen button.
michael@0 2967 aResult->SizeTo(16, 17);
michael@0 2968 }
michael@0 2969 *aIsOverridable = false;
michael@0 2970 break;
michael@0 2971 }
michael@0 2972
michael@0 2973 case NS_THEME_PROGRESSBAR:
michael@0 2974 {
michael@0 2975 SInt32 barHeight = 0;
michael@0 2976 ::GetThemeMetric(kThemeMetricNormalProgressBarThickness, &barHeight);
michael@0 2977 aResult->SizeTo(0, barHeight);
michael@0 2978 break;
michael@0 2979 }
michael@0 2980
michael@0 2981 case NS_THEME_TREEVIEW_TWISTY:
michael@0 2982 case NS_THEME_TREEVIEW_TWISTY_OPEN:
michael@0 2983 {
michael@0 2984 SInt32 twistyHeight = 0, twistyWidth = 0;
michael@0 2985 ::GetThemeMetric(kThemeMetricDisclosureButtonWidth, &twistyWidth);
michael@0 2986 ::GetThemeMetric(kThemeMetricDisclosureButtonHeight, &twistyHeight);
michael@0 2987 aResult->SizeTo(twistyWidth, twistyHeight);
michael@0 2988 *aIsOverridable = false;
michael@0 2989 break;
michael@0 2990 }
michael@0 2991
michael@0 2992 case NS_THEME_TREEVIEW_HEADER:
michael@0 2993 case NS_THEME_TREEVIEW_HEADER_CELL:
michael@0 2994 {
michael@0 2995 SInt32 headerHeight = 0;
michael@0 2996 ::GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
michael@0 2997 aResult->SizeTo(0, headerHeight - 1); // We don't need the top border.
michael@0 2998 break;
michael@0 2999 }
michael@0 3000
michael@0 3001 case NS_THEME_TAB:
michael@0 3002 {
michael@0 3003 aResult->SizeTo(0, tabHeights[miniControlSize]);
michael@0 3004 break;
michael@0 3005 }
michael@0 3006
michael@0 3007 case NS_THEME_RANGE:
michael@0 3008 {
michael@0 3009 // The Mac Appearance Manager API (the old API we're currently using)
michael@0 3010 // doesn't define constants to obtain a minimum size for sliders. We use
michael@0 3011 // the "thickness" of a slider that has default dimensions for both the
michael@0 3012 // minimum width and height to get something sane and so that paint
michael@0 3013 // invalidation works.
michael@0 3014 SInt32 size = 0;
michael@0 3015 if (IsRangeHorizontal(aFrame)) {
michael@0 3016 ::GetThemeMetric(kThemeMetricHSliderHeight, &size);
michael@0 3017 } else {
michael@0 3018 ::GetThemeMetric(kThemeMetricVSliderWidth, &size);
michael@0 3019 }
michael@0 3020 aResult->SizeTo(size, size);
michael@0 3021 *aIsOverridable = true;
michael@0 3022 break;
michael@0 3023 }
michael@0 3024
michael@0 3025 case NS_THEME_RANGE_THUMB:
michael@0 3026 {
michael@0 3027 SInt32 width = 0;
michael@0 3028 SInt32 height = 0;
michael@0 3029 ::GetThemeMetric(kThemeMetricSliderMinThumbWidth, &width);
michael@0 3030 ::GetThemeMetric(kThemeMetricSliderMinThumbHeight, &height);
michael@0 3031 aResult->SizeTo(width, height);
michael@0 3032 *aIsOverridable = false;
michael@0 3033 break;
michael@0 3034 }
michael@0 3035
michael@0 3036 case NS_THEME_SCALE_HORIZONTAL:
michael@0 3037 {
michael@0 3038 SInt32 scaleHeight = 0;
michael@0 3039 ::GetThemeMetric(kThemeMetricHSliderHeight, &scaleHeight);
michael@0 3040 aResult->SizeTo(scaleHeight, scaleHeight);
michael@0 3041 *aIsOverridable = false;
michael@0 3042 break;
michael@0 3043 }
michael@0 3044
michael@0 3045 case NS_THEME_SCALE_VERTICAL:
michael@0 3046 {
michael@0 3047 SInt32 scaleWidth = 0;
michael@0 3048 ::GetThemeMetric(kThemeMetricVSliderWidth, &scaleWidth);
michael@0 3049 aResult->SizeTo(scaleWidth, scaleWidth);
michael@0 3050 *aIsOverridable = false;
michael@0 3051 break;
michael@0 3052 }
michael@0 3053
michael@0 3054 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
michael@0 3055 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
michael@0 3056 {
michael@0 3057 // Find our parent scrollbar frame in order to find out whether we're in
michael@0 3058 // a small or a large scrollbar.
michael@0 3059 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
michael@0 3060 if (!scrollbarFrame)
michael@0 3061 return NS_ERROR_FAILURE;
michael@0 3062
michael@0 3063 bool isSmall = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
michael@0 3064 bool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL);
michael@0 3065 int32_t& minSize = isHorizontal ? aResult->width : aResult->height;
michael@0 3066 minSize = isSmall ? kSmallScrollbarThumbMinSize : kRegularScrollbarThumbMinSize;
michael@0 3067 break;
michael@0 3068 }
michael@0 3069
michael@0 3070 case NS_THEME_SCROLLBAR:
michael@0 3071 case NS_THEME_SCROLLBAR_SMALL:
michael@0 3072 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
michael@0 3073 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
michael@0 3074 {
michael@0 3075 *aIsOverridable = false;
michael@0 3076
michael@0 3077 if (nsLookAndFeel::UseOverlayScrollbars()) {
michael@0 3078 nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
michael@0 3079 if (scrollbarFrame &&
michael@0 3080 scrollbarFrame->StyleDisplay()->mAppearance ==
michael@0 3081 NS_THEME_SCROLLBAR_SMALL) {
michael@0 3082 aResult->SizeTo(14, 14);
michael@0 3083 }
michael@0 3084 else {
michael@0 3085 aResult->SizeTo(16, 16);
michael@0 3086 }
michael@0 3087 break;
michael@0 3088 }
michael@0 3089
michael@0 3090 // yeah, i know i'm cheating a little here, but i figure that it
michael@0 3091 // really doesn't matter if the scrollbar is vertical or horizontal
michael@0 3092 // and the width metric is a really good metric for every piece
michael@0 3093 // of the scrollbar.
michael@0 3094
michael@0 3095 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
michael@0 3096 if (!scrollbarFrame) return NS_ERROR_FAILURE;
michael@0 3097
michael@0 3098 int32_t themeMetric = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
michael@0 3099 kThemeMetricSmallScrollBarWidth :
michael@0 3100 kThemeMetricScrollBarWidth;
michael@0 3101 SInt32 scrollbarWidth = 0;
michael@0 3102 ::GetThemeMetric(themeMetric, &scrollbarWidth);
michael@0 3103 aResult->SizeTo(scrollbarWidth, scrollbarWidth);
michael@0 3104 break;
michael@0 3105 }
michael@0 3106
michael@0 3107 case NS_THEME_SCROLLBAR_NON_DISAPPEARING:
michael@0 3108 {
michael@0 3109 int32_t themeMetric = kThemeMetricScrollBarWidth;
michael@0 3110
michael@0 3111 if (aFrame) {
michael@0 3112 nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
michael@0 3113 if (scrollbarFrame &&
michael@0 3114 scrollbarFrame->StyleDisplay()->mAppearance ==
michael@0 3115 NS_THEME_SCROLLBAR_SMALL) {
michael@0 3116 // XXX We're interested in the width of non-disappearing scrollbars
michael@0 3117 // to leave enough space for a dropmarker in non-native styled
michael@0 3118 // comboboxes (bug 869314). It isn't clear to me if comboboxes can
michael@0 3119 // ever have small scrollbars.
michael@0 3120 themeMetric = kThemeMetricSmallScrollBarWidth;
michael@0 3121 }
michael@0 3122 }
michael@0 3123
michael@0 3124 SInt32 scrollbarWidth = 0;
michael@0 3125 ::GetThemeMetric(themeMetric, &scrollbarWidth);
michael@0 3126 aResult->SizeTo(scrollbarWidth, scrollbarWidth);
michael@0 3127 break;
michael@0 3128 }
michael@0 3129
michael@0 3130 case NS_THEME_SCROLLBAR_BUTTON_UP:
michael@0 3131 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
michael@0 3132 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
michael@0 3133 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
michael@0 3134 {
michael@0 3135 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
michael@0 3136 if (!scrollbarFrame) return NS_ERROR_FAILURE;
michael@0 3137
michael@0 3138 // Since there is no NS_THEME_SCROLLBAR_BUTTON_UP_SMALL we need to ask the parent what appearance style it has.
michael@0 3139 int32_t themeMetric = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
michael@0 3140 kThemeMetricSmallScrollBarWidth :
michael@0 3141 kThemeMetricScrollBarWidth;
michael@0 3142 SInt32 scrollbarWidth = 0;
michael@0 3143 ::GetThemeMetric(themeMetric, &scrollbarWidth);
michael@0 3144
michael@0 3145 // It seems that for both sizes of scrollbar, the buttons are one pixel "longer".
michael@0 3146 if (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT)
michael@0 3147 aResult->SizeTo(scrollbarWidth+1, scrollbarWidth);
michael@0 3148 else
michael@0 3149 aResult->SizeTo(scrollbarWidth, scrollbarWidth+1);
michael@0 3150
michael@0 3151 *aIsOverridable = false;
michael@0 3152 break;
michael@0 3153 }
michael@0 3154 case NS_THEME_RESIZER:
michael@0 3155 {
michael@0 3156 HIThemeGrowBoxDrawInfo drawInfo;
michael@0 3157 drawInfo.version = 0;
michael@0 3158 drawInfo.state = kThemeStateActive;
michael@0 3159 drawInfo.kind = kHIThemeGrowBoxKindNormal;
michael@0 3160 drawInfo.direction = kThemeGrowRight | kThemeGrowDown;
michael@0 3161 drawInfo.size = kHIThemeGrowBoxSizeNormal;
michael@0 3162 HIPoint pnt = { 0, 0 };
michael@0 3163 HIRect bounds;
michael@0 3164 HIThemeGetGrowBoxBounds(&pnt, &drawInfo, &bounds);
michael@0 3165 aResult->SizeTo(bounds.size.width, bounds.size.height);
michael@0 3166 *aIsOverridable = false;
michael@0 3167 }
michael@0 3168 }
michael@0 3169
michael@0 3170 if (IsHiDPIContext(aContext->DeviceContext())) {
michael@0 3171 *aResult = *aResult * 2;
michael@0 3172 }
michael@0 3173
michael@0 3174 return NS_OK;
michael@0 3175
michael@0 3176 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 3177 }
michael@0 3178
michael@0 3179 NS_IMETHODIMP
michael@0 3180 nsNativeThemeCocoa::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
michael@0 3181 nsIAtom* aAttribute, bool* aShouldRepaint)
michael@0 3182 {
michael@0 3183 // Some widget types just never change state.
michael@0 3184 switch (aWidgetType) {
michael@0 3185 case NS_THEME_WINDOW_TITLEBAR:
michael@0 3186 case NS_THEME_TOOLBOX:
michael@0 3187 case NS_THEME_TOOLBAR:
michael@0 3188 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
michael@0 3189 case NS_THEME_STATUSBAR:
michael@0 3190 case NS_THEME_STATUSBAR_PANEL:
michael@0 3191 case NS_THEME_STATUSBAR_RESIZER_PANEL:
michael@0 3192 case NS_THEME_TOOLTIP:
michael@0 3193 case NS_THEME_TAB_PANELS:
michael@0 3194 case NS_THEME_TAB_PANEL:
michael@0 3195 case NS_THEME_DIALOG:
michael@0 3196 case NS_THEME_MENUPOPUP:
michael@0 3197 case NS_THEME_GROUPBOX:
michael@0 3198 case NS_THEME_PROGRESSBAR_CHUNK:
michael@0 3199 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
michael@0 3200 case NS_THEME_PROGRESSBAR:
michael@0 3201 case NS_THEME_PROGRESSBAR_VERTICAL:
michael@0 3202 case NS_THEME_METERBAR:
michael@0 3203 case NS_THEME_METERBAR_CHUNK:
michael@0 3204 *aShouldRepaint = false;
michael@0 3205 return NS_OK;
michael@0 3206 }
michael@0 3207
michael@0 3208 // XXXdwh Not sure what can really be done here. Can at least guess for
michael@0 3209 // specific widgets that they're highly unlikely to have certain states.
michael@0 3210 // For example, a toolbar doesn't care about any states.
michael@0 3211 if (!aAttribute) {
michael@0 3212 // Hover/focus/active changed. Always repaint.
michael@0 3213 *aShouldRepaint = true;
michael@0 3214 } else {
michael@0 3215 // Check the attribute to see if it's relevant.
michael@0 3216 // disabled, checked, dlgtype, default, etc.
michael@0 3217 *aShouldRepaint = false;
michael@0 3218 if (aAttribute == nsGkAtoms::disabled ||
michael@0 3219 aAttribute == nsGkAtoms::checked ||
michael@0 3220 aAttribute == nsGkAtoms::selected ||
michael@0 3221 aAttribute == nsGkAtoms::menuactive ||
michael@0 3222 aAttribute == nsGkAtoms::sortDirection ||
michael@0 3223 aAttribute == nsGkAtoms::focused ||
michael@0 3224 aAttribute == nsGkAtoms::_default ||
michael@0 3225 aAttribute == nsGkAtoms::open ||
michael@0 3226 aAttribute == nsGkAtoms::hover)
michael@0 3227 *aShouldRepaint = true;
michael@0 3228 }
michael@0 3229
michael@0 3230 return NS_OK;
michael@0 3231 }
michael@0 3232
michael@0 3233 NS_IMETHODIMP
michael@0 3234 nsNativeThemeCocoa::ThemeChanged()
michael@0 3235 {
michael@0 3236 // This is unimplemented because we don't care if gecko changes its theme
michael@0 3237 // and Mac OS X doesn't have themes.
michael@0 3238 return NS_OK;
michael@0 3239 }
michael@0 3240
michael@0 3241 bool
michael@0 3242 nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
michael@0 3243 uint8_t aWidgetType)
michael@0 3244 {
michael@0 3245 // We don't have CSS set up to render non-native scrollbars on Mac OS X so we
michael@0 3246 // render natively even if native theme support is disabled.
michael@0 3247 if (aWidgetType != NS_THEME_SCROLLBAR &&
michael@0 3248 aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled())
michael@0 3249 return false;
michael@0 3250
michael@0 3251 // if this is a dropdown button in a combobox the answer is always no
michael@0 3252 if (aWidgetType == NS_THEME_DROPDOWN_BUTTON) {
michael@0 3253 nsIFrame* parentFrame = aFrame->GetParent();
michael@0 3254 if (parentFrame && (parentFrame->GetType() == nsGkAtoms::comboboxControlFrame))
michael@0 3255 return false;
michael@0 3256 }
michael@0 3257
michael@0 3258 switch (aWidgetType) {
michael@0 3259 case NS_THEME_LISTBOX:
michael@0 3260
michael@0 3261 case NS_THEME_DIALOG:
michael@0 3262 case NS_THEME_WINDOW:
michael@0 3263 case NS_THEME_WINDOW_BUTTON_BOX:
michael@0 3264 case NS_THEME_WINDOW_TITLEBAR:
michael@0 3265 case NS_THEME_MENUPOPUP:
michael@0 3266 case NS_THEME_MENUITEM:
michael@0 3267 case NS_THEME_MENUSEPARATOR:
michael@0 3268 case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON:
michael@0 3269 case NS_THEME_TOOLTIP:
michael@0 3270
michael@0 3271 case NS_THEME_CHECKBOX:
michael@0 3272 case NS_THEME_CHECKBOX_CONTAINER:
michael@0 3273 case NS_THEME_RADIO:
michael@0 3274 case NS_THEME_RADIO_CONTAINER:
michael@0 3275 case NS_THEME_GROUPBOX:
michael@0 3276 case NS_THEME_MOZ_MAC_HELP_BUTTON:
michael@0 3277 case NS_THEME_BUTTON:
michael@0 3278 case NS_THEME_BUTTON_BEVEL:
michael@0 3279 case NS_THEME_TOOLBAR_BUTTON:
michael@0 3280 case NS_THEME_SPINNER:
michael@0 3281 case NS_THEME_SPINNER_UP_BUTTON:
michael@0 3282 case NS_THEME_SPINNER_DOWN_BUTTON:
michael@0 3283 case NS_THEME_TOOLBAR:
michael@0 3284 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
michael@0 3285 case NS_THEME_STATUSBAR:
michael@0 3286 case NS_THEME_NUMBER_INPUT:
michael@0 3287 case NS_THEME_TEXTFIELD:
michael@0 3288 case NS_THEME_TEXTFIELD_MULTILINE:
michael@0 3289 case NS_THEME_SEARCHFIELD:
michael@0 3290 //case NS_THEME_TOOLBOX:
michael@0 3291 //case NS_THEME_TOOLBAR_BUTTON:
michael@0 3292 case NS_THEME_PROGRESSBAR:
michael@0 3293 case NS_THEME_PROGRESSBAR_VERTICAL:
michael@0 3294 case NS_THEME_PROGRESSBAR_CHUNK:
michael@0 3295 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
michael@0 3296 case NS_THEME_METERBAR:
michael@0 3297 case NS_THEME_METERBAR_CHUNK:
michael@0 3298 case NS_THEME_TOOLBAR_SEPARATOR:
michael@0 3299
michael@0 3300 case NS_THEME_TAB_PANELS:
michael@0 3301 case NS_THEME_TAB:
michael@0 3302
michael@0 3303 case NS_THEME_TREEVIEW_TWISTY:
michael@0 3304 case NS_THEME_TREEVIEW_TWISTY_OPEN:
michael@0 3305 case NS_THEME_TREEVIEW:
michael@0 3306 case NS_THEME_TREEVIEW_HEADER:
michael@0 3307 case NS_THEME_TREEVIEW_HEADER_CELL:
michael@0 3308 case NS_THEME_TREEVIEW_HEADER_SORTARROW:
michael@0 3309 case NS_THEME_TREEVIEW_TREEITEM:
michael@0 3310 case NS_THEME_TREEVIEW_LINE:
michael@0 3311
michael@0 3312 case NS_THEME_RANGE:
michael@0 3313
michael@0 3314 case NS_THEME_SCALE_HORIZONTAL:
michael@0 3315 case NS_THEME_SCALE_THUMB_HORIZONTAL:
michael@0 3316 case NS_THEME_SCALE_VERTICAL:
michael@0 3317 case NS_THEME_SCALE_THUMB_VERTICAL:
michael@0 3318
michael@0 3319 case NS_THEME_SCROLLBAR:
michael@0 3320 case NS_THEME_SCROLLBAR_SMALL:
michael@0 3321 case NS_THEME_SCROLLBAR_BUTTON_UP:
michael@0 3322 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
michael@0 3323 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
michael@0 3324 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
michael@0 3325 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
michael@0 3326 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
michael@0 3327 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
michael@0 3328 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
michael@0 3329 case NS_THEME_SCROLLBAR_NON_DISAPPEARING:
michael@0 3330
michael@0 3331 case NS_THEME_DROPDOWN:
michael@0 3332 case NS_THEME_DROPDOWN_BUTTON:
michael@0 3333 case NS_THEME_DROPDOWN_TEXT:
michael@0 3334 case NS_THEME_DROPDOWN_TEXTFIELD:
michael@0 3335 return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
michael@0 3336 break;
michael@0 3337
michael@0 3338 case NS_THEME_RESIZER:
michael@0 3339 {
michael@0 3340 nsIFrame* parentFrame = aFrame->GetParent();
michael@0 3341 if (!parentFrame || parentFrame->GetType() != nsGkAtoms::scrollFrame)
michael@0 3342 return true;
michael@0 3343
michael@0 3344 // Note that IsWidgetStyled is not called for resizers on Mac. This is
michael@0 3345 // because for scrollable containers, the native resizer looks better
michael@0 3346 // when (non-overlay) scrollbars are present even when the style is
michael@0 3347 // overriden, and the custom transparent resizer looks better when
michael@0 3348 // scrollbars are not present.
michael@0 3349 nsIScrollableFrame* scrollFrame = do_QueryFrame(parentFrame);
michael@0 3350 return (!nsLookAndFeel::UseOverlayScrollbars() &&
michael@0 3351 scrollFrame && scrollFrame->GetScrollbarVisibility());
michael@0 3352 break;
michael@0 3353 }
michael@0 3354 }
michael@0 3355
michael@0 3356 return false;
michael@0 3357 }
michael@0 3358
michael@0 3359 bool
michael@0 3360 nsNativeThemeCocoa::WidgetIsContainer(uint8_t aWidgetType)
michael@0 3361 {
michael@0 3362 // flesh this out at some point
michael@0 3363 switch (aWidgetType) {
michael@0 3364 case NS_THEME_DROPDOWN_BUTTON:
michael@0 3365 case NS_THEME_RADIO:
michael@0 3366 case NS_THEME_CHECKBOX:
michael@0 3367 case NS_THEME_PROGRESSBAR:
michael@0 3368 case NS_THEME_METERBAR:
michael@0 3369 case NS_THEME_RANGE:
michael@0 3370 case NS_THEME_MOZ_MAC_HELP_BUTTON:
michael@0 3371 return false;
michael@0 3372 break;
michael@0 3373 }
michael@0 3374 return true;
michael@0 3375 }
michael@0 3376
michael@0 3377 bool
michael@0 3378 nsNativeThemeCocoa::ThemeDrawsFocusForWidget(uint8_t aWidgetType)
michael@0 3379 {
michael@0 3380 if (aWidgetType == NS_THEME_DROPDOWN ||
michael@0 3381 aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD ||
michael@0 3382 aWidgetType == NS_THEME_BUTTON ||
michael@0 3383 aWidgetType == NS_THEME_MOZ_MAC_HELP_BUTTON ||
michael@0 3384 aWidgetType == NS_THEME_RADIO ||
michael@0 3385 aWidgetType == NS_THEME_RANGE ||
michael@0 3386 aWidgetType == NS_THEME_CHECKBOX)
michael@0 3387 return true;
michael@0 3388
michael@0 3389 return false;
michael@0 3390 }
michael@0 3391
michael@0 3392 bool
michael@0 3393 nsNativeThemeCocoa::ThemeNeedsComboboxDropmarker()
michael@0 3394 {
michael@0 3395 return false;
michael@0 3396 }
michael@0 3397
michael@0 3398 bool
michael@0 3399 nsNativeThemeCocoa::WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType)
michael@0 3400 {
michael@0 3401 switch (aWidgetType) {
michael@0 3402 case NS_THEME_DIALOG:
michael@0 3403 case NS_THEME_GROUPBOX:
michael@0 3404 case NS_THEME_TAB_PANELS:
michael@0 3405 case NS_THEME_MENUPOPUP:
michael@0 3406 case NS_THEME_MENUITEM:
michael@0 3407 case NS_THEME_MENUSEPARATOR:
michael@0 3408 case NS_THEME_TOOLTIP:
michael@0 3409 case NS_THEME_SPINNER:
michael@0 3410 case NS_THEME_SPINNER_UP_BUTTON:
michael@0 3411 case NS_THEME_SPINNER_DOWN_BUTTON:
michael@0 3412 case NS_THEME_TOOLBAR_SEPARATOR:
michael@0 3413 case NS_THEME_TOOLBOX:
michael@0 3414 case NS_THEME_NUMBER_INPUT:
michael@0 3415 case NS_THEME_TEXTFIELD:
michael@0 3416 case NS_THEME_TREEVIEW:
michael@0 3417 case NS_THEME_TREEVIEW_LINE:
michael@0 3418 case NS_THEME_TEXTFIELD_MULTILINE:
michael@0 3419 case NS_THEME_LISTBOX:
michael@0 3420 case NS_THEME_RESIZER:
michael@0 3421 return false;
michael@0 3422 default:
michael@0 3423 return true;
michael@0 3424 }
michael@0 3425 }
michael@0 3426
michael@0 3427 nsITheme::Transparency
michael@0 3428 nsNativeThemeCocoa::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
michael@0 3429 {
michael@0 3430 switch (aWidgetType) {
michael@0 3431 case NS_THEME_MENUPOPUP:
michael@0 3432 case NS_THEME_TOOLTIP:
michael@0 3433 return eTransparent;
michael@0 3434
michael@0 3435 case NS_THEME_SCROLLBAR_SMALL:
michael@0 3436 case NS_THEME_SCROLLBAR:
michael@0 3437 return nsLookAndFeel::UseOverlayScrollbars() ? eTransparent : eOpaque;
michael@0 3438
michael@0 3439 case NS_THEME_STATUSBAR:
michael@0 3440 // Knowing that scrollbars and statusbars are opaque improves
michael@0 3441 // performance, because we create layers for them.
michael@0 3442 return eOpaque;
michael@0 3443
michael@0 3444 case NS_THEME_TOOLBAR:
michael@0 3445 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
michael@0 3446 return eOpaque;
michael@0 3447
michael@0 3448 default:
michael@0 3449 return eUnknownTransparency;
michael@0 3450 }
michael@0 3451 }

mercurial