2 * Copyright (C) 2008, 2010, 2011, 2012 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #import "platform/mac/ThemeMac.h"
29 #import <Carbon/Carbon.h>
30 #import "platform/graphics/GraphicsContextStateSaver.h"
31 #import "platform/mac/BlockExceptions.h"
32 #import "platform/mac/LocalCurrentGraphicsContext.h"
33 #import "platform/mac/WebCoreNSCellExtras.h"
34 #import "platform/scroll/ScrollView.h"
35 #include "wtf/StdLibExtras.h"
39 NSRect focusRingClipRect;
41 // This is a view whose sole purpose is to tell AppKit that it's flipped.
42 @interface WebCoreFlippedView : NSControl
45 @implementation WebCoreFlippedView
52 - (NSText *)currentEditor
57 - (BOOL)_automaticFocusRingDisabled
62 - (NSRect)_focusRingVisibleRect
64 if (NSIsEmptyRect(focusRingClipRect))
65 return [self visibleRect];
67 NSRect rect = focusRingClipRect;
68 rect.origin.y = [self bounds].size.height - NSMaxY(rect);
73 - (NSView *)_focusRingClipAncestor
80 @implementation NSFont (WebCoreTheme)
82 - (NSString*)webCoreFamilyName
84 if ([[self familyName] hasPrefix:@"."])
85 return [self fontName];
87 return [self familyName];
101 Theme* platformTheme()
103 DEFINE_STATIC_LOCAL(ThemeMac, themeMac, ());
107 // Helper functions used by a bunch of different control parts.
109 static NSControlSize controlSizeForFont(const FontDescription& fontDescription)
111 int fontSize = fontDescription.computedPixelSize();
113 return NSRegularControlSize;
115 return NSSmallControlSize;
116 return NSMiniControlSize;
119 static LengthSize sizeFromNSControlSize(NSControlSize nsControlSize, const LengthSize& zoomedSize, float zoomFactor, const IntSize* sizes)
121 IntSize controlSize = sizes[nsControlSize];
122 if (zoomFactor != 1.0f)
123 controlSize = IntSize(controlSize.width() * zoomFactor, controlSize.height() * zoomFactor);
124 LengthSize result = zoomedSize;
125 if (zoomedSize.width().isIntrinsicOrAuto() && controlSize.width() > 0)
126 result.setWidth(Length(controlSize.width(), Fixed));
127 if (zoomedSize.height().isIntrinsicOrAuto() && controlSize.height() > 0)
128 result.setHeight(Length(controlSize.height(), Fixed));
132 static LengthSize sizeFromFont(const FontDescription& fontDescription, const LengthSize& zoomedSize, float zoomFactor, const IntSize* sizes)
134 return sizeFromNSControlSize(controlSizeForFont(fontDescription), zoomedSize, zoomFactor, sizes);
137 static ControlSize controlSizeFromPixelSize(const IntSize* sizes, const IntSize& minZoomedSize, float zoomFactor)
139 if (minZoomedSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomFactor) &&
140 minZoomedSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomFactor))
141 return NSRegularControlSize;
142 if (minZoomedSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomFactor) &&
143 minZoomedSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomFactor))
144 return NSSmallControlSize;
145 return NSMiniControlSize;
148 static void setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minZoomedSize, float zoomFactor)
150 ControlSize size = controlSizeFromPixelSize(sizes, minZoomedSize, zoomFactor);
151 if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
152 [cell setControlSize:(NSControlSize)size];
155 static void updateStates(NSCell* cell, ControlStates states)
157 // Hover state is not supported by Aqua.
160 bool oldPressed = [cell isHighlighted];
161 bool pressed = states & PressedState;
162 if (pressed != oldPressed)
163 [cell setHighlighted:pressed];
166 bool oldEnabled = [cell isEnabled];
167 bool enabled = states & EnabledState;
168 if (enabled != oldEnabled)
169 [cell setEnabled:enabled];
171 #if BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
173 bool oldFocused = [cell showsFirstResponder];
174 bool focused = states & FocusState;
175 if (focused != oldFocused)
176 [cell setShowsFirstResponder:focused];
179 // Checked and Indeterminate
180 bool oldIndeterminate = [cell state] == NSMixedState;
181 bool indeterminate = (states & IndeterminateState);
182 bool checked = states & CheckedState;
183 bool oldChecked = [cell state] == NSOnState;
184 if (oldIndeterminate != indeterminate || checked != oldChecked)
185 [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)];
187 // Window inactive state does not need to be checked explicitly, since we paint parented to
188 // a view in a window whose key state can be detected.
191 static ThemeDrawState convertControlStatesToThemeDrawState(ThemeButtonKind kind, ControlStates states)
193 if (states & ReadOnlyState)
194 return kThemeStateUnavailableInactive;
195 if (!(states & EnabledState))
196 return kThemeStateUnavailableInactive;
198 // Do not process PressedState if !EnabledState or ReadOnlyState.
199 if (states & PressedState) {
200 if (kind == kThemeIncDecButton || kind == kThemeIncDecButtonSmall || kind == kThemeIncDecButtonMini)
201 return states & SpinUpState ? kThemeStatePressedUp : kThemeStatePressedDown;
202 return kThemeStatePressed;
204 return kThemeStateActive;
207 static IntRect inflateRect(const IntRect& zoomedRect, const IntSize& zoomedSize, const int* margins, float zoomFactor)
209 // Only do the inflation if the available width/height are too small. Otherwise try to
210 // fit the glow/check space into the available box's width/height.
211 int widthDelta = zoomedRect.width() - (zoomedSize.width() + margins[leftMargin] * zoomFactor + margins[rightMargin] * zoomFactor);
212 int heightDelta = zoomedRect.height() - (zoomedSize.height() + margins[topMargin] * zoomFactor + margins[bottomMargin] * zoomFactor);
213 IntRect result(zoomedRect);
214 if (widthDelta < 0) {
215 result.setX(result.x() - margins[leftMargin] * zoomFactor);
216 result.setWidth(result.width() - widthDelta);
218 if (heightDelta < 0) {
219 result.setY(result.y() - margins[topMargin] * zoomFactor);
220 result.setHeight(result.height() - heightDelta);
227 static const IntSize* checkboxSizes()
229 static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
233 static const int* checkboxMargins(NSControlSize controlSize)
235 static const int margins[3][4] =
241 return margins[controlSize];
244 static LengthSize checkboxSize(const FontDescription& fontDescription, const LengthSize& zoomedSize, float zoomFactor)
246 // If the width and height are both specified, then we have nothing to do.
247 if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto())
250 // Use the font size to determine the intrinsic width of the control.
251 return sizeFromFont(fontDescription, zoomedSize, zoomFactor, checkboxSizes());
254 static NSButtonCell *checkbox(ControlStates states, const IntRect& zoomedRect, float zoomFactor)
256 static NSButtonCell *checkboxCell;
258 checkboxCell = [[NSButtonCell alloc] init];
259 [checkboxCell setButtonType:NSSwitchButton];
260 [checkboxCell setTitle:nil];
261 [checkboxCell setAllowsMixedState:YES];
262 [checkboxCell setFocusRingType:NSFocusRingTypeExterior];
265 // Set the control size based off the rectangle we're painting into.
266 setControlSize(checkboxCell, checkboxSizes(), zoomedRect.size(), zoomFactor);
268 // Update the various states we respond to.
269 updateStates(checkboxCell, states);
274 // FIXME: Share more code with radio buttons.
275 static void paintCheckbox(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView)
277 BEGIN_BLOCK_OBJC_EXCEPTIONS
279 // Determine the width and height needed for the control and prepare the cell for painting.
280 NSButtonCell *checkboxCell = checkbox(states, zoomedRect, zoomFactor);
281 GraphicsContextStateSaver stateSaver(*context);
283 NSControlSize controlSize = [checkboxCell controlSize];
284 IntSize zoomedSize = checkboxSizes()[controlSize];
285 zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
286 zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
287 IntRect inflatedRect = inflateRect(zoomedRect, zoomedSize, checkboxMargins(controlSize), zoomFactor);
289 if (zoomFactor != 1.0f) {
290 inflatedRect.setWidth(inflatedRect.width() / zoomFactor);
291 inflatedRect.setHeight(inflatedRect.height() / zoomFactor);
292 context->translate(inflatedRect.x(), inflatedRect.y());
293 context->scale(FloatSize(zoomFactor, zoomFactor));
294 context->translate(-inflatedRect.x(), -inflatedRect.y());
297 LocalCurrentGraphicsContext localContext(context);
298 NSView *view = ThemeMac::ensuredView(scrollView);
299 [checkboxCell drawWithFrame:NSRect(inflatedRect) inView:view];
300 #if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
301 if (states & FocusState)
302 [checkboxCell _web_drawFocusRingWithFrame:NSRect(inflatedRect) inView:view];
304 [checkboxCell setControlView:nil];
306 END_BLOCK_OBJC_EXCEPTIONS
311 static const IntSize* radioSizes()
313 static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
317 static const int* radioMargins(NSControlSize controlSize)
319 static const int margins[3][4] =
325 return margins[controlSize];
328 static LengthSize radioSize(const FontDescription& fontDescription, const LengthSize& zoomedSize, float zoomFactor)
330 // If the width and height are both specified, then we have nothing to do.
331 if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto())
334 // Use the font size to determine the intrinsic width of the control.
335 return sizeFromFont(fontDescription, zoomedSize, zoomFactor, radioSizes());
338 static NSButtonCell *radio(ControlStates states, const IntRect& zoomedRect, float zoomFactor)
340 static NSButtonCell *radioCell;
342 radioCell = [[NSButtonCell alloc] init];
343 [radioCell setButtonType:NSRadioButton];
344 [radioCell setTitle:nil];
345 [radioCell setFocusRingType:NSFocusRingTypeExterior];
348 // Set the control size based off the rectangle we're painting into.
349 setControlSize(radioCell, radioSizes(), zoomedRect.size(), zoomFactor);
351 // Update the various states we respond to.
352 updateStates(radioCell, states);
357 static void paintRadio(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView)
359 // Determine the width and height needed for the control and prepare the cell for painting.
360 NSButtonCell *radioCell = radio(states, zoomedRect, zoomFactor);
361 GraphicsContextStateSaver stateSaver(*context);
363 NSControlSize controlSize = [radioCell controlSize];
364 IntSize zoomedSize = radioSizes()[controlSize];
365 zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
366 zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
367 IntRect inflatedRect = inflateRect(zoomedRect, zoomedSize, radioMargins(controlSize), zoomFactor);
369 if (zoomFactor != 1.0f) {
370 inflatedRect.setWidth(inflatedRect.width() / zoomFactor);
371 inflatedRect.setHeight(inflatedRect.height() / zoomFactor);
372 context->translate(inflatedRect.x(), inflatedRect.y());
373 context->scale(FloatSize(zoomFactor, zoomFactor));
374 context->translate(-inflatedRect.x(), -inflatedRect.y());
377 LocalCurrentGraphicsContext localContext(context);
378 BEGIN_BLOCK_OBJC_EXCEPTIONS
379 NSView *view = ThemeMac::ensuredView(scrollView);
380 [radioCell drawWithFrame:NSRect(inflatedRect) inView:view];
381 #if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
382 if (states & FocusState)
383 [radioCell _web_drawFocusRingWithFrame:NSRect(inflatedRect) inView:view];
385 [radioCell setControlView:nil];
386 END_BLOCK_OBJC_EXCEPTIONS
391 // Buttons really only constrain height. They respect width.
392 static const IntSize* buttonSizes()
394 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
398 static const int* buttonMargins(NSControlSize controlSize)
400 static const int margins[3][4] =
406 return margins[controlSize];
409 static void setUpButtonCell(NSButtonCell *cell, ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor)
411 // Set the control size based off the rectangle we're painting into.
412 const IntSize* sizes = buttonSizes();
413 if (part == SquareButtonPart || zoomedRect.height() > buttonSizes()[NSRegularControlSize].height() * zoomFactor) {
414 // Use the square button
415 if ([cell bezelStyle] != NSShadowlessSquareBezelStyle)
416 [cell setBezelStyle:NSShadowlessSquareBezelStyle];
417 } else if ([cell bezelStyle] != NSRoundedBezelStyle)
418 [cell setBezelStyle:NSRoundedBezelStyle];
420 setControlSize(cell, sizes, zoomedRect.size(), zoomFactor);
422 // Update the various states we respond to.
423 updateStates(cell, states);
426 static NSButtonCell *button(ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor)
428 static NSButtonCell *cell = nil;
430 cell = [[NSButtonCell alloc] init];
432 [cell setButtonType:NSMomentaryPushInButton];
434 setUpButtonCell(cell, part, states, zoomedRect, zoomFactor);
438 static void paintButton(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView)
440 BEGIN_BLOCK_OBJC_EXCEPTIONS
442 // Determine the width and height needed for the control and prepare the cell for painting.
443 NSButtonCell *buttonCell = button(part, states, zoomedRect, zoomFactor);
444 GraphicsContextStateSaver stateSaver(*context);
446 NSControlSize controlSize = [buttonCell controlSize];
447 IntSize zoomedSize = buttonSizes()[controlSize];
448 zoomedSize.setWidth(zoomedRect.width()); // Buttons don't ever constrain width, so the zoomed width can just be honored.
449 zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
450 IntRect inflatedRect = zoomedRect;
451 if ([buttonCell bezelStyle] == NSRoundedBezelStyle) {
452 // Center the button within the available space.
453 if (inflatedRect.height() > zoomedSize.height()) {
454 inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - zoomedSize.height()) / 2);
455 inflatedRect.setHeight(zoomedSize.height());
458 // Now inflate it to account for the shadow.
459 inflatedRect = inflateRect(inflatedRect, zoomedSize, buttonMargins(controlSize), zoomFactor);
461 if (zoomFactor != 1.0f) {
462 inflatedRect.setWidth(inflatedRect.width() / zoomFactor);
463 inflatedRect.setHeight(inflatedRect.height() / zoomFactor);
464 context->translate(inflatedRect.x(), inflatedRect.y());
465 context->scale(FloatSize(zoomFactor, zoomFactor));
466 context->translate(-inflatedRect.x(), -inflatedRect.y());
470 LocalCurrentGraphicsContext localContext(context);
471 NSView *view = ThemeMac::ensuredView(scrollView);
473 [buttonCell drawWithFrame:NSRect(inflatedRect) inView:view];
474 #if !BUTTON_CELL_DRAW_WITH_FRAME_DRAWS_FOCUS_RING
475 if (states & FocusState)
476 [buttonCell _web_drawFocusRingWithFrame:NSRect(inflatedRect) inView:view];
478 [buttonCell setControlView:nil];
480 END_BLOCK_OBJC_EXCEPTIONS
485 static const IntSize* stepperSizes()
487 static const IntSize sizes[3] = { IntSize(19, 27), IntSize(15, 22), IntSize(13, 15) };
491 // We don't use controlSizeForFont() for steppers because the stepper height
492 // should be equal to or less than the corresponding text field height,
493 static NSControlSize stepperControlSizeForFont(const FontDescription& fontDescription)
495 int fontSize = fontDescription.computedPixelSize();
497 return NSRegularControlSize;
499 return NSSmallControlSize;
500 return NSMiniControlSize;
503 static void paintStepper(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView*)
505 // We don't use NSStepperCell because there are no ways to draw an
506 // NSStepperCell with the up button highlighted.
508 HIThemeButtonDrawInfo drawInfo;
509 drawInfo.version = 0;
510 drawInfo.state = convertControlStatesToThemeDrawState(kThemeIncDecButton, states);
511 drawInfo.adornment = kThemeAdornmentDefault;
512 ControlSize controlSize = controlSizeFromPixelSize(stepperSizes(), zoomedRect.size(), zoomFactor);
513 if (controlSize == NSSmallControlSize)
514 drawInfo.kind = kThemeIncDecButtonSmall;
515 else if (controlSize == NSMiniControlSize)
516 drawInfo.kind = kThemeIncDecButtonMini;
518 drawInfo.kind = kThemeIncDecButton;
520 IntRect rect(zoomedRect);
521 GraphicsContextStateSaver stateSaver(*context);
522 if (zoomFactor != 1.0f) {
523 rect.setWidth(rect.width() / zoomFactor);
524 rect.setHeight(rect.height() / zoomFactor);
525 context->translate(rect.x(), rect.y());
526 context->scale(FloatSize(zoomFactor, zoomFactor));
527 context->translate(-rect.x(), -rect.y());
530 CGRect backgroundBounds;
531 HIThemeGetButtonBackgroundBounds(&bounds, &drawInfo, &backgroundBounds);
532 // Center the stepper rectangle in the specified area.
533 backgroundBounds.origin.x = bounds.origin.x + (bounds.size.width - backgroundBounds.size.width) / 2;
534 if (backgroundBounds.size.height < bounds.size.height) {
535 int heightDiff = clampToInteger(bounds.size.height - backgroundBounds.size.height);
536 backgroundBounds.origin.y = bounds.origin.y + (heightDiff / 2) + 1;
539 LocalCurrentGraphicsContext localContext(context);
540 HIThemeDrawButton(&backgroundBounds, &drawInfo, localContext.cgContext(), kHIThemeOrientationNormal, 0);
543 // This will ensure that we always return a valid NSView, even if ScrollView doesn't have an associated document NSView.
544 // If the ScrollView doesn't have an NSView, we will return a fake NSView whose sole purpose is to tell AppKit that it's flipped.
545 NSView *ThemeMac::ensuredView(ScrollView* scrollView)
548 // Use a fake flipped view.
549 static NSView *flippedView = [[WebCoreFlippedView alloc] init];
550 [flippedView setFrameSize:NSSizeFromCGSize(scrollView->contentsSize())];
555 void ThemeMac::setFocusRingClipRect(const FloatRect& rect)
557 focusRingClipRect = rect;
562 int ThemeMac::baselinePositionAdjustment(ControlPart part) const
564 if (part == CheckboxPart || part == RadioPart)
566 return Theme::baselinePositionAdjustment(part);
569 FontDescription ThemeMac::controlFont(ControlPart part, const FontDescription& fontDescription, float zoomFactor) const
572 case PushButtonPart: {
573 FontDescription result;
574 result.setIsAbsoluteSize(true);
575 result.setGenericFamily(FontDescription::SerifFamily);
577 NSFont* nsFont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSizeForFont(fontDescription)]];
578 result.firstFamily().setFamily([nsFont webCoreFamilyName]);
579 result.setComputedSize([nsFont pointSize] * zoomFactor);
580 result.setSpecifiedSize([nsFont pointSize] * zoomFactor);
584 return Theme::controlFont(part, fontDescription, zoomFactor);
588 LengthSize ThemeMac::controlSize(ControlPart part, const FontDescription& fontDescription, const LengthSize& zoomedSize, float zoomFactor) const
592 return checkboxSize(fontDescription, zoomedSize, zoomFactor);
594 return radioSize(fontDescription, zoomedSize, zoomFactor);
596 // Height is reset to auto so that specified heights can be ignored.
597 return sizeFromFont(fontDescription, LengthSize(zoomedSize.width(), Length()), zoomFactor, buttonSizes());
598 case InnerSpinButtonPart:
599 if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto())
601 return sizeFromNSControlSize(stepperControlSizeForFont(fontDescription), zoomedSize, zoomFactor, stepperSizes());
607 LengthSize ThemeMac::minimumControlSize(ControlPart part, const FontDescription& fontDescription, float zoomFactor) const
610 case SquareButtonPart:
612 return LengthSize(Length(0, Fixed), Length(static_cast<int>(15 * zoomFactor), Fixed));
613 case InnerSpinButtonPart:{
614 IntSize base = stepperSizes()[NSMiniControlSize];
615 return LengthSize(Length(static_cast<int>(base.width() * zoomFactor), Fixed),
616 Length(static_cast<int>(base.height() * zoomFactor), Fixed));
619 return Theme::minimumControlSize(part, fontDescription, zoomFactor);
623 LengthBox ThemeMac::controlBorder(ControlPart part, const FontDescription& fontDescription, const LengthBox& zoomedBox, float zoomFactor) const
626 case SquareButtonPart:
628 return LengthBox(0, zoomedBox.right().value(), 0, zoomedBox.left().value());
630 return Theme::controlBorder(part, fontDescription, zoomedBox, zoomFactor);
634 LengthBox ThemeMac::controlPadding(ControlPart part, const FontDescription& fontDescription, const LengthBox& zoomedBox, float zoomFactor) const
637 case PushButtonPart: {
638 // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large
639 // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is
640 // by definition constrained, since we select mini only for small cramped environments.
641 // This also guarantees the HTML <button> will match our rendering by default, since we're using a consistent
643 const int padding = 8 * zoomFactor;
644 return LengthBox(0, padding, 0, padding);
647 return Theme::controlPadding(part, fontDescription, zoomedBox, zoomFactor);
651 void ThemeMac::inflateControlPaintRect(ControlPart part, ControlStates states, IntRect& zoomedRect, float zoomFactor) const
653 BEGIN_BLOCK_OBJC_EXCEPTIONS
656 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
657 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
658 NSCell *cell = checkbox(states, zoomedRect, zoomFactor);
659 NSControlSize controlSize = [cell controlSize];
660 IntSize zoomedSize = checkboxSizes()[controlSize];
661 zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
662 zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
663 zoomedRect = inflateRect(zoomedRect, zoomedSize, checkboxMargins(controlSize), zoomFactor);
667 // We inflate the rect as needed to account for padding included in the cell to accommodate the radio button
668 // shadow". We don't consider this part of the bounds of the control in WebKit.
669 NSCell *cell = radio(states, zoomedRect, zoomFactor);
670 NSControlSize controlSize = [cell controlSize];
671 IntSize zoomedSize = radioSizes()[controlSize];
672 zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
673 zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
674 zoomedRect = inflateRect(zoomedRect, zoomedSize, radioMargins(controlSize), zoomFactor);
679 NSButtonCell *cell = button(part, states, zoomedRect, zoomFactor);
680 NSControlSize controlSize = [cell controlSize];
682 // We inflate the rect as needed to account for the Aqua button's shadow.
683 if ([cell bezelStyle] == NSRoundedBezelStyle) {
684 IntSize zoomedSize = buttonSizes()[controlSize];
685 zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
686 zoomedSize.setWidth(zoomedRect.width()); // Buttons don't ever constrain width, so the zoomed width can just be honored.
687 zoomedRect = inflateRect(zoomedRect, zoomedSize, buttonMargins(controlSize), zoomFactor);
691 case InnerSpinButtonPart: {
692 static const int stepperMargin[4] = { 0, 0, 0, 0 };
693 ControlSize controlSize = controlSizeFromPixelSize(stepperSizes(), zoomedRect.size(), zoomFactor);
694 IntSize zoomedSize = stepperSizes()[controlSize];
695 zoomedSize.setHeight(zoomedSize.height() * zoomFactor);
696 zoomedSize.setWidth(zoomedSize.width() * zoomFactor);
697 zoomedRect = inflateRect(zoomedRect, zoomedSize, stepperMargin, zoomFactor);
703 END_BLOCK_OBJC_EXCEPTIONS
706 void ThemeMac::paint(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) const
710 paintCheckbox(states, context, zoomedRect, zoomFactor, scrollView);
713 paintRadio(states, context, zoomedRect, zoomFactor, scrollView);
717 case SquareButtonPart:
718 paintButton(part, states, context, zoomedRect, zoomFactor, scrollView);
720 case InnerSpinButtonPart:
721 paintStepper(states, context, zoomedRect, zoomFactor, scrollView);