1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Mike Pinkerton (pinkerton@netscape.com).
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
23 * Vladimir Vukicevic <vladimir@pobox.com> (HITheme rewrite)
24 * Josh Aas <josh@mozilla.com>
25 * Colin Barrett <cbarrett@mozilla.com>
26 * Matthew Gregan <kinetik@flim.org>
27 * Markus Stange <mstange@themasta.com>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
43 #include "nsNativeThemeCocoa.h"
44 #include "nsObjCExceptions.h"
45 #include "nsIRenderingContext.h"
48 #include "nsThemeConstants.h"
49 #include "nsIPresShell.h"
50 #include "nsPresContext.h"
51 #include "nsIContent.h"
52 #include "nsIDocument.h"
55 #include "nsIEventStateManager.h"
56 #include "nsINameSpaceManager.h"
57 #include "nsPresContext.h"
58 #include "nsILookAndFeel.h"
59 #include "nsWidgetAtoms.h"
60 #include "nsToolkit.h"
61 #include "nsCocoaWindow.h"
62 #include "nsNativeThemeColors.h"
64 #include "gfxContext.h"
65 #include "gfxQuartzSurface.h"
66 #include "gfxQuartzNativeDrawing.h"
68 #define DRAW_IN_FRAME_DEBUG 0
69 #define SCROLLBARS_VISUAL_DEBUG 0
71 // private Quartz routines needed here
73 CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
76 // Workaround for NSCell control tint drawing
77 // Without this workaround, NSCells are always drawn with the clear control tint
78 // as long as they're not attached to an NSControl which is a subview of an active window.
79 // XXXmstange Why doesn't Webkit need this?
80 @implementation NSCell (ControlTintWorkaround)
81 - (int)_realControlTint { return [self controlTint]; }
84 // The purpose of this class is to provide objects that can be used when drawing
85 // NSCells using drawWithFrame:inView: without causing any harm. The only
86 // messages that will be sent to such an object are "isFlipped" and
87 // "currentEditor": isFlipped needs to return YES in order to avoid drawing bugs
88 // on 10.4 (see bug 465069); currentEditor (which isn't even a method of
89 // NSView) will be called when drawing search fields, and we only provide it in
90 // order to prevent "unrecognized selector" exceptions.
91 // There's no need to pass the actual NSView that we're drawing into to
92 // drawWithFrame:inView:. What's more, doing so even causes unnecessary
93 // invalidations as soon as we draw a focusring!
94 @interface CellDrawView : NSView
98 @implementation CellDrawView
105 - (NSText*)currentEditor
112 // Copied from nsLookAndFeel.h
113 // Apple hasn't defined a constant for scollbars with two arrows on each end, so we'll use this one.
114 static const int kThemeScrollBarArrowsBoth = 2;
116 #define HITHEME_ORIENTATION kHIThemeOrientationNormal
117 #define MAX_FOCUS_RING_WIDTH 4
119 // These enums are for indexing into the margin array.
137 static int EnumSizeForCocoaSize(NSControlSize cocoaControlSize) {
138 if (cocoaControlSize == NSMiniControlSize)
139 return miniControlSize;
140 else if (cocoaControlSize == NSSmallControlSize)
141 return smallControlSize;
143 return regularControlSize;
146 static void InflateControlRect(NSRect* rect, NSControlSize cocoaControlSize, const float marginSet[][3][4])
151 static int osIndex = leopardOS;
152 int controlSize = EnumSizeForCocoaSize(cocoaControlSize);
153 const float* buttonMargins = marginSet[osIndex][controlSize];
154 rect->origin.x -= buttonMargins[leftMargin];
155 rect->origin.y -= buttonMargins[bottomMargin];
156 rect->size.width += buttonMargins[leftMargin] + buttonMargins[rightMargin];
157 rect->size.height += buttonMargins[bottomMargin] + buttonMargins[topMargin];
160 static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
161 nsIWidget** aTopLevelWidget = NULL)
166 nsIWidget* widget = aFrame->GetWindow();
170 nsIWidget* topLevelWidget = widget->GetTopLevelWidget();
172 *aTopLevelWidget = topLevelWidget;
174 return (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW);
177 static BOOL FrameIsInActiveWindow(nsIFrame* aFrame)
179 nsIWidget* topLevelWidget = NULL;
180 NSWindow* win = NativeWindowForFrame(aFrame, &topLevelWidget);
181 if (!topLevelWidget || !win)
184 // XUL popups, e.g. the toolbar customization popup, can't become key windows,
185 // but controls in these windows should still get the active look.
186 nsWindowType windowType;
187 topLevelWidget->GetWindowType(windowType);
188 if (windowType == eWindowType_popup)
191 return [win isKeyWindow];
192 return [win isMainWindow] && ![win attachedSheet];
195 NS_IMPL_ISUPPORTS1(nsNativeThemeCocoa, nsITheme)
198 nsNativeThemeCocoa::nsNativeThemeCocoa()
200 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
202 mPushButtonCell = [[NSButtonCell alloc] initTextCell:nil];
203 [mPushButtonCell setButtonType:NSMomentaryPushInButton];
204 [mPushButtonCell setHighlightsBy:NSPushInCellMask];
206 mRadioButtonCell = [[NSButtonCell alloc] initTextCell:nil];
207 [mRadioButtonCell setButtonType:NSRadioButton];
209 mCheckboxCell = [[NSButtonCell alloc] initTextCell:nil];
210 [mCheckboxCell setButtonType:NSSwitchButton];
211 [mCheckboxCell setAllowsMixedState:YES];
213 mSearchFieldCell = [[NSSearchFieldCell alloc] initTextCell:@""];
214 [mSearchFieldCell setBezelStyle:NSTextFieldRoundedBezel];
215 [mSearchFieldCell setBezeled:YES];
216 [mSearchFieldCell setEditable:YES];
217 [mSearchFieldCell setFocusRingType:NSFocusRingTypeExterior];
219 mDropdownCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
221 mComboBoxCell = [[NSComboBoxCell alloc] initTextCell:@""];
222 [mComboBoxCell setBezeled:YES];
223 [mComboBoxCell setEditable:YES];
224 [mComboBoxCell setFocusRingType:NSFocusRingTypeExterior];
226 mCellDrawView = [[CellDrawView alloc] init];
228 NS_OBJC_END_TRY_ABORT_BLOCK;
231 nsNativeThemeCocoa::~nsNativeThemeCocoa()
233 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
235 [mPushButtonCell release];
236 [mRadioButtonCell release];
237 [mCheckboxCell release];
238 [mSearchFieldCell release];
239 [mDropdownCell release];
240 [mComboBoxCell release];
241 [mCellDrawView release];
243 NS_OBJC_END_TRY_ABORT_BLOCK;
246 // Limit on the area of the target rect (in pixels^2) in
247 // DrawCellWithScaling(), DrawButton() and DrawScrollbar(), above which we
248 // don't draw the object into a bitmap buffer. This is to avoid crashes in
249 // [NSGraphicsContext graphicsContextWithGraphicsPort:flipped:] and
250 // CGContextDrawImage(), and also to avoid very poor drawing performance in
251 // CGContextDrawImage() when it scales the bitmap (particularly if xscale or
252 // yscale is less than but near 1 -- e.g. 0.9). This value was determined
253 // by trial and error, on OS X 10.4.11 and 10.5.4, and on systems with
254 // different amounts of RAM.
255 #define BITMAP_MAX_AREA 500000
258 * Draw the given NSCell into the given cgContext.
260 * destRect - the size and position of the resulting control rectangle
261 * controlSize - the NSControlSize which will be given to the NSCell before
262 * asking it to render
263 * naturalSize - The natural dimensions of this control.
264 * If the control rect size is not equal to either of these, a scale
265 * will be applied to the context so that rendering the control at the
266 * natural size will result in it filling the destRect space.
267 * If a control has no natural dimensions in either/both axes, pass 0.0f.
268 * minimumSize - The minimum dimensions of this control.
269 * If the control rect size is less than the minimum for a given axis,
270 * a scale will be applied to the context so that the minimum is used
271 * for drawing. If a control has no minimum dimensions in either/both
273 * marginSet - an array of margins; a multidimensional array of [2][3][4],
274 * with the first dimension being the OS version (Tiger or Leopard),
275 * the second being the control size (mini, small, regular), and the third
276 * being the 4 margin values (left, top, right, bottom).
277 * view - The NSView that we're drawing into. As far as I can tell, it doesn't
278 * matter if this is really the right view; it just has to return YES when
279 * asked for isFlipped. Otherwise we'll get drawing bugs on 10.4.
280 * mirrorHorizontal - whether to mirror the cell horizontally
282 static void DrawCellWithScaling(NSCell *cell,
283 CGContextRef cgContext,
284 const HIRect& destRect,
285 NSControlSize controlSize,
288 const float marginSet[][3][4],
290 BOOL mirrorHorizontal)
292 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
294 NSRect drawRect = NSMakeRect(destRect.origin.x, destRect.origin.y, destRect.size.width, destRect.size.height);
296 if (naturalSize.width != 0.0f)
297 drawRect.size.width = naturalSize.width;
298 if (naturalSize.height != 0.0f)
299 drawRect.size.height = naturalSize.height;
301 // Keep aspect ratio when scaling if one dimension is free.
302 if (naturalSize.width == 0.0f && naturalSize.height != 0.0f)
303 drawRect.size.width = destRect.size.width * naturalSize.height / destRect.size.height;
304 if (naturalSize.height == 0.0f && naturalSize.width != 0.0f)
305 drawRect.size.height = destRect.size.height * naturalSize.width / destRect.size.width;
307 // Honor minimum sizes.
308 if (drawRect.size.width < minimumSize.width)
309 drawRect.size.width = minimumSize.width;
310 if (drawRect.size.height < minimumSize.height)
311 drawRect.size.height = minimumSize.height;
313 [NSGraphicsContext saveGraphicsState];
315 // Only skip the buffer if the area of our cell (in pixels^2) is too large.
316 if (drawRect.size.width * drawRect.size.height > BITMAP_MAX_AREA) {
317 // Inflate the rect Gecko gave us by the margin for the control.
318 InflateControlRect(&drawRect, controlSize, marginSet);
320 NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
321 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]];
323 [cell drawWithFrame:drawRect inView:view];
325 [NSGraphicsContext setCurrentContext:savedContext];
328 float w = ceil(drawRect.size.width);
329 float h = ceil(drawRect.size.height);
330 NSRect tmpRect = NSMakeRect(MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH, w, h);
332 // inflate to figure out the frame we need to tell NSCell to draw in, to get something that's 0,0,w,h
333 InflateControlRect(&tmpRect, controlSize, marginSet);
335 // and then, expand by MAX_FOCUS_RING_WIDTH size to make sure we can capture any focus ring
336 w += MAX_FOCUS_RING_WIDTH * 2.0;
337 h += MAX_FOCUS_RING_WIDTH * 2.0;
339 CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
340 CGContextRef ctx = CGBitmapContextCreate(NULL,
343 rgb, kCGImageAlphaPremultipliedFirst);
344 CGColorSpaceRelease(rgb);
346 // We need to flip the image twice in order to avoid drawing bugs on 10.4, see bug 465069.
347 // This is the first flip transform, applied to cgContext.
348 CGContextScaleCTM(cgContext, 1.0f, -1.0f);
349 CGContextTranslateCTM(cgContext, 0.0f, -(2.0 * destRect.origin.y + destRect.size.height));
350 if (mirrorHorizontal) {
351 CGContextScaleCTM(cgContext, -1.0f, 1.0f);
352 CGContextTranslateCTM(cgContext, -(2.0 * destRect.origin.x + destRect.size.width), 0.0f);
355 NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
356 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]];
358 // This is the second flip transform, applied to ctx.
359 CGContextScaleCTM(ctx, 1.0f, -1.0f);
360 CGContextTranslateCTM(ctx, 0.0f, -(2.0 * tmpRect.origin.y + tmpRect.size.height));
362 [cell drawWithFrame:tmpRect inView:view];
364 [NSGraphicsContext setCurrentContext:savedContext];
366 CGImageRef img = CGBitmapContextCreateImage(ctx);
368 // Drop the image into the original destination rectangle, scaling to fit
369 // Only scale MAX_FOCUS_RING_WIDTH by xscale/yscale when the resulting rect
370 // doesn't extend beyond the overflow rect
371 float xscale = destRect.size.width / drawRect.size.width;
372 float yscale = destRect.size.height / drawRect.size.height;
373 float scaledFocusRingX = xscale < 1.0f ? MAX_FOCUS_RING_WIDTH * xscale : MAX_FOCUS_RING_WIDTH;
374 float scaledFocusRingY = yscale < 1.0f ? MAX_FOCUS_RING_WIDTH * yscale : MAX_FOCUS_RING_WIDTH;
375 CGContextDrawImage(cgContext, CGRectMake(destRect.origin.x - scaledFocusRingX,
376 destRect.origin.y - scaledFocusRingY,
377 destRect.size.width + scaledFocusRingX * 2,
378 destRect.size.height + scaledFocusRingY * 2),
382 CGContextRelease(ctx);
385 [NSGraphicsContext restoreGraphicsState];
387 #if DRAW_IN_FRAME_DEBUG
388 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
389 CGContextFillRect(cgContext, destRect);
392 NS_OBJC_END_TRY_ABORT_BLOCK;
395 struct CellRenderSettings {
396 // The natural dimensions of the control.
397 // If a control has no natural dimensions in either/both axes, set to 0.0f.
398 NSSize naturalSizes[3];
400 // The minimum dimensions of the control.
401 // If a control has no minimum dimensions in either/both axes, set to 0.0f.
402 NSSize minimumSizes[3];
404 // A multidimensional array of [2][3][4],
405 // with the first dimension being the OS version (Tiger or Leopard),
406 // the second being the control size (mini, small, regular), and the third
407 // being the 4 margin values (left, top, right, bottom).
408 float margins[2][3][4];
412 * Draw the given NSCell into the given cgContext with a nice control size.
414 * This function is similar to DrawCellWithScaling, but it decides what
415 * control size to use based on the destRect's size.
416 * Scaling is only applied when the difference between the destRect's size
417 * and the next smaller natural size is greater than snapTolerance. Otherwise
418 * it snaps to the next smaller control size without scaling because unscaled
419 * controls look nicer.
421 static void DrawCellWithSnapping(NSCell *cell,
422 CGContextRef cgContext,
423 const HIRect& destRect,
424 const CellRenderSettings settings,
425 float verticalAlignFactor,
427 BOOL mirrorHorizontal,
428 float snapTolerance = 2.0f)
430 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
432 const float rectWidth = destRect.size.width, rectHeight = destRect.size.height;
433 const NSSize *sizes = settings.naturalSizes;
434 const NSSize miniSize = sizes[EnumSizeForCocoaSize(NSMiniControlSize)];
435 const NSSize smallSize = sizes[EnumSizeForCocoaSize(NSSmallControlSize)];
436 const NSSize regularSize = sizes[EnumSizeForCocoaSize(NSRegularControlSize)];
438 NSControlSize controlSizeX = NSRegularControlSize, controlSizeY = NSRegularControlSize;
439 HIRect drawRect = destRect;
441 if (rectWidth <= miniSize.width + snapTolerance && rectWidth < smallSize.width)
442 controlSizeX = NSMiniControlSize;
443 else if(rectWidth <= smallSize.width + snapTolerance && rectWidth < regularSize.width)
444 controlSizeX = NSSmallControlSize;
446 if (rectHeight <= miniSize.height + snapTolerance && rectHeight < smallSize.height)
447 controlSizeY = NSMiniControlSize;
448 else if(rectHeight <= smallSize.height + snapTolerance && rectHeight < regularSize.height)
449 controlSizeY = NSSmallControlSize;
451 NSControlSize controlSize = NSRegularControlSize;
454 // At some sizes, don't scale but snap.
455 const NSControlSize smallerControlSize =
456 EnumSizeForCocoaSize(controlSizeX) < EnumSizeForCocoaSize(controlSizeY) ?
457 controlSizeX : controlSizeY;
458 const int smallerControlSizeIndex = EnumSizeForCocoaSize(smallerControlSize);
459 const NSSize size = sizes[smallerControlSizeIndex];
460 float diffWidth = size.width ? rectWidth - size.width : 0.0f;
461 float diffHeight = size.height ? rectHeight - size.height : 0.0f;
462 if (diffWidth >= 0.0f && diffHeight >= 0.0f &&
463 diffWidth <= snapTolerance && diffHeight <= snapTolerance) {
464 // Snap to the smaller control size.
465 controlSize = smallerControlSize;
466 sizeIndex = smallerControlSizeIndex;
467 // Resize and center the drawRect.
468 if (sizes[sizeIndex].width) {
469 drawRect.origin.x += ceil((destRect.size.width - sizes[sizeIndex].width) / 2);
470 drawRect.size.width = sizes[sizeIndex].width;
472 if (sizes[sizeIndex].height) {
473 drawRect.origin.y += floor((destRect.size.height - sizes[sizeIndex].height) * verticalAlignFactor);
474 drawRect.size.height = sizes[sizeIndex].height;
477 // Use the larger control size.
478 controlSize = EnumSizeForCocoaSize(controlSizeX) > EnumSizeForCocoaSize(controlSizeY) ?
479 controlSizeX : controlSizeY;
480 sizeIndex = EnumSizeForCocoaSize(controlSize);
483 [cell setControlSize:controlSize];
485 NSSize minimumSize = settings.minimumSizes ? settings.minimumSizes[sizeIndex] : NSZeroSize;
486 DrawCellWithScaling(cell, cgContext, drawRect, controlSize, sizes[sizeIndex],
487 minimumSize, settings.margins, view, mirrorHorizontal);
489 NS_OBJC_END_TRY_ABORT_BLOCK;
492 static float VerticalAlignFactor(nsIFrame *aFrame)
495 return 0.5f; // default: center
497 const nsStyleCoord& va = aFrame->GetStyleTextReset()->mVerticalAlign;
498 PRUint8 intval = (va.GetUnit() == eStyleUnit_Enumerated)
500 : NS_STYLE_VERTICAL_ALIGN_MIDDLE;
502 case NS_STYLE_VERTICAL_ALIGN_TOP:
503 case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
506 case NS_STYLE_VERTICAL_ALIGN_SUB:
507 case NS_STYLE_VERTICAL_ALIGN_SUPER:
508 case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
509 case NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE:
512 case NS_STYLE_VERTICAL_ALIGN_BASELINE:
513 case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
514 case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
518 NS_NOTREACHED("invalid vertical-align");
523 // These are the sizes that Gecko needs to request to draw if it wants
524 // to get a standard-sized Aqua radio button drawn. Note that the rects
525 // that draw these are actually a little bigger.
526 static const CellRenderSettings radioSettings = {
528 NSMakeSize(11, 11), // mini
529 NSMakeSize(13, 13), // small
530 NSMakeSize(16, 16) // regular
533 NSZeroSize, NSZeroSize, NSZeroSize
537 {0, 0, 0, 0}, // mini
538 {0, 1, 1, 2}, // small
539 {0, -1, 0, 1} // regular
542 {0, 0, 0, 0}, // mini
543 {0, 1, 1, 1}, // small
544 {0, 0, 0, 0} // regular
549 static const CellRenderSettings checkboxSettings = {
551 NSMakeSize(11, 11), // mini
552 NSMakeSize(13, 13), // small
553 NSMakeSize(16, 16) // regular
556 NSZeroSize, NSZeroSize, NSZeroSize
560 {0, 1, 0, 0}, // mini
561 {0, 2, 0, 1}, // small
562 {0, 1, 0, 1} // regular
565 {0, 1, 0, 0}, // mini
566 {0, 1, 0, 1}, // small
567 {0, 1, 0, 1} // regular
573 nsNativeThemeCocoa::DrawCheckboxOrRadio(CGContextRef cgContext, PRBool inCheckbox,
574 const HIRect& inBoxRect, PRBool inSelected,
575 PRBool inDisabled, PRInt32 inState,
578 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
580 NSButtonCell *cell = inCheckbox ? mCheckboxCell : mRadioButtonCell;
581 NSCellStateValue state = inSelected ? NSOnState : NSOffState;
583 // Check if we have an indeterminate checkbox
584 if (inCheckbox && GetIndeterminate(aFrame))
585 state = NSMixedState;
587 [cell setEnabled:!inDisabled];
588 [cell setShowsFirstResponder:(inState & NS_EVENT_STATE_FOCUS)];
589 [cell setState:state];
590 [cell setHighlighted:((inState & NS_EVENT_STATE_ACTIVE) && (inState & NS_EVENT_STATE_HOVER))];
591 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
593 // Ensure that the control is square.
594 float length = PR_MIN(inBoxRect.size.width, inBoxRect.size.height);
595 HIRect drawRect = CGRectMake(inBoxRect.origin.x + (int)((inBoxRect.size.width - length) / 2.0f),
596 inBoxRect.origin.y + (int)((inBoxRect.size.height - length) / 2.0f),
599 DrawCellWithSnapping(cell, cgContext, drawRect,
600 inCheckbox ? checkboxSettings : radioSettings,
601 VerticalAlignFactor(aFrame), mCellDrawView, NO);
603 NS_OBJC_END_TRY_ABORT_BLOCK;
606 static const CellRenderSettings searchFieldSettings = {
608 NSMakeSize(0, 16), // mini
609 NSMakeSize(0, 19), // small
610 NSMakeSize(0, 22) // regular
613 NSMakeSize(32, 0), // mini
614 NSMakeSize(38, 0), // small
615 NSMakeSize(44, 0) // regular
619 {0, 0, 0, 0}, // mini
620 {0, 0, 0, 0}, // small
621 {0, 0, 0, 0} // regular
624 {0, 0, 0, 0}, // mini
625 {0, 0, 0, 0}, // small
626 {0, 0, 0, 0} // regular
632 nsNativeThemeCocoa::DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
635 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
637 NSSearchFieldCell* cell = mSearchFieldCell;
638 [cell setEnabled:!IsDisabled(aFrame)];
639 [cell setShowsFirstResponder:IsFocused(aFrame)];
641 DrawCellWithSnapping(cell, cgContext, inBoxRect, searchFieldSettings,
642 VerticalAlignFactor(aFrame), mCellDrawView,
645 NS_OBJC_END_TRY_ABORT_BLOCK;
648 static const CellRenderSettings pushButtonSettings = {
650 NSMakeSize(0, 16), // mini
651 NSMakeSize(0, 19), // small
652 NSMakeSize(0, 22) // regular
655 NSMakeSize(18, 0), // mini
656 NSMakeSize(26, 0), // small
657 NSMakeSize(30, 0) // regular
661 {1, 1, 1, 1}, // mini
662 {5, 0, 5, 2}, // small
663 {6, 0, 6, 2} // regular
666 {0, 0, 0, 0}, // mini
667 {4, 0, 4, 1}, // small
668 {5, 0, 5, 2} // regular
673 // The height at which we start doing square buttons instead of rounded buttons
674 // Rounded buttons look bad if drawn at a height greater than 26, so at that point
675 // we switch over to doing square buttons which looks fine at any size.
676 #define DO_SQUARE_BUTTON_HEIGHT 26
679 nsNativeThemeCocoa::DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect,
680 PRBool inDisabled, PRInt32 inState, nsIFrame* aFrame)
682 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
684 BOOL isActive = FrameIsInActiveWindow(aFrame);
686 [mPushButtonCell setEnabled:!inDisabled];
687 [mPushButtonCell setHighlighted:((inState & NS_EVENT_STATE_ACTIVE) &&
688 (inState & NS_EVENT_STATE_HOVER) &&
690 [mPushButtonCell setShowsFirstResponder:(inState & NS_EVENT_STATE_FOCUS) && !inDisabled && isActive];
692 // If the button is tall enough, draw the square button style so that buttons with
693 // non-standard content look good. Otherwise draw normal rounded aqua buttons.
694 if (inBoxRect.size.height > DO_SQUARE_BUTTON_HEIGHT) {
695 [mPushButtonCell setBezelStyle:NSShadowlessSquareBezelStyle];
696 DrawCellWithScaling(mPushButtonCell, cgContext, inBoxRect, NSRegularControlSize,
697 NSZeroSize, NSMakeSize(14, 0), NULL,
698 mCellDrawView, IsFrameRTL(aFrame));
700 [mPushButtonCell setBezelStyle:NSRoundedBezelStyle];
702 DrawCellWithSnapping(mPushButtonCell, cgContext, inBoxRect, pushButtonSettings,
703 0.5f, mCellDrawView, IsFrameRTL(aFrame), 1.0f);
706 #if DRAW_IN_FRAME_DEBUG
707 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
708 CGContextFillRect(cgContext, inBoxRect);
711 NS_OBJC_END_TRY_ABORT_BLOCK;
714 typedef void (*RenderHIThemeControlFunction)(CGContextRef cgContext, const HIRect& aRenderRect, void* aData);
717 RenderTransformedHIThemeControl(CGContextRef aCGContext, const HIRect& aRect,
718 RenderHIThemeControlFunction aFunc, void* aData,
719 BOOL mirrorHorizontally = NO)
721 CGAffineTransform savedCTM = CGContextGetCTM(aCGContext);
722 CGContextTranslateCTM(aCGContext, aRect.origin.x, aRect.origin.y);
725 HIRect drawRect = aRect;
726 drawRect.origin = CGPointZero;
728 if (!mirrorHorizontally && savedCTM.a == 1.0f && savedCTM.b == 0.0f &&
729 savedCTM.c == 0.0f && (savedCTM.d == 1.0f || savedCTM.d == -1.0f)) {
735 // Fall back to no bitmap buffer if the area of our control (in pixels^2)
737 if (drawDirect || (aRect.size.width * aRect.size.height > BITMAP_MAX_AREA)) {
738 aFunc(aCGContext, drawRect, aData);
740 // Inflate the buffer to capture focus rings.
741 int w = ceil(drawRect.size.width) + 2 * MAX_FOCUS_RING_WIDTH;
742 int h = ceil(drawRect.size.height) + 2 * MAX_FOCUS_RING_WIDTH;
744 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
745 CGContextRef bitmapctx = CGBitmapContextCreate(NULL, w, h, 8, w * 4,
747 kCGImageAlphaPremultipliedFirst);
748 CGColorSpaceRelease(colorSpace);
750 CGContextTranslateCTM(bitmapctx, MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH);
752 // HITheme always wants to draw into a flipped context, or things
754 CGContextTranslateCTM(bitmapctx, 0.0f, aRect.size.height);
755 CGContextScaleCTM(bitmapctx, 1.0f, -1.0f);
757 aFunc(bitmapctx, drawRect, aData);
759 CGImageRef bitmap = CGBitmapContextCreateImage(bitmapctx);
761 CGAffineTransform ctm = CGContextGetCTM(aCGContext);
763 // We need to unflip, so that we can do a DrawImage without getting a flipped image.
764 CGContextTranslateCTM(aCGContext, 0.0f, aRect.size.height);
765 CGContextScaleCTM(aCGContext, 1.0f, -1.0f);
767 if (mirrorHorizontally) {
768 CGContextTranslateCTM(aCGContext, aRect.size.width, 0);
769 CGContextScaleCTM(aCGContext, -1.0f, 1.0f);
772 HIRect inflatedDrawRect = CGRectMake(-MAX_FOCUS_RING_WIDTH, -MAX_FOCUS_RING_WIDTH, w, h);
773 CGContextDrawImage(aCGContext, inflatedDrawRect, bitmap);
775 CGContextSetCTM(aCGContext, ctm);
777 CGImageRelease(bitmap);
778 CGContextRelease(bitmapctx);
781 CGContextSetCTM(aCGContext, savedCTM);
785 RenderButton(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
787 HIThemeButtonDrawInfo* bdi = (HIThemeButtonDrawInfo*)aData;
788 HIThemeDrawButton(&aRenderRect, bdi, cgContext, kHIThemeOrientationNormal, NULL);
792 nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, ThemeButtonKind inKind,
793 const HIRect& inBoxRect, PRBool inIsDefault, PRBool inDisabled,
794 ThemeButtonValue inValue, ThemeButtonAdornment inAdornment,
795 PRInt32 inState, nsIFrame* aFrame)
797 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
799 BOOL isActive = FrameIsInActiveWindow(aFrame);
801 HIThemeButtonDrawInfo bdi;
805 bdi.adornment = inAdornment;
808 bdi.state = kThemeStateUnavailable;
810 else if ((inState & NS_EVENT_STATE_ACTIVE) && (inState & NS_EVENT_STATE_HOVER)) {
811 bdi.state = kThemeStatePressed;
814 if (inKind == kThemeArrowButton)
815 bdi.state = kThemeStateUnavailable; // these are always drawn as unavailable
816 else if (!isActive && inKind == kThemeListHeaderButton)
817 bdi.state = kThemeStateInactive;
819 bdi.state = kThemeStateActive;
822 if (inState & NS_EVENT_STATE_FOCUS && isActive)
823 bdi.adornment |= kThemeAdornmentFocus;
825 if (inIsDefault && !inDisabled && isActive && !(inState & NS_EVENT_STATE_ACTIVE)) {
826 bdi.adornment |= kThemeAdornmentDefault;
827 bdi.animation.time.start = 0;
828 bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
831 HIRect drawFrame = inBoxRect;
833 if (inKind == kThemePushButton) {
834 drawFrame.size.height -= 2;
835 if (inBoxRect.size.height < pushButtonSettings.naturalSizes[smallControlSize].height) {
836 bdi.kind = kThemePushButtonMini;
838 else if (inBoxRect.size.height < pushButtonSettings.naturalSizes[regularControlSize].height) {
839 bdi.kind = kThemePushButtonSmall;
840 drawFrame.origin.y -= 1;
841 drawFrame.origin.x += 1;
842 drawFrame.size.width -= 2;
845 else if (inKind == kThemeListHeaderButton) {
846 CGContextClipToRect(cgContext, inBoxRect);
847 // Always remove the top border.
848 drawFrame.origin.y -= 1;
849 drawFrame.size.height += 1;
850 // Remove the left border in LTR mode and the right border in RTL mode.
851 drawFrame.size.width += 1;
852 PRBool isLast = IsLastTreeHeaderCell(aFrame);
854 drawFrame.size.width += 1; // Also remove the other border.
855 if (!IsFrameRTL(aFrame) || isLast)
856 drawFrame.origin.x -= 1;
859 RenderTransformedHIThemeControl(cgContext, drawFrame, RenderButton, &bdi,
862 #if DRAW_IN_FRAME_DEBUG
863 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
864 CGContextFillRect(cgContext, inBoxRect);
867 NS_OBJC_END_TRY_ABORT_BLOCK;
870 static const CellRenderSettings dropdownSettings = {
872 NSMakeSize(0, 16), // mini
873 NSMakeSize(0, 19), // small
874 NSMakeSize(0, 22) // regular
877 NSMakeSize(18, 0), // mini
878 NSMakeSize(38, 0), // small
879 NSMakeSize(44, 0) // regular
883 {1, 1, 2, 1}, // mini
884 {3, 0, 3, 1}, // small
885 {3, 0, 3, 0} // regular
888 {1, 1, 2, 1}, // mini
889 {3, 0, 3, 1}, // small
890 {3, 0, 3, 0} // regular
895 static const CellRenderSettings editableMenulistSettings = {
897 NSMakeSize(0, 15), // mini
898 NSMakeSize(0, 18), // small
899 NSMakeSize(0, 21) // regular
902 NSMakeSize(18, 0), // mini
903 NSMakeSize(38, 0), // small
904 NSMakeSize(44, 0) // regular
908 {0, 0, 2, 2}, // mini
909 {0, 0, 3, 2}, // small
910 {0, 1, 3, 3} // regular
913 {0, 0, 2, 2}, // mini
914 {0, 0, 3, 2}, // small
915 {0, 1, 3, 3} // regular
921 nsNativeThemeCocoa::DrawDropdown(CGContextRef cgContext, const HIRect& inBoxRect,
922 PRInt32 inState, PRUint8 aWidgetType, nsIFrame* aFrame)
924 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
926 [mDropdownCell setPullsDown:(aWidgetType == NS_THEME_BUTTON)];
928 BOOL isEditable = (aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD);
929 NSCell* cell = isEditable ? (NSCell*)mComboBoxCell : (NSCell*)mDropdownCell;
931 [cell setEnabled:!IsDisabled(aFrame)];
932 [cell setShowsFirstResponder:(IsFocused(aFrame) || (inState & NS_EVENT_STATE_FOCUS))];
933 [cell setHighlighted:IsOpenButton(aFrame)];
934 [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
936 const CellRenderSettings& settings = isEditable ? editableMenulistSettings : dropdownSettings;
937 DrawCellWithSnapping(cell, cgContext, inBoxRect, settings,
938 0.5f, mCellDrawView, IsFrameRTL(aFrame));
940 NS_OBJC_END_TRY_ABORT_BLOCK;
944 nsNativeThemeCocoa::DrawSpinButtons(CGContextRef cgContext, ThemeButtonKind inKind,
945 const HIRect& inBoxRect, PRBool inDisabled,
946 ThemeDrawState inDrawState,
947 ThemeButtonAdornment inAdornment,
948 PRInt32 inState, nsIFrame* aFrame)
950 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
952 HIThemeButtonDrawInfo bdi;
955 bdi.value = kThemeButtonOff;
956 bdi.adornment = inAdornment;
959 bdi.state = kThemeStateUnavailable;
961 bdi.state = FrameIsInActiveWindow(aFrame) ? inDrawState : kThemeStateActive;
963 HIThemeDrawButton(&inBoxRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
965 NS_OBJC_END_TRY_ABORT_BLOCK;
969 nsNativeThemeCocoa::DrawFrame(CGContextRef cgContext, HIThemeFrameKind inKind,
970 const HIRect& inBoxRect, PRBool inIsDisabled, PRInt32 inState)
972 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
974 HIThemeFrameDrawInfo fdi;
978 // We don't ever set an inactive state for this because it doesn't
979 // look right (see other apps).
980 fdi.state = inIsDisabled ? kThemeStateUnavailable : kThemeStateActive;
982 // for some reason focus rings on listboxes draw incorrectly
983 if (inKind == kHIThemeFrameListBox)
986 fdi.isFocused = (inState & NS_EVENT_STATE_FOCUS) != 0;
988 // HIThemeDrawFrame takes the rect for the content area of the frame, not
989 // the bounding rect for the frame. Here we reduce the size of the rect we
990 // will pass to make it the size of the content.
991 HIRect drawRect = inBoxRect;
992 if (inKind == kHIThemeFrameTextFieldSquare) {
993 SInt32 frameOutset = 0;
994 ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
995 drawRect.origin.x += frameOutset;
996 drawRect.origin.y += frameOutset;
997 drawRect.size.width -= frameOutset * 2;
998 drawRect.size.height -= frameOutset * 2;
1000 else if (inKind == kHIThemeFrameListBox) {
1001 SInt32 frameOutset = 0;
1002 ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
1003 drawRect.origin.x += frameOutset;
1004 drawRect.origin.y += frameOutset;
1005 drawRect.size.width -= frameOutset * 2;
1006 drawRect.size.height -= frameOutset * 2;
1009 #if DRAW_IN_FRAME_DEBUG
1010 CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
1011 CGContextFillRect(cgContext, inBoxRect);
1014 HIThemeDrawFrame(&drawRect, &fdi, cgContext, HITHEME_ORIENTATION);
1016 NS_OBJC_END_TRY_ABORT_BLOCK;
1020 nsNativeThemeCocoa::DrawProgress(CGContextRef cgContext, const HIRect& inBoxRect,
1021 PRBool inIsIndeterminate, PRBool inIsHorizontal,
1022 PRInt32 inValue, PRInt32 inMaxValue,
1025 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1027 HIThemeTrackDrawInfo tdi;
1029 PRInt32 stepsPerSecond = inIsIndeterminate ? 60 : 30;
1030 PRInt32 milliSecondsPerStep = 1000 / stepsPerSecond;
1033 tdi.kind = inIsIndeterminate ? kThemeMediumIndeterminateBar: kThemeMediumProgressBar;
1034 tdi.bounds = inBoxRect;
1036 tdi.max = inMaxValue;
1037 tdi.value = inValue;
1038 tdi.attributes = inIsHorizontal ? kThemeTrackHorizontal : 0;
1039 tdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
1040 tdi.trackInfo.progress.phase = PR_IntervalToMilliseconds(PR_IntervalNow()) /
1041 milliSecondsPerStep % 16;
1043 HIThemeDrawTrack(&tdi, NULL, cgContext, HITHEME_ORIENTATION);
1045 NS_OBJC_END_TRY_ABORT_BLOCK;
1049 nsNativeThemeCocoa::DrawTabPanel(CGContextRef cgContext, const HIRect& inBoxRect,
1052 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1054 HIThemeTabPaneDrawInfo tpdi;
1057 tpdi.state = FrameIsInActiveWindow(aFrame) ? kThemeStateActive : kThemeStateInactive;
1058 tpdi.direction = kThemeTabNorth;
1059 tpdi.size = kHIThemeTabSizeNormal;
1060 tpdi.kind = kHIThemeTabKindNormal;
1062 HIThemeDrawTabPane(&inBoxRect, &tpdi, cgContext, HITHEME_ORIENTATION);
1064 NS_OBJC_END_TRY_ABORT_BLOCK;
1068 nsNativeThemeCocoa::DrawScale(CGContextRef cgContext, const HIRect& inBoxRect,
1069 PRBool inIsDisabled, PRInt32 inState,
1070 PRBool inIsVertical, PRBool inIsReverse,
1071 PRInt32 inCurrentValue, PRInt32 inMinValue,
1072 PRInt32 inMaxValue, nsIFrame* aFrame)
1074 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1076 HIThemeTrackDrawInfo tdi;
1079 tdi.kind = kThemeMediumSlider;
1080 tdi.bounds = inBoxRect;
1081 tdi.min = inMinValue;
1082 tdi.max = inMaxValue;
1083 tdi.value = inCurrentValue;
1084 tdi.attributes = kThemeTrackShowThumb;
1086 tdi.attributes |= kThemeTrackHorizontal;
1088 tdi.attributes |= kThemeTrackRightToLeft;
1089 if (inState & NS_EVENT_STATE_FOCUS)
1090 tdi.attributes |= kThemeTrackHasFocus;
1092 tdi.enableState = kThemeTrackDisabled;
1094 tdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
1095 tdi.trackInfo.slider.thumbDir = kThemeThumbPlain;
1096 tdi.trackInfo.slider.pressState = 0;
1098 HIThemeDrawTrack(&tdi, NULL, cgContext, HITHEME_ORIENTATION);
1100 NS_OBJC_END_TRY_ABORT_BLOCK;
1103 #define NATURAL_MINI_TAB_BUTTON_HEIGHT 17
1104 #define NATURAL_SMALL_TAB_BUTTON_HEIGHT 20
1105 #define NATURAL_REGULAR_TAB_BUTTON_HEIGHT 23
1108 nsNativeThemeCocoa::DrawTab(CGContextRef cgContext, HIRect inBoxRect,
1109 PRInt32 inState, nsIFrame* aFrame)
1111 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1113 HIThemeTabDrawInfo tdi;
1115 tdi.kind = kHIThemeTabKindNormal;
1117 PRBool isSelected = IsSelectedTab(aFrame);
1118 PRBool isDisabled = IsDisabled(aFrame);
1121 tdi.style = kThemeTabFrontUnavailable;
1123 tdi.style = FrameIsInActiveWindow(aFrame) ? kThemeTabFront : kThemeTabFrontInactive;
1126 tdi.style = kThemeTabNonFrontUnavailable;
1127 else if ((inState & NS_EVENT_STATE_ACTIVE) && (inState & NS_EVENT_STATE_HOVER))
1128 tdi.style = kThemeTabNonFrontPressed;
1130 tdi.style = FrameIsInActiveWindow(aFrame) ? kThemeTabNonFront : kThemeTabNonFrontInactive;
1133 tdi.direction = kThemeTabNorth;
1134 tdi.size = kHIThemeTabSizeNormal;
1135 if (inBoxRect.size.height < NATURAL_REGULAR_TAB_BUTTON_HEIGHT)
1136 tdi.size = kHIThemeTabSizeSmall;
1137 if (inBoxRect.size.height < NATURAL_SMALL_TAB_BUTTON_HEIGHT)
1138 tdi.size = kHIThemeTabSizeMini;
1140 PRBool isRTL = IsFrameRTL(aFrame);
1141 PRBool isFirst = isRTL ? IsLastTab(aFrame) : IsFirstTab(aFrame);
1142 PRBool isLast = isRTL ? IsFirstTab(aFrame) : IsLastTab(aFrame);
1144 if (isFirst && isLast)
1145 tdi.position = kHIThemeTabPositionOnly;
1147 tdi.position = kHIThemeTabPositionFirst;
1149 tdi.position = kHIThemeTabPositionLast;
1151 tdi.position = kHIThemeTabPositionMiddle;
1153 // Tab separator management:
1154 // Normal tabs only draw their left separator, in the leftmost pixel row of
1155 // their frame. Selected tabs additionally draw their right separator, outside
1156 // of their frame. To prevent overlapping, the tab to the right of the
1157 // selected tab shouldn't draw its left separator.
1158 tdi.adornment = kHIThemeTabAdornmentNone;
1159 if (isRTL ? IsBeforeSelectedTab(aFrame) : IsAfterSelectedTab(aFrame)) {
1160 // On Leopard, the tab's left edge must be shifted 1px to the right.
1161 // On Tiger, this happens automatically when no leading separator is drawn.
1162 inBoxRect.origin.x += 1;
1163 inBoxRect.size.width -= 1;
1166 tdi.adornment = kHIThemeTabAdornmentLeadingSeparator;
1169 if (isSelected && !isLast) {
1170 tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
1171 // On Tiger, the right separator is drawn outside of the frame.
1172 // On Leopard, the right edge must be shifted 1px to the right.
1173 inBoxRect.size.width += 1;
1176 if (inState & NS_EVENT_STATE_FOCUS)
1177 tdi.adornment |= kThemeAdornmentFocus;
1179 HIThemeDrawTab(&inBoxRect, &tdi, cgContext, HITHEME_ORIENTATION, NULL);
1181 NS_OBJC_END_TRY_ABORT_BLOCK;
1185 ConvertToPressState(PRInt32 aButtonState, UInt8 aPressState)
1187 // If the button is pressed, return the press state passed in. Otherwise, return 0.
1188 return ((aButtonState & NS_EVENT_STATE_ACTIVE) && (aButtonState & NS_EVENT_STATE_HOVER)) ? aPressState : 0;
1192 nsNativeThemeCocoa::GetScrollbarPressStates(nsIFrame *aFrame, PRInt32 aButtonStates[])
1194 static nsIContent::AttrValuesArray attributeValues[] = {
1195 &nsWidgetAtoms::scrollbarUpTop,
1196 &nsWidgetAtoms::scrollbarDownTop,
1197 &nsWidgetAtoms::scrollbarUpBottom,
1198 &nsWidgetAtoms::scrollbarDownBottom,
1202 // Get the state of any scrollbar buttons in our child frames
1203 for (nsIFrame *childFrame = aFrame->GetFirstChild(nsnull);
1205 childFrame = childFrame->GetNextSibling()) {
1207 nsIContent *childContent = childFrame->GetContent();
1208 if (!childContent) continue;
1209 PRInt32 attrIndex = childContent->FindAttrValueIn(kNameSpaceID_None, nsWidgetAtoms::sbattr,
1210 attributeValues, eCaseMatters);
1211 if (attrIndex < 0) continue;
1213 PRInt32 currentState = GetContentState(childFrame, NS_THEME_BUTTON);
1214 aButtonStates[attrIndex] = currentState;
1218 // Both of the following sets of numbers were derived by loading the testcase in
1219 // bmo bug 380185 in Safari and observing its behavior for various heights of scrollbar.
1220 // These magic numbers are the minimum sizes we can draw a scrollbar and still
1221 // have room for everything to display, including the thumb
1222 #define MIN_SCROLLBAR_SIZE_WITH_THUMB 61
1223 #define MIN_SMALL_SCROLLBAR_SIZE_WITH_THUMB 49
1224 // And these are the minimum sizes if we don't draw the thumb
1225 #define MIN_SCROLLBAR_SIZE 56
1226 #define MIN_SMALL_SCROLLBAR_SIZE 46
1229 nsNativeThemeCocoa::GetScrollbarDrawInfo(HIThemeTrackDrawInfo& aTdi, nsIFrame *aFrame,
1230 const CGSize& aSize, PRBool aShouldGetButtonStates)
1232 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1234 PRInt32 curpos = CheckIntAttr(aFrame, nsWidgetAtoms::curpos, 0);
1235 PRInt32 minpos = CheckIntAttr(aFrame, nsWidgetAtoms::minpos, 0);
1236 PRInt32 maxpos = CheckIntAttr(aFrame, nsWidgetAtoms::maxpos, 100);
1237 PRInt32 thumbSize = CheckIntAttr(aFrame, nsWidgetAtoms::pageincrement, 10);
1239 PRBool isHorizontal = aFrame->GetContent()->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::orient,
1240 nsWidgetAtoms::horizontal, eCaseMatters);
1241 PRBool isSmall = aFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL;
1244 aTdi.kind = isSmall ? kThemeSmallScrollBar : kThemeMediumScrollBar;
1245 aTdi.bounds.origin = CGPointZero;
1246 aTdi.bounds.size = aSize;
1249 aTdi.value = curpos;
1250 aTdi.attributes = 0;
1251 aTdi.enableState = kThemeTrackActive;
1253 aTdi.attributes |= kThemeTrackHorizontal;
1255 aTdi.trackInfo.scrollbar.viewsize = (SInt32)thumbSize;
1257 // This should be done early on so things like "kThemeTrackNothingToScroll" can
1258 // override the active enable state.
1259 aTdi.enableState = FrameIsInActiveWindow(aFrame) ? kThemeTrackActive : kThemeTrackInactive;
1261 /* Only display features if we have enough room for them.
1262 * Gecko still maintains the scrollbar info; this is just a visual issue (bug 380185).
1264 PRInt32 longSideLength = (PRInt32)(isHorizontal ? (aSize.width) : (aSize.height));
1265 if (longSideLength >= (isSmall ? MIN_SMALL_SCROLLBAR_SIZE_WITH_THUMB : MIN_SCROLLBAR_SIZE_WITH_THUMB)) {
1266 aTdi.attributes |= kThemeTrackShowThumb;
1268 else if (longSideLength < (isSmall ? MIN_SMALL_SCROLLBAR_SIZE : MIN_SCROLLBAR_SIZE)) {
1269 aTdi.enableState = kThemeTrackNothingToScroll;
1273 aTdi.trackInfo.scrollbar.pressState = 0;
1275 // Only go get these scrollbar button states if we need it. For example, there's no reaon to look up scrollbar button
1276 // states when we're only creating a TrackDrawInfo to determine the size of the thumb.
1277 if (aShouldGetButtonStates) {
1278 PRInt32 buttonStates[] = {0, 0, 0, 0};
1279 GetScrollbarPressStates(aFrame, buttonStates);
1280 NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
1281 // It seems that unless all four buttons are showing, kThemeTopOutsideArrowPressed is the correct constant for
1282 // the up scrollbar button.
1283 if ([buttonPlacement isEqualToString:@"DoubleBoth"]) {
1284 aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
1285 ConvertToPressState(buttonStates[1], kThemeTopInsideArrowPressed) |
1286 ConvertToPressState(buttonStates[2], kThemeBottomInsideArrowPressed) |
1287 ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
1289 aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
1290 ConvertToPressState(buttonStates[1], kThemeBottomOutsideArrowPressed) |
1291 ConvertToPressState(buttonStates[2], kThemeTopOutsideArrowPressed) |
1292 ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
1296 NS_OBJC_END_TRY_ABORT_BLOCK;
1300 RenderScrollbar(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
1302 HIThemeTrackDrawInfo* tdi = (HIThemeTrackDrawInfo*)aData;
1303 HIThemeDrawTrack(tdi, NULL, cgContext, HITHEME_ORIENTATION);
1307 nsNativeThemeCocoa::DrawScrollbar(CGContextRef aCGContext, const HIRect& aBoxRect, nsIFrame *aFrame)
1309 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1311 HIThemeTrackDrawInfo tdi;
1312 GetScrollbarDrawInfo(tdi, aFrame, aBoxRect.size, PR_TRUE); // True means we want the press states
1313 RenderTransformedHIThemeControl(aCGContext, aBoxRect, RenderScrollbar, &tdi);
1315 NS_OBJC_END_TRY_ABORT_BLOCK;
1319 nsNativeThemeCocoa::GetParentScrollbarFrame(nsIFrame *aFrame)
1321 // Walk our parents to find a scrollbar frame
1322 nsIFrame *scrollbarFrame = aFrame;
1324 if (scrollbarFrame->GetType() == nsWidgetAtoms::scrollbarFrame) break;
1325 } while ((scrollbarFrame = scrollbarFrame->GetParent()));
1327 // We return null if we can't find a parent scrollbar frame
1328 return scrollbarFrame;
1331 static BOOL DrawingAtWindowTop(CGContextRef cgContext, float viewHeight, float yPos)
1333 // Ignore all non-trivial transforms.
1334 CGAffineTransform ctm = CGContextGetCTM(cgContext);
1335 if (ctm.a != 1.0f || ctm.b != 0.0f || ctm.c != 0.0f || ctm.d != -1.0f)
1338 // ctm.ty contains the vertical offset from the window's bottom edge.
1339 return ctm.ty - yPos >= viewHeight;
1343 ToolbarCanBeUnified(CGContextRef cgContext, const HIRect& inBoxRect, NSWindow* aWindow)
1345 return [aWindow isKindOfClass:[ToolbarWindow class]] &&
1346 ![(ToolbarWindow*)aWindow drawsContentsIntoWindowFrame] &&
1347 DrawingAtWindowTop(cgContext, [[aWindow contentView] bounds].size.height,
1348 inBoxRect.origin.y);
1352 nsNativeThemeCocoa::DrawUnifiedToolbar(CGContextRef cgContext, const HIRect& inBoxRect,
1355 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1357 float titlebarHeight = 0;
1359 if (ToolbarCanBeUnified(cgContext, inBoxRect, aWindow)) {
1360 // Consider the titlebar height when calculating the gradient.
1361 titlebarHeight = [(ToolbarWindow*)aWindow titlebarHeight];
1362 // Notify the window about the toolbar's height so that it can draw the
1363 // correct gradient in the titlebar.
1364 [(ToolbarWindow*)aWindow setUnifiedToolbarHeight:inBoxRect.size.height];
1367 BOOL isMain = [aWindow isMainWindow] || ![NSView focusView];
1369 // Draw the gradient
1370 UnifiedGradientInfo info = { titlebarHeight, inBoxRect.size.height, isMain, NO };
1371 struct CGFunctionCallbacks callbacks = { 0, nsCocoaWindow::UnifiedShading, NULL };
1372 CGFunctionRef function = CGFunctionCreate(&info, 1, NULL, 4, NULL, &callbacks);
1373 float srcY = inBoxRect.origin.y;
1374 float dstY = srcY + inBoxRect.size.height - 1;
1375 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
1376 CGShadingRef shading = CGShadingCreateAxial(colorSpace,
1377 CGPointMake(0, srcY),
1378 CGPointMake(0, dstY), function,
1380 CGColorSpaceRelease(colorSpace);
1381 CGFunctionRelease(function);
1382 CGContextClipToRect(cgContext, inBoxRect);
1383 CGContextDrawShading(cgContext, shading);
1384 CGShadingRelease(shading);
1386 // Draw the border at the bottom of the toolbar.
1387 CGRect borderRect = CGRectMake(inBoxRect.origin.x, inBoxRect.origin.y +
1388 inBoxRect.size.height - 1.0f,
1389 inBoxRect.size.width, 1.0f);
1390 DrawNativeGreyColorInRect(cgContext, headerBorderGrey, borderRect, isMain);
1392 NS_OBJC_END_TRY_ABORT_BLOCK;
1395 struct GreyGradientInfo {
1400 static void GreyGradientCallback(void* aInfo, const CGFloat* aIn, CGFloat* aOut)
1402 GreyGradientInfo* info = static_cast<GreyGradientInfo*>(aInfo);
1403 CGFloat result = (1.0f - *aIn) * info->startGrey + *aIn * info->endGrey;
1410 static void DrawGreyGradient(CGContextRef cgContext, const HIRect& rect,
1411 float startGrey, float endGrey)
1413 if (rect.size.height <= 0.0f)
1416 GreyGradientInfo info = { startGrey, endGrey };
1417 struct CGFunctionCallbacks callbacks = { 0, GreyGradientCallback, NULL };
1418 CGFunctionRef function = CGFunctionCreate(&info, 1, NULL, 4, NULL, &callbacks);
1419 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
1420 CGShadingRef shading = CGShadingCreateAxial(colorSpace,
1421 CGPointMake(0, CGRectGetMinY(rect)),
1422 CGPointMake(0, CGRectGetMaxY(rect)),
1423 function, false, false);
1424 CGColorSpaceRelease(colorSpace);
1425 CGFunctionRelease(function);
1426 CGContextSaveGState(cgContext);
1427 CGContextClipToRect(cgContext, rect);
1428 CGContextDrawShading(cgContext, shading);
1429 CGContextRestoreGState(cgContext);
1430 CGShadingRelease(shading);
1434 nsNativeThemeCocoa::DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect,
1437 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1439 if (inBoxRect.size.height < 2.0f)
1442 BOOL isMain = [NativeWindowForFrame(aFrame) isMainWindow] || ![NSView focusView];
1444 // Draw the borders at the top of the statusbar.
1445 CGRect rect = CGRectMake(inBoxRect.origin.x, inBoxRect.origin.y,
1446 inBoxRect.size.width, 1.0f);
1447 DrawNativeGreyColorInRect(cgContext, statusbarFirstTopBorderGrey, rect, isMain);
1448 rect.origin.y += 1.0f;
1449 DrawNativeGreyColorInRect(cgContext, statusbarSecondTopBorderGrey, rect, isMain);
1451 // Draw the gradient.
1452 DrawGreyGradient(cgContext, CGRectMake(inBoxRect.origin.x, inBoxRect.origin.y + 2.0f,
1453 inBoxRect.size.width, inBoxRect.size.height - 2.0f),
1454 NativeGreyColorAsFloat(statusbarGradientStartGrey, isMain),
1455 NativeGreyColorAsFloat(statusbarGradientEndGrey, isMain));
1457 NS_OBJC_END_TRY_ABORT_BLOCK;
1461 RenderResizer(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
1463 HIThemeGrowBoxDrawInfo* drawInfo = (HIThemeGrowBoxDrawInfo*)aData;
1464 HIThemeDrawGrowBox(&CGPointZero, drawInfo, cgContext, kHIThemeOrientationNormal);
1468 nsNativeThemeCocoa::DrawResizer(CGContextRef cgContext, const HIRect& aRect,
1471 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
1473 HIThemeGrowBoxDrawInfo drawInfo;
1474 drawInfo.version = 0;
1475 drawInfo.state = kThemeStateActive;
1476 drawInfo.kind = kHIThemeGrowBoxKindNormal;
1477 drawInfo.direction = kThemeGrowRight | kThemeGrowDown;
1478 drawInfo.size = kHIThemeGrowBoxSizeNormal;
1480 RenderTransformedHIThemeControl(cgContext, aRect, RenderResizer, &drawInfo,
1481 IsFrameRTL(aFrame));
1483 NS_OBJC_END_TRY_ABORT_BLOCK;
1487 nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame,
1488 PRUint8 aWidgetType, const nsRect& aRect,
1489 const nsRect& aDirtyRect)
1491 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1493 // setup to draw into the correct port
1494 nsCOMPtr<nsIDeviceContext> dctx;
1495 aContext->GetDeviceContext(*getter_AddRefs(dctx));
1496 PRInt32 p2a = dctx->AppUnitsPerDevPixel();
1498 gfxRect nativeDirtyRect(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
1499 gfxRect nativeWidgetRect(aRect.x, aRect.y, aRect.width, aRect.height);
1500 nativeWidgetRect.ScaleInverse(gfxFloat(p2a));
1501 nativeDirtyRect.ScaleInverse(gfxFloat(p2a));
1502 nativeWidgetRect.Round();
1503 if (nativeWidgetRect.IsEmpty())
1504 return NS_OK; // Don't attempt to draw invisible widgets.
1506 nsRefPtr<gfxContext> thebesCtx = aContext->ThebesContext();
1508 return NS_ERROR_FAILURE;
1510 gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect);
1512 CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
1513 if (cgContext == nsnull) {
1514 // The Quartz surface handles 0x0 surfaces by internally
1515 // making all operations no-ops; there's no cgcontext created for them.
1516 // Unfortunately, this means that callers that want to render
1517 // directly to the CGContext need to be aware of this quirk.
1522 if (1 /*aWidgetType == NS_THEME_TEXTFIELD*/) {
1523 fprintf(stderr, "Native theme drawing widget %d [%p] dis:%d in rect [%d %d %d %d]\n",
1524 aWidgetType, aFrame, IsDisabled(aFrame), aRect.x, aRect.y, aRect.width, aRect.height);
1525 fprintf(stderr, "Cairo matrix: [%f %f %f %f %f %f]\n",
1526 mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0);
1527 fprintf(stderr, "Native theme xform[0]: [%f %f %f %f %f %f]\n",
1528 mm0.a, mm0.b, mm0.c, mm0.d, mm0.tx, mm0.ty);
1529 CGAffineTransform mm = CGContextGetCTM(cgContext);
1530 fprintf(stderr, "Native theme xform[1]: [%f %f %f %f %f %f]\n",
1531 mm.a, mm.b, mm.c, mm.d, mm.tx, mm.ty);
1535 CGRect macRect = CGRectMake(nativeWidgetRect.X(), nativeWidgetRect.Y(),
1536 nativeWidgetRect.Width(), nativeWidgetRect.Height());
1539 fprintf(stderr, " --> macRect %f %f %f %f\n",
1540 macRect.origin.x, macRect.origin.y, macRect.size.width, macRect.size.height);
1541 CGRect bounds = CGContextGetClipBoundingBox(cgContext);
1542 fprintf(stderr, " --> clip bounds: %f %f %f %f\n",
1543 bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
1545 //CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 1.0, 0.1);
1546 //CGContextFillRect(cgContext, bounds);
1549 PRInt32 eventState = GetContentState(aFrame, aWidgetType);
1551 switch (aWidgetType) {
1552 case NS_THEME_DIALOG: {
1553 HIThemeSetFill(kThemeBrushDialogBackgroundActive, NULL, cgContext, HITHEME_ORIENTATION);
1554 CGContextFillRect(cgContext, macRect);
1558 case NS_THEME_MENUPOPUP: {
1559 HIThemeMenuDrawInfo mdi = {
1561 menuType: IsDisabled(aFrame) ? kThemeMenuTypeInactive : kThemeMenuTypePopUp
1564 PRBool isLeftOfParent = PR_FALSE;
1565 if (IsSubmenu(aFrame, &isLeftOfParent) && !isLeftOfParent) {
1566 mdi.menuType = kThemeMenuTypeHierarchical;
1569 // The rounded corners draw outside the frame.
1570 CGRect deflatedRect = CGRectMake(macRect.origin.x, macRect.origin.y + 4,
1571 macRect.size.width, macRect.size.height - 8);
1572 HIThemeDrawMenuBackground(&deflatedRect, &mdi, cgContext, HITHEME_ORIENTATION);
1576 case NS_THEME_MENUITEM: {
1577 // Clear the background to get correct transparency.
1578 CGContextClearRect(cgContext, macRect);
1580 // maybe use kThemeMenuItemHierBackground or PopUpBackground instead of just Plain?
1581 HIThemeMenuItemDrawInfo drawInfo = {
1583 itemType: kThemeMenuItemPlain,
1584 state: (IsDisabled(aFrame) ? kThemeMenuDisabled :
1585 CheckBooleanAttr(aFrame, nsWidgetAtoms::mozmenuactive) ? kThemeMenuSelected :
1589 // XXX pass in the menu rect instead of always using the item rect
1591 HIThemeDrawMenuItem(&macRect, &macRect, &drawInfo, cgContext, HITHEME_ORIENTATION, &ignored);
1595 case NS_THEME_MENUSEPARATOR: {
1596 ThemeMenuState menuState;
1597 if (IsDisabled(aFrame)) {
1598 menuState = kThemeMenuDisabled;
1601 menuState = CheckBooleanAttr(aFrame, nsWidgetAtoms::mozmenuactive) ?
1602 kThemeMenuSelected : kThemeMenuActive;
1605 HIThemeMenuItemDrawInfo midi = { 0, kThemeMenuItemPlain, menuState };
1606 HIThemeDrawMenuSeparator(&macRect, &macRect, &midi, cgContext, HITHEME_ORIENTATION);
1610 case NS_THEME_TOOLTIP:
1611 CGContextSetRGBFillColor(cgContext, 0.996, 1.000, 0.792, 0.950);
1612 CGContextFillRect(cgContext, macRect);
1615 case NS_THEME_CHECKBOX:
1616 case NS_THEME_RADIO: {
1617 PRBool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX);
1618 DrawCheckboxOrRadio(cgContext, isCheckbox, macRect, GetCheckedOrSelected(aFrame, !isCheckbox),
1619 IsDisabled(aFrame), eventState, aFrame);
1623 case NS_THEME_BUTTON:
1624 if (IsDefaultButton(aFrame)) {
1625 DrawButton(cgContext, kThemePushButton, macRect, true, IsDisabled(aFrame),
1626 kThemeButtonOff, kThemeAdornmentNone, eventState, aFrame);
1627 } else if (IsButtonTypeMenu(aFrame)) {
1628 DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
1630 DrawPushButton(cgContext, macRect, IsDisabled(aFrame), eventState, aFrame);
1634 case NS_THEME_BUTTON_BEVEL:
1635 DrawButton(cgContext, kThemeMediumBevelButton, macRect,
1636 IsDefaultButton(aFrame), IsDisabled(aFrame),
1637 kThemeButtonOff, kThemeAdornmentNone, eventState, aFrame);
1640 case NS_THEME_SPINNER: {
1641 ThemeDrawState state = kThemeStateActive;
1642 nsIContent* content = aFrame->GetContent();
1643 if (content->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::state,
1644 NS_LITERAL_STRING("up"), eCaseMatters)) {
1645 state = kThemeStatePressedUp;
1647 else if (content->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::state,
1648 NS_LITERAL_STRING("down"), eCaseMatters)) {
1649 state = kThemeStatePressedDown;
1652 DrawSpinButtons(cgContext, kThemeIncDecButton, macRect, IsDisabled(aFrame),
1653 state, kThemeAdornmentNone, eventState, aFrame);
1657 case NS_THEME_TOOLBAR_BUTTON:
1658 DrawButton(cgContext, kThemePushButton, macRect,
1659 IsDefaultButton(aFrame), IsDisabled(aFrame),
1660 kThemeButtonOn, kThemeAdornmentNone, eventState, aFrame);
1663 case NS_THEME_TOOLBAR_SEPARATOR: {
1664 HIThemeSeparatorDrawInfo sdi = { 0, kThemeStateActive };
1665 HIThemeDrawSeparator(&macRect, &sdi, cgContext, HITHEME_ORIENTATION);
1669 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
1670 DrawUnifiedToolbar(cgContext, macRect, NativeWindowForFrame(aFrame));
1673 case NS_THEME_TOOLBAR: {
1674 NSWindow* win = NativeWindowForFrame(aFrame);
1675 if (ToolbarCanBeUnified(cgContext, macRect, win)) {
1676 DrawUnifiedToolbar(cgContext, macRect, win);
1679 BOOL isMain = [win isMainWindow] || ![NSView focusView];
1680 CGRect drawRect = macRect;
1683 drawRect.size.height = 1.0f;
1684 DrawNativeGreyColorInRect(cgContext, toolbarTopBorderGrey, drawRect, isMain);
1687 drawRect.origin.y += drawRect.size.height;
1688 drawRect.size.height = macRect.size.height - 2.0f;
1689 DrawNativeGreyColorInRect(cgContext, headerEndGrey, drawRect, isMain);
1692 drawRect.origin.y += drawRect.size.height;
1693 drawRect.size.height = 1.0f;
1694 DrawNativeGreyColorInRect(cgContext, headerBorderGrey, drawRect, isMain);
1698 case NS_THEME_TOOLBOX: {
1699 HIThemeHeaderDrawInfo hdi = { 0, kThemeStateActive, kHIThemeHeaderKindWindow };
1700 HIThemeDrawHeader(&macRect, &hdi, cgContext, HITHEME_ORIENTATION);
1704 case NS_THEME_STATUSBAR:
1705 DrawStatusBar(cgContext, macRect, aFrame);
1708 case NS_THEME_DROPDOWN:
1709 case NS_THEME_DROPDOWN_TEXTFIELD:
1710 DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
1713 case NS_THEME_DROPDOWN_BUTTON:
1714 DrawButton(cgContext, kThemeArrowButton, macRect, PR_FALSE,
1715 IsDisabled(aFrame), kThemeButtonOn,
1716 kThemeAdornmentArrowDownArrow, eventState, aFrame);
1719 case NS_THEME_GROUPBOX: {
1720 HIThemeGroupBoxDrawInfo gdi = { 0, kThemeStateActive, kHIThemeGroupBoxKindPrimary };
1721 HIThemeDrawGroupBox(&macRect, &gdi, cgContext, HITHEME_ORIENTATION);
1725 case NS_THEME_TEXTFIELD:
1726 // HIThemeSetFill is not available on 10.3
1727 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
1728 CGContextFillRect(cgContext, macRect);
1730 // XUL textboxes set the native appearance on the containing box, while
1731 // concrete focus is set on the html:input element within it. We can
1732 // though, check the focused attribute of xul textboxes in this case.
1733 if (aFrame->GetContent()->IsXUL() && IsFocused(aFrame)) {
1734 eventState |= NS_EVENT_STATE_FOCUS;
1737 DrawFrame(cgContext, kHIThemeFrameTextFieldSquare,
1738 macRect, (IsDisabled(aFrame) || IsReadOnly(aFrame)), eventState);
1741 case NS_THEME_SEARCHFIELD:
1742 DrawSearchField(cgContext, macRect, aFrame);
1745 case NS_THEME_PROGRESSBAR:
1746 DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame),
1747 PR_TRUE, GetProgressValue(aFrame),
1748 GetProgressMaxValue(aFrame), aFrame);
1751 case NS_THEME_PROGRESSBAR_VERTICAL:
1752 DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame),
1753 PR_FALSE, GetProgressValue(aFrame),
1754 GetProgressMaxValue(aFrame), aFrame);
1757 case NS_THEME_PROGRESSBAR_CHUNK:
1758 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
1759 // do nothing, covered by the progress bar cases above
1762 case NS_THEME_TREEVIEW_TWISTY:
1763 DrawButton(cgContext, kThemeDisclosureButton, macRect, PR_FALSE, IsDisabled(aFrame),
1764 kThemeDisclosureRight, kThemeAdornmentNone, eventState, aFrame);
1767 case NS_THEME_TREEVIEW_TWISTY_OPEN:
1768 DrawButton(cgContext, kThemeDisclosureButton, macRect, PR_FALSE, IsDisabled(aFrame),
1769 kThemeDisclosureDown, kThemeAdornmentNone, eventState, aFrame);
1772 case NS_THEME_TREEVIEW_HEADER_CELL: {
1773 TreeSortDirection sortDirection = GetTreeSortDirection(aFrame);
1774 DrawButton(cgContext, kThemeListHeaderButton, macRect, PR_FALSE, IsDisabled(aFrame),
1775 sortDirection == eTreeSortDirection_Natural ? kThemeButtonOff : kThemeButtonOn,
1776 sortDirection == eTreeSortDirection_Ascending ?
1777 kThemeAdornmentHeaderButtonSortUp : kThemeAdornmentNone, eventState, aFrame);
1781 case NS_THEME_TREEVIEW_TREEITEM:
1782 case NS_THEME_TREEVIEW:
1783 // HIThemeSetFill is not available on 10.3
1784 // HIThemeSetFill(kThemeBrushWhite, NULL, cgContext, HITHEME_ORIENTATION);
1785 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
1786 CGContextFillRect(cgContext, macRect);
1789 case NS_THEME_TREEVIEW_HEADER:
1790 // do nothing, taken care of by individual header cells
1791 case NS_THEME_TREEVIEW_HEADER_SORTARROW:
1792 // do nothing, taken care of by treeview header
1793 case NS_THEME_TREEVIEW_LINE:
1794 // do nothing, these lines don't exist on macos
1797 case NS_THEME_SCALE_HORIZONTAL:
1798 case NS_THEME_SCALE_VERTICAL: {
1799 PRInt32 curpos = CheckIntAttr(aFrame, nsWidgetAtoms::curpos, 0);
1800 PRInt32 minpos = CheckIntAttr(aFrame, nsWidgetAtoms::minpos, 0);
1801 PRInt32 maxpos = CheckIntAttr(aFrame, nsWidgetAtoms::maxpos, 100);
1805 PRBool reverse = aFrame->GetContent()->
1806 AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::dir,
1807 NS_LITERAL_STRING("reverse"), eCaseMatters);
1808 DrawScale(cgContext, macRect, IsDisabled(aFrame), eventState,
1809 (aWidgetType == NS_THEME_SCALE_VERTICAL), reverse,
1810 curpos, minpos, maxpos, aFrame);
1814 case NS_THEME_SCALE_THUMB_HORIZONTAL:
1815 case NS_THEME_SCALE_THUMB_VERTICAL:
1816 // do nothing, drawn by scale
1819 case NS_THEME_SCROLLBAR_SMALL:
1820 case NS_THEME_SCROLLBAR: {
1821 DrawScrollbar(cgContext, macRect, aFrame);
1824 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
1825 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
1826 #if SCROLLBARS_VISUAL_DEBUG
1827 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 0, 0.6);
1828 CGContextFillRect(cgContext, macRect);
1831 case NS_THEME_SCROLLBAR_BUTTON_UP:
1832 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
1833 #if SCROLLBARS_VISUAL_DEBUG
1834 CGContextSetRGBFillColor(cgContext, 1.0, 0, 0, 0.6);
1835 CGContextFillRect(cgContext, macRect);
1838 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
1839 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
1840 #if SCROLLBARS_VISUAL_DEBUG
1841 CGContextSetRGBFillColor(cgContext, 0, 1.0, 0, 0.6);
1842 CGContextFillRect(cgContext, macRect);
1845 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
1846 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
1847 // do nothing, drawn by scrollbar
1850 case NS_THEME_TEXTFIELD_MULTILINE: {
1851 // we have to draw this by hand because there is no HITheme value for it
1852 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
1854 CGContextFillRect(cgContext, macRect);
1856 CGContextSetLineWidth(cgContext, 1.0);
1857 CGContextSetShouldAntialias(cgContext, false);
1859 // stroke everything but the top line of the text area
1860 CGContextSetRGBStrokeColor(cgContext, 0.6, 0.6, 0.6, 1.0);
1861 CGContextBeginPath(cgContext);
1862 CGContextMoveToPoint(cgContext, macRect.origin.x, macRect.origin.y + 1);
1863 CGContextAddLineToPoint(cgContext, macRect.origin.x, macRect.origin.y + macRect.size.height);
1864 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + macRect.size.height);
1865 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + 1);
1866 CGContextStrokePath(cgContext);
1868 // stroke the line across the top of the text area
1869 CGContextSetRGBStrokeColor(cgContext, 0.4510, 0.4510, 0.4510, 1.0);
1870 CGContextBeginPath(cgContext);
1871 CGContextMoveToPoint(cgContext, macRect.origin.x, macRect.origin.y + 1);
1872 CGContextAddLineToPoint(cgContext, macRect.origin.x + macRect.size.width - 1, macRect.origin.y + 1);
1873 CGContextStrokePath(cgContext);
1875 // draw a focus ring
1876 if (eventState & NS_EVENT_STATE_FOCUS) {
1877 // We need to bring the rectangle in by 1 pixel on each side.
1878 CGRect cgr = CGRectMake(macRect.origin.x + 1,
1879 macRect.origin.y + 1,
1880 macRect.size.width - 2,
1881 macRect.size.height - 2);
1882 HIThemeDrawFocusRect(&cgr, true, cgContext, kHIThemeOrientationNormal);
1887 case NS_THEME_LISTBOX:
1888 // HIThemeSetFill is not available on 10.3
1889 CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
1890 CGContextFillRect(cgContext, macRect);
1891 DrawFrame(cgContext, kHIThemeFrameListBox, macRect,
1892 (IsDisabled(aFrame) || IsReadOnly(aFrame)), eventState);
1896 DrawTab(cgContext, macRect, eventState, aFrame);
1899 case NS_THEME_TAB_PANELS:
1900 DrawTabPanel(cgContext, macRect, aFrame);
1903 case NS_THEME_RESIZER:
1904 DrawResizer(cgContext, macRect, aFrame);
1908 nativeDrawing.EndNativeDrawing();
1912 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1916 nsNativeThemeCocoa::RTLAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame)
1918 if (IsFrameRTL(aFrame))
1919 return nsIntMargin(aMargin.right, aMargin.top, aMargin.left, aMargin.bottom);
1924 static const nsIntMargin kAquaDropdownBorder(5, 1, 22, 2);
1925 static const nsIntMargin kAquaComboboxBorder(4, 3, 20, 3);
1926 static const nsIntMargin kAquaSearchfieldBorder(19, 3, 5, 2);
1929 nsNativeThemeCocoa::GetWidgetBorder(nsIDeviceContext* aContext,
1931 PRUint8 aWidgetType,
1932 nsIntMargin* aResult)
1934 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1936 aResult->SizeTo(0, 0, 0, 0);
1938 switch (aWidgetType) {
1939 case NS_THEME_BUTTON:
1941 if (IsButtonTypeMenu(aFrame)) {
1942 *aResult = RTLAwareMargin(kAquaDropdownBorder, aFrame);
1944 aResult->SizeTo(7, 1, 7, 3);
1949 case NS_THEME_CHECKBOX:
1950 case NS_THEME_RADIO:
1952 // nsFormControlFrame::GetIntrinsicWidth and nsFormControlFrame::GetIntrinsicHeight
1953 // assume a border width of 2px.
1954 aResult->SizeTo(2, 2, 2, 2);
1958 case NS_THEME_DROPDOWN:
1959 case NS_THEME_DROPDOWN_BUTTON:
1960 *aResult = RTLAwareMargin(kAquaDropdownBorder, aFrame);
1963 case NS_THEME_DROPDOWN_TEXTFIELD:
1964 *aResult = RTLAwareMargin(kAquaComboboxBorder, aFrame);
1967 case NS_THEME_TEXTFIELD:
1969 SInt32 frameOutset = 0;
1970 ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
1972 SInt32 textPadding = 0;
1973 ::GetThemeMetric(kThemeMetricEditTextWhitespace, &textPadding);
1975 frameOutset += textPadding;
1977 aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
1981 case NS_THEME_TEXTFIELD_MULTILINE:
1982 aResult->SizeTo(1, 1, 1, 1);
1985 case NS_THEME_SEARCHFIELD:
1986 *aResult = RTLAwareMargin(kAquaSearchfieldBorder, aFrame);
1989 case NS_THEME_LISTBOX:
1991 SInt32 frameOutset = 0;
1992 ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
1993 aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
1997 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
1998 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
2000 // There's only an endcap to worry about when both arrows are on the bottom
2001 NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
2002 if (!buttonPlacement || [buttonPlacement isEqualToString:@"DoubleMax"]) {
2003 PRBool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
2005 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
2006 if (!scrollbarFrame) return NS_ERROR_FAILURE;
2007 PRBool isSmall = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
2009 // There isn't a metric for this, so just hardcode a best guess at the value.
2010 // This value is even less exact due to the fact that the endcap is partially concave.
2011 PRInt32 endcapSize = isSmall ? 5 : 6;
2014 aResult->SizeTo(endcapSize, 0, 0, 0);
2016 aResult->SizeTo(0, endcapSize, 0, 0);
2021 case NS_THEME_STATUSBAR:
2022 aResult->SizeTo(0, 1, 0, 0);
2028 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2031 // Return PR_FALSE here to indicate that CSS padding values should be used. There is
2032 // no reason to make a distinction between padding and border values, just specify
2033 // whatever values you want in GetWidgetBorder and only use this to return PR_TRUE
2034 // if you want to override CSS padding values.
2036 nsNativeThemeCocoa::GetWidgetPadding(nsIDeviceContext* aContext,
2038 PRUint8 aWidgetType,
2039 nsIntMargin* aResult)
2041 // We don't want CSS padding being used for certain widgets.
2042 // See bug 381639 for an example of why.
2043 switch (aWidgetType) {
2044 case NS_THEME_BUTTON:
2045 // Radios and checkboxes return a fixed size in GetMinimumWidgetSize
2046 // and have a meaningful baseline, so they can't have
2047 // author-specified padding.
2048 case NS_THEME_CHECKBOX:
2049 case NS_THEME_RADIO:
2050 aResult->SizeTo(0, 0, 0, 0);
2057 nsNativeThemeCocoa::GetWidgetOverflow(nsIDeviceContext* aContext, nsIFrame* aFrame,
2058 PRUint8 aWidgetType, nsRect* aOverflowRect)
2060 switch (aWidgetType) {
2061 case NS_THEME_BUTTON:
2062 case NS_THEME_TEXTFIELD:
2063 case NS_THEME_TEXTFIELD_MULTILINE:
2064 case NS_THEME_SEARCHFIELD:
2065 case NS_THEME_LISTBOX:
2066 case NS_THEME_DROPDOWN:
2067 case NS_THEME_DROPDOWN_BUTTON:
2068 case NS_THEME_DROPDOWN_TEXTFIELD:
2069 case NS_THEME_CHECKBOX:
2070 case NS_THEME_RADIO:
2073 // We assume that the above widgets can draw a focus ring that will be less than
2074 // or equal to 4 pixels thick.
2075 nsIntMargin extraSize = nsIntMargin(MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH);
2076 PRInt32 p2a = aContext->AppUnitsPerDevPixel();
2077 nsMargin m(NSIntPixelsToAppUnits(extraSize.left, p2a),
2078 NSIntPixelsToAppUnits(extraSize.top, p2a),
2079 NSIntPixelsToAppUnits(extraSize.right, p2a),
2080 NSIntPixelsToAppUnits(extraSize.bottom, p2a));
2081 aOverflowRect->Inflate(m);
2089 static const PRInt32 kRegularScrollbarThumbMinSize = 22;
2090 static const PRInt32 kSmallScrollbarThumbMinSize = 19;
2093 nsNativeThemeCocoa::GetMinimumWidgetSize(nsIRenderingContext* aContext,
2095 PRUint8 aWidgetType,
2097 PRBool* aIsOverridable)
2099 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2101 aResult->SizeTo(0,0);
2102 *aIsOverridable = PR_TRUE;
2104 switch (aWidgetType) {
2105 case NS_THEME_BUTTON:
2107 aResult->SizeTo(pushButtonSettings.minimumSizes[miniControlSize].width,
2108 pushButtonSettings.naturalSizes[miniControlSize].height);
2112 case NS_THEME_SPINNER:
2114 SInt32 buttonHeight = 0, buttonWidth = 0;
2115 ::GetThemeMetric(kThemeMetricLittleArrowsWidth, &buttonWidth);
2116 ::GetThemeMetric(kThemeMetricLittleArrowsHeight, &buttonHeight);
2117 aResult->SizeTo(buttonWidth, buttonHeight);
2118 *aIsOverridable = PR_FALSE;
2122 case NS_THEME_DROPDOWN:
2123 case NS_THEME_DROPDOWN_BUTTON:
2125 SInt32 popupHeight = 0;
2126 ::GetThemeMetric(kThemeMetricPopupButtonHeight, &popupHeight);
2127 aResult->SizeTo(0, popupHeight);
2131 case NS_THEME_TEXTFIELD:
2132 case NS_THEME_TEXTFIELD_MULTILINE:
2133 case NS_THEME_SEARCHFIELD:
2135 // at minimum, we should be tall enough for 9pt text.
2136 // I'm using hardcoded values here because the appearance manager
2137 // values for the frame size are incorrect.
2138 aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */);
2142 case NS_THEME_PROGRESSBAR:
2144 SInt32 barHeight = 0;
2145 ::GetThemeMetric(kThemeMetricNormalProgressBarThickness, &barHeight);
2146 aResult->SizeTo(0, barHeight);
2150 case NS_THEME_TREEVIEW_TWISTY:
2151 case NS_THEME_TREEVIEW_TWISTY_OPEN:
2153 SInt32 twistyHeight = 0, twistyWidth = 0;
2154 ::GetThemeMetric(kThemeMetricDisclosureButtonWidth, &twistyWidth);
2155 ::GetThemeMetric(kThemeMetricDisclosureButtonHeight, &twistyHeight);
2156 aResult->SizeTo(twistyWidth, twistyHeight);
2157 *aIsOverridable = PR_FALSE;
2161 case NS_THEME_TREEVIEW_HEADER:
2162 case NS_THEME_TREEVIEW_HEADER_CELL:
2164 SInt32 headerHeight = 0;
2165 ::GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
2166 aResult->SizeTo(0, headerHeight - 1); // We don't need the top border.
2172 aResult->SizeTo(0, NATURAL_MINI_TAB_BUTTON_HEIGHT);
2176 case NS_THEME_SCALE_HORIZONTAL:
2178 SInt32 scaleHeight = 0;
2179 ::GetThemeMetric(kThemeMetricHSliderHeight, &scaleHeight);
2180 aResult->SizeTo(scaleHeight, scaleHeight);
2181 *aIsOverridable = PR_FALSE;
2185 case NS_THEME_SCALE_VERTICAL:
2187 SInt32 scaleWidth = 0;
2188 ::GetThemeMetric(kThemeMetricVSliderWidth, &scaleWidth);
2189 aResult->SizeTo(scaleWidth, scaleWidth);
2190 *aIsOverridable = PR_FALSE;
2194 case NS_THEME_SCROLLBAR_SMALL:
2196 SInt32 scrollbarWidth = 0;
2197 ::GetThemeMetric(kThemeMetricSmallScrollBarWidth, &scrollbarWidth);
2198 aResult->SizeTo(scrollbarWidth, scrollbarWidth);
2199 *aIsOverridable = PR_FALSE;
2203 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
2204 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
2206 // Find our parent scrollbar frame in order to find out whether we're in
2207 // a small or a large scrollbar.
2208 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
2209 if (!scrollbarFrame)
2210 return NS_ERROR_FAILURE;
2212 PRBool isSmall = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
2213 PRBool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL);
2214 PRInt32& minSize = isHorizontal ? aResult->width : aResult->height;
2215 minSize = isSmall ? kSmallScrollbarThumbMinSize : kRegularScrollbarThumbMinSize;
2219 case NS_THEME_SCROLLBAR:
2220 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
2221 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
2223 // yeah, i know i'm cheating a little here, but i figure that it
2224 // really doesn't matter if the scrollbar is vertical or horizontal
2225 // and the width metric is a really good metric for every piece
2226 // of the scrollbar.
2228 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
2229 if (!scrollbarFrame) return NS_ERROR_FAILURE;
2231 PRInt32 themeMetric = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
2232 kThemeMetricSmallScrollBarWidth :
2233 kThemeMetricScrollBarWidth;
2234 SInt32 scrollbarWidth = 0;
2235 ::GetThemeMetric(themeMetric, &scrollbarWidth);
2236 aResult->SizeTo(scrollbarWidth, scrollbarWidth);
2237 *aIsOverridable = PR_FALSE;
2241 case NS_THEME_SCROLLBAR_BUTTON_UP:
2242 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
2243 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
2244 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
2246 nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
2247 if (!scrollbarFrame) return NS_ERROR_FAILURE;
2249 // Since there is no NS_THEME_SCROLLBAR_BUTTON_UP_SMALL we need to ask the parent what appearance style it has.
2250 PRInt32 themeMetric = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
2251 kThemeMetricSmallScrollBarWidth :
2252 kThemeMetricScrollBarWidth;
2253 SInt32 scrollbarWidth = 0;
2254 ::GetThemeMetric(themeMetric, &scrollbarWidth);
2256 // It seems that for both sizes of scrollbar, the buttons are one pixel "longer".
2257 if (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT)
2258 aResult->SizeTo(scrollbarWidth+1, scrollbarWidth);
2260 aResult->SizeTo(scrollbarWidth, scrollbarWidth+1);
2262 *aIsOverridable = PR_FALSE;
2265 case NS_THEME_RESIZER:
2267 HIThemeGrowBoxDrawInfo drawInfo;
2268 drawInfo.version = 0;
2269 drawInfo.state = kThemeStateActive;
2270 drawInfo.kind = kHIThemeGrowBoxKindNormal;
2271 drawInfo.direction = kThemeGrowRight | kThemeGrowDown;
2272 drawInfo.size = kHIThemeGrowBoxSizeNormal;
2273 HIPoint pnt = { 0, 0 };
2275 HIThemeGetGrowBoxBounds(&pnt, &drawInfo, &bounds);
2276 aResult->SizeTo(bounds.size.width, bounds.size.height);
2282 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2286 nsNativeThemeCocoa::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType,
2287 nsIAtom* aAttribute, PRBool* aShouldRepaint)
2289 // Some widget types just never change state.
2290 switch (aWidgetType) {
2291 case NS_THEME_TOOLBOX:
2292 case NS_THEME_TOOLBAR:
2293 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
2294 case NS_THEME_TOOLBAR_BUTTON:
2295 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
2296 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
2297 case NS_THEME_STATUSBAR:
2298 case NS_THEME_STATUSBAR_PANEL:
2299 case NS_THEME_STATUSBAR_RESIZER_PANEL:
2300 case NS_THEME_TOOLTIP:
2301 case NS_THEME_TAB_PANELS:
2302 case NS_THEME_TAB_PANEL:
2303 case NS_THEME_DIALOG:
2304 case NS_THEME_MENUPOPUP:
2305 case NS_THEME_GROUPBOX:
2306 *aShouldRepaint = PR_FALSE;
2308 case NS_THEME_PROGRESSBAR_CHUNK:
2309 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
2310 case NS_THEME_PROGRESSBAR:
2311 case NS_THEME_PROGRESSBAR_VERTICAL:
2312 *aShouldRepaint = (aAttribute == nsWidgetAtoms::step);
2316 // XXXdwh Not sure what can really be done here. Can at least guess for
2317 // specific widgets that they're highly unlikely to have certain states.
2318 // For example, a toolbar doesn't care about any states.
2320 // Hover/focus/active changed. Always repaint.
2321 *aShouldRepaint = PR_TRUE;
2323 // Check the attribute to see if it's relevant.
2324 // disabled, checked, dlgtype, default, etc.
2325 *aShouldRepaint = PR_FALSE;
2326 if (aAttribute == nsWidgetAtoms::disabled ||
2327 aAttribute == nsWidgetAtoms::checked ||
2328 aAttribute == nsWidgetAtoms::selected ||
2329 aAttribute == nsWidgetAtoms::mozmenuactive ||
2330 aAttribute == nsWidgetAtoms::sortdirection ||
2331 aAttribute == nsWidgetAtoms::focused ||
2332 aAttribute == nsWidgetAtoms::_default ||
2333 aAttribute == nsWidgetAtoms::step ||
2334 aAttribute == nsWidgetAtoms::open)
2335 *aShouldRepaint = PR_TRUE;
2342 nsNativeThemeCocoa::ThemeChanged()
2344 // This is unimplemented because we don't care if gecko changes its theme
2345 // and Mac OS X doesn't have themes.
2350 nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
2351 PRUint8 aWidgetType)
2353 // We don't have CSS set up to render non-native scrollbars on Mac OS X so we
2354 // render natively even if native theme support is disabled.
2355 if (aWidgetType != NS_THEME_SCROLLBAR &&
2356 aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled())
2359 // if this is a dropdown button in a combobox the answer is always no
2360 if (aWidgetType == NS_THEME_DROPDOWN_BUTTON) {
2361 nsIFrame* parentFrame = aFrame->GetParent();
2362 if (parentFrame && (parentFrame->GetType() == nsWidgetAtoms::comboboxControlFrame))
2366 switch (aWidgetType) {
2367 case NS_THEME_LISTBOX:
2369 case NS_THEME_DIALOG:
2370 case NS_THEME_WINDOW:
2371 case NS_THEME_MENUPOPUP:
2372 case NS_THEME_MENUITEM:
2373 case NS_THEME_MENUSEPARATOR:
2374 case NS_THEME_TOOLTIP:
2375 case NS_THEME_RESIZER:
2377 case NS_THEME_CHECKBOX:
2378 case NS_THEME_CHECKBOX_CONTAINER:
2379 case NS_THEME_RADIO:
2380 case NS_THEME_RADIO_CONTAINER:
2381 case NS_THEME_GROUPBOX:
2382 case NS_THEME_BUTTON:
2383 case NS_THEME_BUTTON_BEVEL:
2384 case NS_THEME_SPINNER:
2385 case NS_THEME_TOOLBAR:
2386 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
2387 case NS_THEME_STATUSBAR:
2388 case NS_THEME_TEXTFIELD:
2389 case NS_THEME_TEXTFIELD_MULTILINE:
2390 case NS_THEME_SEARCHFIELD:
2391 //case NS_THEME_TOOLBOX:
2392 //case NS_THEME_TOOLBAR_BUTTON:
2393 case NS_THEME_PROGRESSBAR:
2394 case NS_THEME_PROGRESSBAR_VERTICAL:
2395 case NS_THEME_PROGRESSBAR_CHUNK:
2396 case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
2397 case NS_THEME_TOOLBAR_SEPARATOR:
2399 case NS_THEME_TAB_PANELS:
2402 case NS_THEME_TREEVIEW_TWISTY:
2403 case NS_THEME_TREEVIEW_TWISTY_OPEN:
2404 case NS_THEME_TREEVIEW:
2405 case NS_THEME_TREEVIEW_HEADER:
2406 case NS_THEME_TREEVIEW_HEADER_CELL:
2407 case NS_THEME_TREEVIEW_HEADER_SORTARROW:
2408 case NS_THEME_TREEVIEW_TREEITEM:
2409 case NS_THEME_TREEVIEW_LINE:
2411 case NS_THEME_SCALE_HORIZONTAL:
2412 case NS_THEME_SCALE_THUMB_HORIZONTAL:
2413 case NS_THEME_SCALE_VERTICAL:
2414 case NS_THEME_SCALE_THUMB_VERTICAL:
2416 case NS_THEME_SCROLLBAR:
2417 case NS_THEME_SCROLLBAR_SMALL:
2418 case NS_THEME_SCROLLBAR_BUTTON_UP:
2419 case NS_THEME_SCROLLBAR_BUTTON_DOWN:
2420 case NS_THEME_SCROLLBAR_BUTTON_LEFT:
2421 case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
2422 case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
2423 case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
2424 case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
2425 case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
2427 case NS_THEME_DROPDOWN:
2428 case NS_THEME_DROPDOWN_BUTTON:
2429 case NS_THEME_DROPDOWN_TEXT:
2430 case NS_THEME_DROPDOWN_TEXTFIELD:
2431 return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
2439 nsNativeThemeCocoa::WidgetIsContainer(PRUint8 aWidgetType)
2441 // flesh this out at some point
2442 switch (aWidgetType) {
2443 case NS_THEME_DROPDOWN_BUTTON:
2444 case NS_THEME_RADIO:
2445 case NS_THEME_CHECKBOX:
2446 case NS_THEME_PROGRESSBAR:
2454 nsNativeThemeCocoa::ThemeDrawsFocusForWidget(nsPresContext* aPresContext, nsIFrame* aFrame, PRUint8 aWidgetType)
2456 if (aWidgetType == NS_THEME_DROPDOWN ||
2457 aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD ||
2458 aWidgetType == NS_THEME_BUTTON ||
2459 aWidgetType == NS_THEME_RADIO ||
2460 aWidgetType == NS_THEME_CHECKBOX)
2467 nsNativeThemeCocoa::ThemeNeedsComboboxDropmarker()
2473 nsNativeThemeCocoa::GetWidgetTransparency(PRUint8 aWidgetType)
2475 if (aWidgetType == NS_THEME_MENUPOPUP ||
2476 aWidgetType == NS_THEME_TOOLTIP)
2477 return eTransparencyTransparent;
2479 return eTransparencyOpaque;