1/* 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2008, 2009 Google, Inc. 4 * Copyright (C) 2009 Kenneth Rohde Christiansen 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22// FIXME: we still need to figure out if passing a null view to the cell 23// drawing routines will work. I expect not, and if that's the case we'll have 24// to figure out something else. For now, at least leave the lines commented 25// in, but the procurement of the view if 0'd. 26 27#import "config.h" 28#import "RenderThemeChromiumMac.h" 29 30#import <Carbon/Carbon.h> 31#import <Cocoa/Cocoa.h> 32#import <math.h> 33 34#import "BitmapImage.h" 35#import "ChromiumBridge.h" 36#import "ColorMac.h" 37#import "CSSStyleSelector.h" 38#import "CSSValueKeywords.h" 39#import "Element.h" 40#import "FoundationExtras.h" 41#import "FrameView.h" 42#import "GraphicsContext.h" 43#import "HTMLInputElement.h" 44#import "HTMLMediaElement.h" 45#import "HTMLNames.h" 46#import "Image.h" 47#import "LocalCurrentGraphicsContext.h" 48#import "MediaControlElements.h" 49#import "RenderMedia.h" 50#import "RenderSlider.h" 51#import "RenderView.h" 52#import "SharedBuffer.h" 53#import "WebCoreSystemInterface.h" 54#import <wtf/RetainPtr.h> 55 56#ifdef BUILDING_ON_TIGER 57typedef int NSInteger; 58typedef unsigned NSUInteger; 59#endif 60 61using std::min; 62 63// The methods in this file are specific to the Mac OS X platform. 64 65// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. 66 67@interface WebCoreRenderThemeNotificationObserver : NSObject 68{ 69 WebCore::RenderTheme *_theme; 70} 71 72- (id)initWithTheme:(WebCore::RenderTheme *)theme; 73- (void)systemColorsDidChange:(NSNotification *)notification; 74 75@end 76 77@implementation WebCoreRenderThemeNotificationObserver 78 79- (id)initWithTheme:(WebCore::RenderTheme *)theme 80{ 81 [super init]; 82 _theme = theme; 83 84 return self; 85} 86 87- (void)systemColorsDidChange:(NSNotification *)notification 88{ 89 ASSERT([[notification name] isEqualToString:NSSystemColorsDidChangeNotification]); 90 _theme->platformColorsDidChange(); 91} 92 93@end 94 95namespace WebCore { 96 97using namespace HTMLNames; 98 99enum { 100 TopMargin, 101 RightMargin, 102 BottomMargin, 103 LeftMargin 104}; 105 106enum { 107 TopPadding, 108 RightPadding, 109 BottomPadding, 110 LeftPadding 111}; 112 113// In our Mac port, we don't define PLATFORM(MAC) and thus don't pick up the 114// |operator NSRect()| on WebCore::IntRect and FloatRect. This substitues for 115// that missing conversion operator. 116NSRect IntRectToNSRect(const IntRect & rect) 117{ 118 return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); 119} 120 121NSRect FloatRectToNSRect(const FloatRect & rect) 122{ 123 return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); 124} 125 126IntRect NSRectToIntRect(const NSRect & rect) 127{ 128 return IntRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 129} 130 131PassRefPtr<RenderTheme> RenderThemeChromiumMac::create() 132{ 133 return adoptRef(new RenderThemeChromiumMac); 134} 135 136PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 137{ 138 static RenderTheme* rt = RenderThemeChromiumMac::create().releaseRef(); 139 return rt; 140} 141 142RenderThemeChromiumMac::RenderThemeChromiumMac() 143 : m_isSliderThumbHorizontalPressed(false) 144 , m_isSliderThumbVerticalPressed(false) 145 , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]) 146{ 147 [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get() 148 selector:@selector(systemColorsDidChange:) 149 name:NSSystemColorsDidChangeNotification 150 object:nil]; 151} 152 153RenderThemeChromiumMac::~RenderThemeChromiumMac() 154{ 155 [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()]; 156} 157 158Color RenderThemeChromiumMac::platformActiveSelectionBackgroundColor() const 159{ 160 NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; 161 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); 162} 163 164Color RenderThemeChromiumMac::platformInactiveSelectionBackgroundColor() const 165{ 166 NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; 167 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); 168} 169 170Color RenderThemeChromiumMac::platformActiveListBoxSelectionBackgroundColor() const 171{ 172 NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; 173 return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); 174} 175 176Color RenderThemeChromiumMac::platformFocusRingColor() const 177{ 178 if (ChromiumBridge::layoutTestMode()) 179 return oldAquaFocusRingColor(); 180 181 return systemColor(CSSValueWebkitFocusRingColor); 182} 183 184static FontWeight toFontWeight(NSInteger appKitFontWeight) 185{ 186 ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); 187 if (appKitFontWeight > 14) 188 appKitFontWeight = 14; 189 else if (appKitFontWeight < 1) 190 appKitFontWeight = 1; 191 192 static FontWeight fontWeights[] = { 193 FontWeight100, 194 FontWeight100, 195 FontWeight200, 196 FontWeight300, 197 FontWeight400, 198 FontWeight500, 199 FontWeight600, 200 FontWeight600, 201 FontWeight700, 202 FontWeight800, 203 FontWeight800, 204 FontWeight900, 205 FontWeight900, 206 FontWeight900 207 }; 208 return fontWeights[appKitFontWeight - 1]; 209} 210 211void RenderThemeChromiumMac::systemFont(int cssValueId, FontDescription& fontDescription) const 212{ 213 static FontDescription systemFont; 214 static FontDescription smallSystemFont; 215 static FontDescription menuFont; 216 static FontDescription labelFont; 217 static FontDescription miniControlFont; 218 static FontDescription smallControlFont; 219 static FontDescription controlFont; 220 221 FontDescription* cachedDesc; 222 NSFont* font = nil; 223 switch (cssValueId) { 224 case CSSValueSmallCaption: 225 cachedDesc = &smallSystemFont; 226 if (!smallSystemFont.isAbsoluteSize()) 227 font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; 228 break; 229 case CSSValueMenu: 230 cachedDesc = &menuFont; 231 if (!menuFont.isAbsoluteSize()) 232 font = [NSFont menuFontOfSize:[NSFont systemFontSize]]; 233 break; 234 case CSSValueStatusBar: 235 cachedDesc = &labelFont; 236 if (!labelFont.isAbsoluteSize()) 237 font = [NSFont labelFontOfSize:[NSFont labelFontSize]]; 238 break; 239 case CSSValueWebkitMiniControl: 240 cachedDesc = &miniControlFont; 241 if (!miniControlFont.isAbsoluteSize()) 242 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]; 243 break; 244 case CSSValueWebkitSmallControl: 245 cachedDesc = &smallControlFont; 246 if (!smallControlFont.isAbsoluteSize()) 247 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; 248 break; 249 case CSSValueWebkitControl: 250 cachedDesc = &controlFont; 251 if (!controlFont.isAbsoluteSize()) 252 font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; 253 break; 254 default: 255 cachedDesc = &systemFont; 256 if (!systemFont.isAbsoluteSize()) 257 font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; 258 } 259 260 if (font) { 261 NSFontManager *fontManager = [NSFontManager sharedFontManager]; 262 cachedDesc->setIsAbsoluteSize(true); 263 cachedDesc->setGenericFamily(FontDescription::NoFamily); 264 cachedDesc->firstFamily().setFamily([font familyName]); 265 cachedDesc->setSpecifiedSize([font pointSize]); 266 cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font])); 267 cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask); 268 } 269 fontDescription = *cachedDesc; 270} 271 272static RGBA32 convertNSColorToColor(NSColor *color) 273{ 274 NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; 275 if (colorInColorSpace) { 276 static const double scaleFactor = nextafter(256.0, 0.0); 277 return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]), 278 static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]), 279 static_cast<int>(scaleFactor * [colorInColorSpace blueComponent])); 280 } 281 282 // This conversion above can fail if the NSColor in question is an NSPatternColor 283 // (as many system colors are). These colors are actually a repeating pattern 284 // not just a solid color. To work around this we simply draw a 1x1 image of 285 // the color and use that pixel's color. It might be better to use an average of 286 // the colors in the pattern instead. 287 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil 288 pixelsWide:1 289 pixelsHigh:1 290 bitsPerSample:8 291 samplesPerPixel:4 292 hasAlpha:YES 293 isPlanar:NO 294 colorSpaceName:NSCalibratedRGBColorSpace 295 bytesPerRow:4 296 bitsPerPixel:32]; 297 298 [NSGraphicsContext saveGraphicsState]; 299 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; 300 NSEraseRect(NSMakeRect(0, 0, 1, 1)); 301 [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)]; 302 [NSGraphicsContext restoreGraphicsState]; 303 304 NSUInteger pixel[4]; 305 [offscreenRep getPixel:pixel atX:0 y:0]; 306 307 [offscreenRep release]; 308 309 return makeRGB(pixel[0], pixel[1], pixel[2]); 310} 311 312static RGBA32 menuBackgroundColor() 313{ 314 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil 315 pixelsWide:1 316 pixelsHigh:1 317 bitsPerSample:8 318 samplesPerPixel:4 319 hasAlpha:YES 320 isPlanar:NO 321 colorSpaceName:NSCalibratedRGBColorSpace 322 bytesPerRow:4 323 bitsPerPixel:32]; 324 325 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]); 326 CGRect rect = CGRectMake(0, 0, 1, 1); 327 HIThemeMenuDrawInfo drawInfo; 328 drawInfo.version = 0; 329 drawInfo.menuType = kThemeMenuTypePopUp; 330 HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted); 331 332 NSUInteger pixel[4]; 333 [offscreenRep getPixel:pixel atX:0 y:0]; 334 335 [offscreenRep release]; 336 337 return makeRGB(pixel[0], pixel[1], pixel[2]); 338} 339 340void RenderThemeChromiumMac::platformColorsDidChange() 341{ 342 m_systemColorCache.clear(); 343 RenderTheme::platformColorsDidChange(); 344} 345 346Color RenderThemeChromiumMac::systemColor(int cssValueId) const 347{ 348 if (m_systemColorCache.contains(cssValueId)) 349 return m_systemColorCache.get(cssValueId); 350 351 Color color; 352 switch (cssValueId) { 353 case CSSValueActiveborder: 354 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); 355 break; 356 case CSSValueActivecaption: 357 color = convertNSColorToColor([NSColor windowFrameTextColor]); 358 break; 359 case CSSValueAppworkspace: 360 color = convertNSColorToColor([NSColor headerColor]); 361 break; 362 case CSSValueBackground: 363 // Use theme independent default 364 break; 365 case CSSValueButtonface: 366 // We use this value instead of NSColor's controlColor to avoid website incompatibilities. 367 // We may want to change this to use the NSColor in future. 368 color = 0xFFC0C0C0; 369 break; 370 case CSSValueButtonhighlight: 371 color = convertNSColorToColor([NSColor controlHighlightColor]); 372 break; 373 case CSSValueButtonshadow: 374 color = convertNSColorToColor([NSColor controlShadowColor]); 375 break; 376 case CSSValueButtontext: 377 color = convertNSColorToColor([NSColor controlTextColor]); 378 break; 379 case CSSValueCaptiontext: 380 color = convertNSColorToColor([NSColor textColor]); 381 break; 382 case CSSValueGraytext: 383 color = convertNSColorToColor([NSColor disabledControlTextColor]); 384 break; 385 case CSSValueHighlight: 386 color = convertNSColorToColor([NSColor selectedTextBackgroundColor]); 387 break; 388 case CSSValueHighlighttext: 389 color = convertNSColorToColor([NSColor selectedTextColor]); 390 break; 391 case CSSValueInactiveborder: 392 color = convertNSColorToColor([NSColor controlBackgroundColor]); 393 break; 394 case CSSValueInactivecaption: 395 color = convertNSColorToColor([NSColor controlBackgroundColor]); 396 break; 397 case CSSValueInactivecaptiontext: 398 color = convertNSColorToColor([NSColor textColor]); 399 break; 400 case CSSValueInfobackground: 401 // There is no corresponding NSColor for this so we use a hard coded value. 402 color = 0xFFFBFCC5; 403 break; 404 case CSSValueInfotext: 405 color = convertNSColorToColor([NSColor textColor]); 406 break; 407 case CSSValueMenu: 408 color = menuBackgroundColor(); 409 break; 410 case CSSValueMenutext: 411 color = convertNSColorToColor([NSColor selectedMenuItemTextColor]); 412 break; 413 case CSSValueScrollbar: 414 color = convertNSColorToColor([NSColor scrollBarColor]); 415 break; 416 case CSSValueText: 417 color = convertNSColorToColor([NSColor textColor]); 418 break; 419 case CSSValueThreeddarkshadow: 420 color = convertNSColorToColor([NSColor controlDarkShadowColor]); 421 break; 422 case CSSValueThreedshadow: 423 color = convertNSColorToColor([NSColor shadowColor]); 424 break; 425 case CSSValueThreedface: 426 // We use this value instead of NSColor's controlColor to avoid website incompatibilities. 427 // We may want to change this to use the NSColor in future. 428 color = 0xFFC0C0C0; 429 break; 430 case CSSValueThreedhighlight: 431 color = convertNSColorToColor([NSColor highlightColor]); 432 break; 433 case CSSValueThreedlightshadow: 434 color = convertNSColorToColor([NSColor controlLightHighlightColor]); 435 break; 436 case CSSValueWebkitFocusRingColor: 437 color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); 438 break; 439 case CSSValueWindow: 440 color = convertNSColorToColor([NSColor windowBackgroundColor]); 441 break; 442 case CSSValueWindowframe: 443 color = convertNSColorToColor([NSColor windowFrameColor]); 444 break; 445 case CSSValueWindowtext: 446 color = convertNSColorToColor([NSColor windowFrameTextColor]); 447 break; 448 } 449 450 if (!color.isValid()) 451 color = RenderTheme::systemColor(cssValueId); 452 453 if (color.isValid()) 454 m_systemColorCache.set(cssValueId, color.rgb()); 455 456 return color; 457} 458 459bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const BorderData& border, 460 const FillLayer& background, const Color& backgroundColor) const 461{ 462 if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) 463 return style->border() != border; 464 465 // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when 466 // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style 467 // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming 468 // is in effect we treat it like the control is styled. 469 if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f) 470 return true; 471 472 return RenderTheme::isControlStyled(style, border, background, backgroundColor); 473} 474 475// FIXME: Use the code from the old upstream version, before it was converted to the new theme API in r37731. 476void RenderThemeChromiumMac::adjustRepaintRect(const RenderObject* o, IntRect& r) 477{ 478 float zoomLevel = o->style()->effectiveZoom(); 479 480 switch (o->style()->appearance()) { 481 case CheckboxPart: { 482 // Since we query the prototype cell, we need to update its state to match. 483 setCheckboxCellState(o, r); 484 485 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox 486 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. 487 IntSize size = checkboxSizes()[[checkbox() controlSize]]; 488 size.setHeight(size.height() * zoomLevel); 489 size.setWidth(size.width() * zoomLevel); 490 r = inflateRect(r, size, checkboxMargins(), zoomLevel); 491 break; 492 } 493 case RadioPart: { 494 // Since we query the prototype cell, we need to update its state to match. 495 setRadioCellState(o, r); 496 497 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox 498 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. 499 IntSize size = radioSizes()[[radio() controlSize]]; 500 size.setHeight(size.height() * zoomLevel); 501 size.setWidth(size.width() * zoomLevel); 502 r = inflateRect(r, size, radioMargins(), zoomLevel); 503 break; 504 } 505 case PushButtonPart: 506 case DefaultButtonPart: 507 case ButtonPart: { 508 // Since we query the prototype cell, we need to update its state to match. 509 setButtonCellState(o, r); 510 511 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox 512 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. 513 if ([button() bezelStyle] == NSRoundedBezelStyle) { 514 IntSize size = buttonSizes()[[button() controlSize]]; 515 size.setHeight(size.height() * zoomLevel); 516 size.setWidth(r.width()); 517 r = inflateRect(r, size, buttonMargins(), zoomLevel); 518 } 519 break; 520 } 521 case MenulistPart: { 522 setPopupButtonCellState(o, r); 523 IntSize size = popupButtonSizes()[[popupButton() controlSize]]; 524 size.setHeight(size.height() * zoomLevel); 525 size.setWidth(r.width()); 526 r = inflateRect(r, size, popupButtonMargins(), zoomLevel); 527 break; 528 } 529 default: 530 break; 531 } 532} 533 534IntRect RenderThemeChromiumMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const 535{ 536 // Only do the inflation if the available width/height are too small. Otherwise try to 537 // fit the glow/check space into the available box's width/height. 538 int widthDelta = r.width() - (size.width() + margins[LeftMargin] * zoomLevel + margins[RightMargin] * zoomLevel); 539 int heightDelta = r.height() - (size.height() + margins[TopMargin] * zoomLevel + margins[BottomMargin] * zoomLevel); 540 IntRect result(r); 541 if (widthDelta < 0) { 542 result.setX(result.x() - margins[LeftMargin] * zoomLevel); 543 result.setWidth(result.width() - widthDelta); 544 } 545 if (heightDelta < 0) { 546 result.setY(result.y() - margins[TopMargin] * zoomLevel); 547 result.setHeight(result.height() - heightDelta); 548 } 549 return result; 550} 551 552void RenderThemeChromiumMac::updateCheckedState(NSCell* cell, const RenderObject* o) 553{ 554 bool oldIndeterminate = [cell state] == NSMixedState; 555 bool indeterminate = isIndeterminate(o); 556 bool checked = isChecked(o); 557 558 if (oldIndeterminate != indeterminate) { 559 [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)]; 560 return; 561 } 562 563 bool oldChecked = [cell state] == NSOnState; 564 if (checked != oldChecked) 565 [cell setState:checked ? NSOnState : NSOffState]; 566} 567 568void RenderThemeChromiumMac::updateEnabledState(NSCell* cell, const RenderObject* o) 569{ 570 bool oldEnabled = [cell isEnabled]; 571 bool enabled = isEnabled(o); 572 if (enabled != oldEnabled) 573 [cell setEnabled:enabled]; 574} 575 576void RenderThemeChromiumMac::updateFocusedState(NSCell* cell, const RenderObject* o) 577{ 578 bool oldFocused = [cell showsFirstResponder]; 579 bool focused = isFocused(o) && o->style()->outlineStyleIsAuto(); 580 if (focused != oldFocused) 581 [cell setShowsFirstResponder:focused]; 582} 583 584void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject* o) 585{ 586 bool oldPressed = [cell isHighlighted]; 587 bool pressed = (o->node() && o->node()->active()); 588 if (pressed != oldPressed) 589 [cell setHighlighted:pressed]; 590} 591 592// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 593int RenderThemeChromiumMac::baselinePosition(const RenderObject* o) const 594{ 595 if (!o->isBox()) 596 return 0; 597 598 if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) { 599 const RenderBox* box = toRenderBox(o); 600 return box->marginTop() + box->height() - 2 * o->style()->effectiveZoom(); // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. 601 } 602 return RenderTheme::baselinePosition(o); 603} 604 605bool RenderThemeChromiumMac::controlSupportsTints(const RenderObject* o) const 606{ 607 // An alternate way to implement this would be to get the appropriate cell object 608 // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of 609 // that would be that we would match AppKit behavior more closely, but a disadvantage 610 // would be that we would rely on an AppKit SPI method. 611 612 if (!isEnabled(o)) 613 return false; 614 615 // Checkboxes only have tint when checked. 616 if (o->style()->appearance() == CheckboxPart) 617 return isChecked(o); 618 619 // For now assume other controls have tint if enabled. 620 return true; 621} 622 623NSControlSize RenderThemeChromiumMac::controlSizeForFont(RenderStyle* style) const 624{ 625 int fontSize = style->fontSize(); 626 if (fontSize >= 16) 627 return NSRegularControlSize; 628 if (fontSize >= 11) 629 return NSSmallControlSize; 630 return NSMiniControlSize; 631} 632 633void RenderThemeChromiumMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel) 634{ 635 NSControlSize size; 636 if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) && 637 minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel)) 638 size = NSRegularControlSize; 639 else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) && 640 minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel)) 641 size = NSSmallControlSize; 642 else 643 size = NSMiniControlSize; 644 if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. 645 [cell setControlSize:size]; 646} 647 648IntSize RenderThemeChromiumMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const 649{ 650 if (style->effectiveZoom() != 1.0f) { 651 IntSize result = sizes[controlSizeForFont(style)]; 652 return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); 653 } 654 return sizes[controlSizeForFont(style)]; 655} 656 657IntSize RenderThemeChromiumMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const 658{ 659 if (style->effectiveZoom() != 1.0f) { 660 IntSize result = sizes[controlSizeForSystemFont(style)]; 661 return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); 662 } 663 return sizes[controlSizeForSystemFont(style)]; 664} 665 666void RenderThemeChromiumMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const 667{ 668 // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. 669 IntSize size = sizeForFont(style, sizes); 670 if (style->width().isIntrinsicOrAuto() && size.width() > 0) 671 style->setWidth(Length(size.width(), Fixed)); 672 if (style->height().isAuto() && size.height() > 0) 673 style->setHeight(Length(size.height(), Fixed)); 674} 675 676void RenderThemeChromiumMac::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const 677{ 678 FontDescription fontDescription; 679 fontDescription.setIsAbsoluteSize(true); 680 fontDescription.setGenericFamily(FontDescription::SerifFamily); 681 682 NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]]; 683 fontDescription.firstFamily().setFamily([font familyName]); 684 fontDescription.setComputedSize([font pointSize] * style->effectiveZoom()); 685 fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom()); 686 687 // Reset line height 688 style->setLineHeight(RenderStyle::initialLineHeight()); 689 690 if (style->setFontDescription(fontDescription)) 691 style->font().update(0); 692} 693 694NSControlSize RenderThemeChromiumMac::controlSizeForSystemFont(RenderStyle* style) const 695{ 696 int fontSize = style->fontSize(); 697 if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize]) 698 return NSRegularControlSize; 699 if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize]) 700 return NSSmallControlSize; 701 return NSMiniControlSize; 702} 703 704// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 705bool RenderThemeChromiumMac::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 706{ 707 LocalCurrentGraphicsContext localContext(paintInfo.context); 708 709 // Determine the width and height needed for the control and prepare the cell for painting. 710 setCheckboxCellState(o, r); 711 712 paintInfo.context->save(); 713 714 float zoomLevel = o->style()->effectiveZoom(); 715 716 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox 717 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. 718 NSButtonCell* checkbox = this->checkbox(); 719 IntSize size = checkboxSizes()[[checkbox controlSize]]; 720 size.setWidth(size.width() * zoomLevel); 721 size.setHeight(size.height() * zoomLevel); 722 IntRect inflatedRect = inflateRect(r, size, checkboxMargins(), zoomLevel); 723 724 if (zoomLevel != 1.0f) { 725 inflatedRect.setWidth(inflatedRect.width() / zoomLevel); 726 inflatedRect.setHeight(inflatedRect.height() / zoomLevel); 727 paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); 728 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 729 paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); 730 } 731 732 [checkbox drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil]; 733 [checkbox setControlView:nil]; 734 735 paintInfo.context->restore(); 736 737 return false; 738} 739 740// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 741const IntSize* RenderThemeChromiumMac::checkboxSizes() const 742{ 743 static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) }; 744 return sizes; 745} 746 747// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 748const int* RenderThemeChromiumMac::checkboxMargins() const 749{ 750 static const int margins[3][4] = 751 { 752 { 3, 4, 4, 2 }, 753 { 4, 3, 3, 3 }, 754 { 4, 3, 3, 3 }, 755 }; 756 return margins[[checkbox() controlSize]]; 757} 758 759// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 760void RenderThemeChromiumMac::setCheckboxCellState(const RenderObject* o, const IntRect& r) 761{ 762 NSButtonCell* checkbox = this->checkbox(); 763 764 // Set the control size based off the rectangle we're painting into. 765 setControlSize(checkbox, checkboxSizes(), r.size(), o->style()->effectiveZoom()); 766 767 // Update the various states we respond to. 768 updateCheckedState(checkbox, o); 769 updateEnabledState(checkbox, o); 770 updatePressedState(checkbox, o); 771 updateFocusedState(checkbox, o); 772} 773 774// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 775void RenderThemeChromiumMac::setCheckboxSize(RenderStyle* style) const 776{ 777 // If the width and height are both specified, then we have nothing to do. 778 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 779 return; 780 781 // Use the font size to determine the intrinsic width of the control. 782 setSizeFromFont(style, checkboxSizes()); 783} 784 785// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 786bool RenderThemeChromiumMac::paintRadio(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 787{ 788 LocalCurrentGraphicsContext localContext(paintInfo.context); 789 790 // Determine the width and height needed for the control and prepare the cell for painting. 791 setRadioCellState(o, r); 792 793 paintInfo.context->save(); 794 795 float zoomLevel = o->style()->effectiveZoom(); 796 797 // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox 798 // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. 799 NSButtonCell* radio = this->radio(); 800 IntSize size = radioSizes()[[radio controlSize]]; 801 size.setWidth(size.width() * zoomLevel); 802 size.setHeight(size.height() * zoomLevel); 803 IntRect inflatedRect = inflateRect(r, size, radioMargins(), zoomLevel); 804 805 if (zoomLevel != 1.0f) { 806 inflatedRect.setWidth(inflatedRect.width() / zoomLevel); 807 inflatedRect.setHeight(inflatedRect.height() / zoomLevel); 808 paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); 809 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 810 paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); 811 } 812 813 [radio drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil]; 814 [radio setControlView:nil]; 815 816 paintInfo.context->restore(); 817 818 return false; 819} 820 821// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 822const IntSize* RenderThemeChromiumMac::radioSizes() const 823{ 824 static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) }; 825 return sizes; 826} 827 828// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 829const int* RenderThemeChromiumMac::radioMargins() const 830{ 831 static const int margins[3][4] = 832 { 833 { 2, 2, 4, 2 }, 834 { 3, 2, 3, 2 }, 835 { 1, 0, 2, 0 }, 836 }; 837 return margins[[radio() controlSize]]; 838} 839 840// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 841void RenderThemeChromiumMac::setRadioCellState(const RenderObject* o, const IntRect& r) 842{ 843 NSButtonCell* radio = this->radio(); 844 845 // Set the control size based off the rectangle we're painting into. 846 setControlSize(radio, radioSizes(), r.size(), o->style()->effectiveZoom()); 847 848 // Update the various states we respond to. 849 updateCheckedState(radio, o); 850 updateEnabledState(radio, o); 851 updatePressedState(radio, o); 852 updateFocusedState(radio, o); 853} 854 855// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 856void RenderThemeChromiumMac::setRadioSize(RenderStyle* style) const 857{ 858 // If the width and height are both specified, then we have nothing to do. 859 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 860 return; 861 862 // Use the font size to determine the intrinsic width of the control. 863 setSizeFromFont(style, radioSizes()); 864} 865 866// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 867void RenderThemeChromiumMac::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const 868{ 869 // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large 870 // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is 871 // by definition constrained, since we select mini only for small cramped environments. 872 // This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent 873 // padding. 874 const int padding = 8 * style->effectiveZoom(); 875 style->setPaddingLeft(Length(padding, Fixed)); 876 style->setPaddingRight(Length(padding, Fixed)); 877 style->setPaddingTop(Length(0, Fixed)); 878 style->setPaddingBottom(Length(0, Fixed)); 879} 880 881// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 882void RenderThemeChromiumMac::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 883{ 884 // There are three appearance constants for buttons. 885 // (1) Push-button is the constant for the default Aqua system button. Push buttons will not scale vertically and will not allow 886 // custom fonts or colors. <input>s use this constant. This button will allow custom colors and font weights/variants but won't 887 // scale vertically. 888 // (2) square-button is the constant for the square button. This button will allow custom fonts and colors and will scale vertically. 889 // (3) Button is the constant that means "pick the best button as appropriate." <button>s use this constant. This button will 890 // also scale vertically and allow custom fonts and colors. It will attempt to use Aqua if possible and will make this determination 891 // solely on the rectangle of the control. 892 893 // Determine our control size based off our font. 894 NSControlSize controlSize = controlSizeForFont(style); 895 896 if (style->appearance() == PushButtonPart) { 897 // Ditch the border. 898 style->resetBorder(); 899 900 // Height is locked to auto. 901 style->setHeight(Length(Auto)); 902 903 // White-space is locked to pre 904 style->setWhiteSpace(PRE); 905 906 // Set the button's vertical size. 907 setButtonSize(style); 908 909 // Add in the padding that we'd like to use. 910 setButtonPaddingFromControlSize(style, controlSize); 911 912 // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out 913 // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate 914 // system font for the control size instead. 915 setFontFromControlSize(selector, style, controlSize); 916 } else { 917 // Set a min-height so that we can't get smaller than the mini button. 918 style->setMinHeight(Length(static_cast<int>(15 * style->effectiveZoom()), Fixed)); 919 920 // Reset the top and bottom borders. 921 style->resetBorderTop(); 922 style->resetBorderBottom(); 923 } 924 925 style->setBoxShadow(0); 926} 927 928// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 929const IntSize* RenderThemeChromiumMac::buttonSizes() const 930{ 931 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; 932 return sizes; 933} 934 935// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 936const int* RenderThemeChromiumMac::buttonMargins() const 937{ 938 static const int margins[3][4] = 939 { 940 { 4, 6, 7, 6 }, 941 { 4, 5, 6, 5 }, 942 { 0, 1, 1, 1 }, 943 }; 944 return margins[[button() controlSize]]; 945} 946 947// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 948void RenderThemeChromiumMac::setButtonSize(RenderStyle* style) const 949{ 950 // If the width and height are both specified, then we have nothing to do. 951 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 952 return; 953 954 // Use the font size to determine the intrinsic width of the control. 955 setSizeFromFont(style, buttonSizes()); 956} 957 958// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 959void RenderThemeChromiumMac::setButtonCellState(const RenderObject* o, const IntRect& r) 960{ 961 NSButtonCell* button = this->button(); 962 963 // Set the control size based off the rectangle we're painting into. 964 if (o->style()->appearance() == SquareButtonPart || 965 r.height() > buttonSizes()[NSRegularControlSize].height() * o->style()->effectiveZoom()) { 966 // Use the square button 967 if ([button bezelStyle] != NSShadowlessSquareBezelStyle) 968 [button setBezelStyle:NSShadowlessSquareBezelStyle]; 969 } else if ([button bezelStyle] != NSRoundedBezelStyle) 970 [button setBezelStyle:NSRoundedBezelStyle]; 971 972 setControlSize(button, buttonSizes(), r.size(), o->style()->effectiveZoom()); 973 974 NSWindow *window = [nil window]; 975 BOOL isDefaultButton = (isDefault(o) && [window isKeyWindow]); 976 [button setKeyEquivalent:(isDefaultButton ? @"\r" : @"")]; 977 978 // Update the various states we respond to. 979 updateCheckedState(button, o); 980 updateEnabledState(button, o); 981 updatePressedState(button, o); 982 updateFocusedState(button, o); 983} 984 985// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 986bool RenderThemeChromiumMac::paintButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 987{ 988 NSButtonCell* button = this->button(); 989 LocalCurrentGraphicsContext localContext(paintInfo.context); 990 991 // Determine the width and height needed for the control and prepare the cell for painting. 992 setButtonCellState(o, r); 993 994 paintInfo.context->save(); 995 996 // We inflate the rect as needed to account for padding included in the cell to accommodate the button 997 // shadow. We don't consider this part of the bounds of the control in WebKit. 998 float zoomLevel = o->style()->effectiveZoom(); 999 IntSize size = buttonSizes()[[button controlSize]]; 1000 size.setWidth(r.width()); 1001 size.setHeight(size.height() * zoomLevel); 1002 IntRect inflatedRect = r; 1003 if ([button bezelStyle] == NSRoundedBezelStyle) { 1004 // Center the button within the available space. 1005 if (inflatedRect.height() > size.height()) { 1006 inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2); 1007 inflatedRect.setHeight(size.height()); 1008 } 1009 1010 // Now inflate it to account for the shadow. 1011 inflatedRect = inflateRect(inflatedRect, size, buttonMargins(), zoomLevel); 1012 1013 if (zoomLevel != 1.0f) { 1014 inflatedRect.setWidth(inflatedRect.width() / zoomLevel); 1015 inflatedRect.setHeight(inflatedRect.height() / zoomLevel); 1016 paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); 1017 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 1018 paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); 1019 } 1020 } 1021 1022 NSView *view = nil; 1023 NSWindow *window = [view window]; 1024 NSButtonCell *previousDefaultButtonCell = [window defaultButtonCell]; 1025 1026 if (isDefault(o) && [window isKeyWindow]) { 1027 [window setDefaultButtonCell:button]; 1028 wkAdvanceDefaultButtonPulseAnimation(button); 1029 } else if ([previousDefaultButtonCell isEqual:button]) 1030 [window setDefaultButtonCell:nil]; 1031 1032 [button drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:view]; 1033 [button setControlView:nil]; 1034 1035 if (![previousDefaultButtonCell isEqual:button]) 1036 [window setDefaultButtonCell:previousDefaultButtonCell]; 1037 1038 paintInfo.context->restore(); 1039 1040 return false; 1041} 1042 1043bool RenderThemeChromiumMac::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1044{ 1045 LocalCurrentGraphicsContext localContext(paintInfo.context); 1046 wkDrawBezeledTextFieldCell(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o)); 1047 return false; 1048} 1049 1050void RenderThemeChromiumMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const 1051{ 1052} 1053 1054bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1055{ 1056 if (paintInfo.context->paintingDisabled()) 1057 return true; 1058 1059 LocalCurrentGraphicsContext localContext(paintInfo.context); 1060 wkDrawCapsLockIndicator(paintInfo.context->platformContext(), r); 1061 1062 return false; 1063} 1064 1065bool RenderThemeChromiumMac::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1066{ 1067 LocalCurrentGraphicsContext localContext(paintInfo.context); 1068 wkDrawBezeledTextArea(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o)); 1069 return false; 1070} 1071 1072void RenderThemeChromiumMac::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const 1073{ 1074} 1075 1076const int* RenderThemeChromiumMac::popupButtonMargins() const 1077{ 1078 static const int margins[3][4] = 1079 { 1080 { 0, 3, 1, 3 }, 1081 { 0, 3, 2, 3 }, 1082 { 0, 1, 0, 1 } 1083 }; 1084 return margins[[popupButton() controlSize]]; 1085} 1086 1087const IntSize* RenderThemeChromiumMac::popupButtonSizes() const 1088{ 1089 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; 1090 return sizes; 1091} 1092 1093const int* RenderThemeChromiumMac::popupButtonPadding(NSControlSize size) const 1094{ 1095 static const int padding[3][4] = 1096 { 1097 { 2, 26, 3, 8 }, 1098 { 2, 23, 3, 8 }, 1099 { 2, 22, 3, 10 } 1100 }; 1101 return padding[size]; 1102} 1103 1104bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1105{ 1106 LocalCurrentGraphicsContext localContext(paintInfo.context); 1107 1108 setPopupButtonCellState(o, r); 1109 1110 NSPopUpButtonCell* popupButton = this->popupButton(); 1111 1112 float zoomLevel = o->style()->effectiveZoom(); 1113 IntSize size = popupButtonSizes()[[popupButton controlSize]]; 1114 size.setHeight(size.height() * zoomLevel); 1115 size.setWidth(r.width()); 1116 1117 // Now inflate it to account for the shadow. 1118 IntRect inflatedRect = r; 1119 if (r.width() >= minimumMenuListSize(o->style())) 1120 inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel); 1121 1122 paintInfo.context->save(); 1123 1124#ifndef BUILDING_ON_TIGER 1125 // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect 1126 paintInfo.context->clip(inflatedRect); 1127#endif 1128 1129 if (zoomLevel != 1.0f) { 1130 inflatedRect.setWidth(inflatedRect.width() / zoomLevel); 1131 inflatedRect.setHeight(inflatedRect.height() / zoomLevel); 1132 paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); 1133 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 1134 paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); 1135 } 1136 1137 [popupButton drawWithFrame:IntRectToNSRect(inflatedRect) inView:nil]; 1138 [popupButton setControlView:nil]; 1139 1140 paintInfo.context->restore(); 1141 1142 return false; 1143} 1144 1145static const float baseFontSize = 11.0f; 1146static const float baseArrowHeight = 4.0f; 1147static const float baseArrowWidth = 5.0f; 1148static const float baseSpaceBetweenArrows = 2.0f; 1149static const int arrowPaddingLeft = 6; 1150static const int arrowPaddingRight = 6; 1151static const int paddingBeforeSeparator = 4; 1152static const int baseBorderRadius = 5; 1153static const int styledPopupPaddingLeft = 8; 1154static const int styledPopupPaddingTop = 1; 1155static const int styledPopupPaddingBottom = 2; 1156 1157static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) 1158{ 1159 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; 1160 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; 1161 float a = inData[0]; 1162 int i = 0; 1163 for (i = 0; i < 4; i++) 1164 outData[i] = (1.0f - a) * dark[i] + a * light[i]; 1165} 1166 1167static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) 1168{ 1169 static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; 1170 static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; 1171 float a = inData[0]; 1172 int i = 0; 1173 for (i = 0; i < 4; i++) 1174 outData[i] = (1.0f - a) * dark[i] + a * light[i]; 1175} 1176 1177static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) 1178{ 1179 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; 1180 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 1181 float a = inData[0]; 1182 int i = 0; 1183 for (i = 0; i < 4; i++) 1184 outData[i] = (1.0f - a) * dark[i] + a * light[i]; 1185} 1186 1187static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) 1188{ 1189 static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f }; 1190 static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f }; 1191 float a = inData[0]; 1192 int i = 0; 1193 for (i = 0; i < 4; i++) 1194 outData[i] = (1.0f - a) * dark[i] + a * light[i]; 1195} 1196 1197void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1198{ 1199 CGContextRef context = paintInfo.context->platformContext(); 1200 1201 paintInfo.context->save(); 1202 1203 int radius = o->style()->borderTopLeftRadius().width(); 1204 1205 RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); 1206 1207 FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); 1208 struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; 1209 RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); 1210 RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false)); 1211 1212 FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); 1213 struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; 1214 RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); 1215 RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false)); 1216 1217 struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; 1218 RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); 1219 RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false)); 1220 1221 RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); 1222 1223 RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false)); 1224 paintInfo.context->save(); 1225 CGContextClipToRect(context, r); 1226 paintInfo.context->addRoundedRectClip(r, 1227 o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), 1228 o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); 1229 CGContextDrawShading(context, mainShading.get()); 1230 paintInfo.context->restore(); 1231 1232 paintInfo.context->save(); 1233 CGContextClipToRect(context, topGradient); 1234 paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), 1235 o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), 1236 IntSize(), IntSize()); 1237 CGContextDrawShading(context, topShading.get()); 1238 paintInfo.context->restore(); 1239 1240 paintInfo.context->save(); 1241 CGContextClipToRect(context, bottomGradient); 1242 paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), 1243 IntSize(), IntSize(), 1244 o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); 1245 CGContextDrawShading(context, bottomShading.get()); 1246 paintInfo.context->restore(); 1247 1248 paintInfo.context->save(); 1249 CGContextClipToRect(context, r); 1250 paintInfo.context->addRoundedRectClip(r, 1251 o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), 1252 o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); 1253 CGContextDrawShading(context, leftShading.get()); 1254 CGContextDrawShading(context, rightShading.get()); 1255 paintInfo.context->restore(); 1256 1257 paintInfo.context->restore(); 1258} 1259 1260bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1261{ 1262 paintInfo.context->save(); 1263 1264 IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(), 1265 r.y() + o->style()->borderTopWidth(), 1266 r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(), 1267 r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth()); 1268 // Draw the gradients to give the styled popup menu a button appearance 1269 paintMenuListButtonGradients(o, paintInfo, bounds); 1270 1271 // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds 1272 float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows)); 1273 float centerY = bounds.y() + bounds.height() / 2.0f; 1274 float arrowHeight = baseArrowHeight * fontScale; 1275 float arrowWidth = baseArrowWidth * fontScale; 1276 float leftEdge = bounds.right() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; 1277 float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale; 1278 1279 if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) 1280 return false; 1281 1282 paintInfo.context->setFillColor(o->style()->color()); 1283 paintInfo.context->setStrokeStyle(NoStroke); 1284 1285 FloatPoint arrow1[3]; 1286 arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f); 1287 arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f); 1288 arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight); 1289 1290 // Draw the top arrow 1291 paintInfo.context->drawConvexPolygon(3, arrow1, true); 1292 1293 FloatPoint arrow2[3]; 1294 arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f); 1295 arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f); 1296 arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight); 1297 1298 // Draw the bottom arrow 1299 paintInfo.context->drawConvexPolygon(3, arrow2, true); 1300 1301 Color leftSeparatorColor(0, 0, 0, 40); 1302 Color rightSeparatorColor(255, 255, 255, 40); 1303 1304 // FIXME: Should the separator thickness and space be scaled up by fontScale? 1305 int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin. 1306 int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round? 1307 1308 // Draw the separator to the left of the arrows 1309 paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin. 1310 paintInfo.context->setStrokeStyle(SolidStroke); 1311 paintInfo.context->setStrokeColor(leftSeparatorColor); 1312 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), 1313 IntPoint(leftEdgeOfSeparator, bounds.bottom())); 1314 1315 paintInfo.context->setStrokeColor(rightSeparatorColor); 1316 paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), 1317 IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); 1318 1319 paintInfo.context->restore(); 1320 return false; 1321} 1322 1323static const IntSize* menuListButtonSizes() 1324{ 1325 static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; 1326 return sizes; 1327} 1328 1329void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1330{ 1331 NSControlSize controlSize = controlSizeForFont(style); 1332 1333 style->resetBorder(); 1334 style->resetPadding(); 1335 1336 // Height is locked to auto. 1337 style->setHeight(Length(Auto)); 1338 1339 // White-space is locked to pre 1340 style->setWhiteSpace(PRE); 1341 1342 // Set the foreground color to black or gray when we have the aqua look. 1343 // Cast to RGB32 is to work around a compiler bug. 1344 style->setColor(e && e->isEnabledFormControl() ? static_cast<RGBA32>(Color::black) : Color::darkGray); 1345 1346 // Set the button's vertical size. 1347 setSizeFromFont(style, menuListButtonSizes()); 1348 1349 // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out 1350 // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate 1351 // system font for the control size instead. 1352 setFontFromControlSize(selector, style, controlSize); 1353 1354 style->setBoxShadow(0); 1355} 1356 1357int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const 1358{ 1359 if (style->appearance() == MenulistPart) 1360 return popupButtonPadding(controlSizeForFont(style))[LeftPadding] * style->effectiveZoom(); 1361 if (style->appearance() == MenulistButtonPart) 1362 return styledPopupPaddingLeft * style->effectiveZoom(); 1363 return 0; 1364} 1365 1366int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const 1367{ 1368 if (style->appearance() == MenulistPart) 1369 return popupButtonPadding(controlSizeForFont(style))[RightPadding] * style->effectiveZoom(); 1370 if (style->appearance() == MenulistButtonPart) { 1371 float fontScale = style->fontSize() / baseFontSize; 1372 float arrowWidth = baseArrowWidth * fontScale; 1373 return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom())); 1374 } 1375 return 0; 1376} 1377 1378int RenderThemeChromiumMac::popupInternalPaddingTop(RenderStyle* style) const 1379{ 1380 if (style->appearance() == MenulistPart) 1381 return popupButtonPadding(controlSizeForFont(style))[TopPadding] * style->effectiveZoom(); 1382 if (style->appearance() == MenulistButtonPart) 1383 return styledPopupPaddingTop * style->effectiveZoom(); 1384 return 0; 1385} 1386 1387int RenderThemeChromiumMac::popupInternalPaddingBottom(RenderStyle* style) const 1388{ 1389 if (style->appearance() == MenulistPart) 1390 return popupButtonPadding(controlSizeForFont(style))[BottomPadding] * style->effectiveZoom(); 1391 if (style->appearance() == MenulistButtonPart) 1392 return styledPopupPaddingBottom * style->effectiveZoom(); 1393 return 0; 1394} 1395 1396void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1397{ 1398 float fontScale = style->fontSize() / baseFontSize; 1399 1400 style->resetPadding(); 1401 style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up? 1402 1403 const int minHeight = 15; 1404 style->setMinHeight(Length(minHeight, Fixed)); 1405 1406 style->setLineHeight(RenderStyle::initialLineHeight()); 1407} 1408 1409void RenderThemeChromiumMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r) 1410{ 1411 NSPopUpButtonCell* popupButton = this->popupButton(); 1412 1413 // Set the control size based off the rectangle we're painting into. 1414 setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom()); 1415 1416 // Update the various states we respond to. 1417 updateCheckedState(popupButton, o); 1418 updateEnabledState(popupButton, o); 1419 updatePressedState(popupButton, o); 1420 updateFocusedState(popupButton, o); 1421} 1422 1423const IntSize* RenderThemeChromiumMac::menuListSizes() const 1424{ 1425 static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) }; 1426 return sizes; 1427} 1428 1429int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const 1430{ 1431 return sizeForSystemFont(style, menuListSizes()).width(); 1432} 1433 1434static const int trackWidth = 5; 1435static const int trackRadius = 2; 1436 1437void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1438{ 1439 style->setBoxShadow(0); 1440} 1441 1442bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1443{ 1444 IntRect bounds = r; 1445 float zoomLevel = o->style()->effectiveZoom(); 1446 float zoomedTrackWidth = trackWidth * zoomLevel; 1447 1448 if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) { 1449 bounds.setHeight(zoomedTrackWidth); 1450 bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2); 1451 } else if (o->style()->appearance() == SliderVerticalPart) { 1452 bounds.setWidth(zoomedTrackWidth); 1453 bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2); 1454 } 1455 1456 LocalCurrentGraphicsContext localContext(paintInfo.context); 1457 CGContextRef context = paintInfo.context->platformContext(); 1458 RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); 1459 1460 paintInfo.context->save(); 1461 CGContextClipToRect(context, bounds); 1462 1463 struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL }; 1464 RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); 1465 RetainPtr<CGShadingRef> mainShading; 1466 if (o->style()->appearance() == SliderVerticalPart) 1467 mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false)); 1468 else 1469 mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false)); 1470 1471 IntSize radius(trackRadius, trackRadius); 1472 paintInfo.context->addRoundedRectClip(bounds, 1473 radius, radius, 1474 radius, radius); 1475 CGContextDrawShading(context, mainShading.get()); 1476 paintInfo.context->restore(); 1477 1478 return false; 1479} 1480 1481void RenderThemeChromiumMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1482{ 1483 style->setBoxShadow(0); 1484} 1485 1486static const float verticalSliderHeightPadding = 0.1f; 1487 1488bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1489{ 1490 ASSERT(o->parent()->isSlider()); 1491 1492 NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart 1493 ? sliderThumbVertical() 1494 : sliderThumbHorizontal(); 1495 1496 LocalCurrentGraphicsContext localContext(paintInfo.context); 1497 1498 // Update the various states we respond to. 1499 updateEnabledState(sliderThumbCell, o->parent()); 1500 updateFocusedState(sliderThumbCell, o->parent()); 1501 1502 // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it. 1503 bool oldPressed; 1504 if (o->style()->appearance() == SliderThumbVerticalPart) 1505 oldPressed = m_isSliderThumbVerticalPressed; 1506 else 1507 oldPressed = m_isSliderThumbHorizontalPressed; 1508 1509 bool pressed = toRenderSlider(o->parent())->inDragMode(); 1510 1511 if (o->style()->appearance() == SliderThumbVerticalPart) 1512 m_isSliderThumbVerticalPressed = pressed; 1513 else 1514 m_isSliderThumbHorizontalPressed = pressed; 1515 1516 if (pressed != oldPressed) { 1517 if (pressed) 1518 [sliderThumbCell startTrackingAt:NSPoint() inView:nil]; 1519 else 1520 [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES]; 1521 } 1522 1523 FloatRect bounds = r; 1524 // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider. 1525 if (o->style()->appearance() == SliderThumbVerticalPart) 1526 bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom()); 1527 1528 paintInfo.context->save(); 1529 float zoomLevel = o->style()->effectiveZoom(); 1530 1531 FloatRect unzoomedRect = bounds; 1532 if (zoomLevel != 1.0f) { 1533 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); 1534 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); 1535 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); 1536 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 1537 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); 1538 } 1539 1540 [sliderThumbCell drawWithFrame:FloatRectToNSRect(unzoomedRect) inView:nil]; 1541 [sliderThumbCell setControlView:nil]; 1542 1543 paintInfo.context->restore(); 1544 1545 return false; 1546} 1547 1548const int sliderThumbWidth = 15; 1549const int sliderThumbHeight = 15; 1550const int mediaSliderThumbWidth = 13; 1551const int mediaSliderThumbHeight = 14; 1552 1553void RenderThemeChromiumMac::adjustSliderThumbSize(RenderObject* o) const 1554{ 1555 float zoomLevel = o->style()->effectiveZoom(); 1556 if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { 1557 o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); 1558 o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); 1559 } else if (o->style()->appearance() == MediaSliderThumbPart) { 1560 o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed)); 1561 o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed)); 1562 } 1563} 1564 1565bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1566{ 1567 NSSearchFieldCell* search = this->search(); 1568 LocalCurrentGraphicsContext localContext(paintInfo.context); 1569 1570 setSearchCellState(o, r); 1571 1572 paintInfo.context->save(); 1573 1574 float zoomLevel = o->style()->effectiveZoom(); 1575 1576 IntRect unzoomedRect = r; 1577 1578 if (zoomLevel != 1.0f) { 1579 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); 1580 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); 1581 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); 1582 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 1583 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); 1584 } 1585 1586 // Set the search button to nil before drawing. Then reset it so we can draw it later. 1587 [search setSearchButtonCell:nil]; 1588 1589 [search drawWithFrame:NSRect(IntRectToNSRect(unzoomedRect)) inView:nil]; 1590#ifdef BUILDING_ON_TIGER 1591 if ([search showsFirstResponder]) 1592 wkDrawTextFieldCellFocusRing(search, NSRect(unzoomedRect)); 1593#endif 1594 1595 [search setControlView:nil]; 1596 [search resetSearchButtonCell]; 1597 1598 paintInfo.context->restore(); 1599 1600 return false; 1601} 1602 1603void RenderThemeChromiumMac::setSearchCellState(RenderObject* o, const IntRect& r) 1604{ 1605 NSSearchFieldCell* search = this->search(); 1606 1607 [search setControlSize:controlSizeForFont(o->style())]; 1608 1609 // Update the various states we respond to. 1610 updateEnabledState(search, o); 1611 updateFocusedState(search, o); 1612} 1613 1614const IntSize* RenderThemeChromiumMac::searchFieldSizes() const 1615{ 1616 static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) }; 1617 return sizes; 1618} 1619 1620void RenderThemeChromiumMac::setSearchFieldSize(RenderStyle* style) const 1621{ 1622 // If the width and height are both specified, then we have nothing to do. 1623 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 1624 return; 1625 1626 // Use the font size to determine the intrinsic width of the control. 1627 setSizeFromFont(style, searchFieldSizes()); 1628} 1629 1630void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1631{ 1632 // Override border. 1633 style->resetBorder(); 1634 const short borderWidth = 2 * style->effectiveZoom(); 1635 style->setBorderLeftWidth(borderWidth); 1636 style->setBorderLeftStyle(INSET); 1637 style->setBorderRightWidth(borderWidth); 1638 style->setBorderRightStyle(INSET); 1639 style->setBorderBottomWidth(borderWidth); 1640 style->setBorderBottomStyle(INSET); 1641 style->setBorderTopWidth(borderWidth); 1642 style->setBorderTopStyle(INSET); 1643 1644 // Override height. 1645 style->setHeight(Length(Auto)); 1646 setSearchFieldSize(style); 1647 1648 // Override padding size to match AppKit text positioning. 1649 const int padding = 1 * style->effectiveZoom(); 1650 style->setPaddingLeft(Length(padding, Fixed)); 1651 style->setPaddingRight(Length(padding, Fixed)); 1652 style->setPaddingTop(Length(padding, Fixed)); 1653 style->setPaddingBottom(Length(padding, Fixed)); 1654 1655 NSControlSize controlSize = controlSizeForFont(style); 1656 setFontFromControlSize(selector, style, controlSize); 1657 1658 style->setBoxShadow(0); 1659} 1660 1661bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1662{ 1663 LocalCurrentGraphicsContext localContext(paintInfo.context); 1664 1665 Node* input = o->node()->shadowAncestorNode(); 1666 setSearchCellState(input->renderer(), r); 1667 1668 NSSearchFieldCell* search = this->search(); 1669 1670 updatePressedState([search cancelButtonCell], o); 1671 1672 paintInfo.context->save(); 1673 1674 float zoomLevel = o->style()->effectiveZoom(); 1675 1676 NSRect bounds = [search cancelButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; 1677 1678 IntRect unzoomedRect(NSRectToIntRect(bounds)); 1679 if (zoomLevel != 1.0f) { 1680 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); 1681 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); 1682 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); 1683 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 1684 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); 1685 } 1686 1687 [[search cancelButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil]; 1688 [[search cancelButtonCell] setControlView:nil]; 1689 1690 paintInfo.context->restore(); 1691 return false; 1692} 1693 1694const IntSize* RenderThemeChromiumMac::cancelButtonSizes() const 1695{ 1696 static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) }; 1697 return sizes; 1698} 1699 1700void RenderThemeChromiumMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1701{ 1702 IntSize size = sizeForSystemFont(style, cancelButtonSizes()); 1703 style->setWidth(Length(size.width(), Fixed)); 1704 style->setHeight(Length(size.height(), Fixed)); 1705 style->setBoxShadow(0); 1706} 1707 1708const IntSize* RenderThemeChromiumMac::resultsButtonSizes() const 1709{ 1710 static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) }; 1711 return sizes; 1712} 1713 1714static const int emptyResultsOffset = 9; 1715void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1716{ 1717 IntSize size = sizeForSystemFont(style, resultsButtonSizes()); 1718 style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); 1719 style->setHeight(Length(size.height(), Fixed)); 1720 style->setBoxShadow(0); 1721} 1722 1723bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1724{ 1725 return false; 1726} 1727 1728void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1729{ 1730 IntSize size = sizeForSystemFont(style, resultsButtonSizes()); 1731 style->setWidth(Length(size.width(), Fixed)); 1732 style->setHeight(Length(size.height(), Fixed)); 1733 style->setBoxShadow(0); 1734} 1735 1736bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1737{ 1738 LocalCurrentGraphicsContext localContext(paintInfo.context); 1739 1740 Node* input = o->node()->shadowAncestorNode(); 1741 setSearchCellState(input->renderer(), r); 1742 1743 NSSearchFieldCell* search = this->search(); 1744 1745 if ([search searchMenuTemplate] != nil) 1746 [search setSearchMenuTemplate:nil]; 1747 1748 NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; 1749 [[search searchButtonCell] drawWithFrame:bounds inView:nil]; 1750 [[search searchButtonCell] setControlView:nil]; 1751 return false; 1752} 1753 1754static const int resultsArrowWidth = 5; 1755void RenderThemeChromiumMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 1756{ 1757 IntSize size = sizeForSystemFont(style, resultsButtonSizes()); 1758 style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); 1759 style->setHeight(Length(size.height(), Fixed)); 1760 style->setBoxShadow(0); 1761} 1762 1763bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1764{ 1765 LocalCurrentGraphicsContext localContext(paintInfo.context); 1766 1767 Node* input = o->node()->shadowAncestorNode(); 1768 setSearchCellState(input->renderer(), r); 1769 1770 NSSearchFieldCell* search = this->search(); 1771 1772 if (![search searchMenuTemplate]) 1773 [search setSearchMenuTemplate:searchMenuTemplate()]; 1774 1775 paintInfo.context->save(); 1776 1777 float zoomLevel = o->style()->effectiveZoom(); 1778 1779 NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; 1780 1781 IntRect unzoomedRect(NSRectToIntRect(bounds)); 1782 if (zoomLevel != 1.0f) { 1783 unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); 1784 unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); 1785 paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); 1786 paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); 1787 paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); 1788 } 1789 1790 [[search searchButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil]; 1791 [[search searchButtonCell] setControlView:nil]; 1792 1793 paintInfo.context->restore(); 1794 1795 return false; 1796} 1797 1798#if ENABLE(VIDEO) 1799// FIXME: This enum is lifted from RenderThemeMac.mm We need to decide which theme to use for the default controls, or decide to avoid wkDrawMediaUIPart and render our own. 1800typedef enum { 1801 MediaControllerThemeClassic = 1, 1802 MediaControllerThemeQT = 2 1803} MediaControllerThemeStyle; 1804 1805enum WKMediaControllerThemeState { 1806 MediaUIPartDisabledFlag = 1 << 0, 1807 MediaUIPartPressedFlag = 1 << 1, 1808 MediaUIPartDrawEndCapsFlag = 1 << 3, 1809}; 1810#endif 1811 1812bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1813{ 1814#if ENABLE(VIDEO) 1815 Node* node = o->node(); 1816 if (!node) 1817 return false; 1818 1819 LocalCurrentGraphicsContext localContext(paintInfo.context); 1820 wkDrawMediaUIPart(MediaFullscreenButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, 1821 node->active() ? MediaUIPartPressedFlag : 0); 1822#endif 1823 return false; 1824} 1825 1826bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1827{ 1828#if ENABLE(VIDEO) 1829 Node* node = o->node(); 1830 Node* mediaNode = node ? node->shadowAncestorNode() : 0; 1831 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) 1832 return false; 1833 1834 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); 1835 if (!mediaElement) 1836 return false; 1837 1838 LocalCurrentGraphicsContext localContext(paintInfo.context); 1839 wkDrawMediaUIPart(mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, 1840 node->active() ? MediaUIPartPressedFlag : 0); 1841#endif 1842 return false; 1843} 1844 1845bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1846{ 1847#if ENABLE(VIDEO) 1848 Node* node = o->node(); 1849 Node* mediaNode = node ? node->shadowAncestorNode() : 0; 1850 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) 1851 return false; 1852 1853 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); 1854 if (!mediaElement) 1855 return false; 1856 1857 LocalCurrentGraphicsContext localContext(paintInfo.context); 1858 wkDrawMediaUIPart(mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, 1859 node->active() ? MediaUIPartPressedFlag : 0); 1860#endif 1861 return false; 1862} 1863 1864bool RenderThemeChromiumMac::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1865{ 1866#if ENABLE(VIDEO) 1867 Node* node = o->node(); 1868 if (!node) 1869 return false; 1870 1871 LocalCurrentGraphicsContext localContext(paintInfo.context); 1872 wkDrawMediaUIPart(MediaSeekBackButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, 1873 node->active() ? MediaUIPartPressedFlag : 0); 1874#endif 1875 return false; 1876} 1877 1878bool RenderThemeChromiumMac::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1879{ 1880#if ENABLE(VIDEO) 1881 Node* node = o->node(); 1882 if (!node) 1883 return false; 1884 1885 LocalCurrentGraphicsContext localContext(paintInfo.context); 1886 wkDrawMediaUIPart(MediaSeekForwardButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, 1887 node->active() ? MediaUIPartPressedFlag : 0); 1888#endif 1889 return false; 1890} 1891 1892bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1893{ 1894#if ENABLE(VIDEO) 1895 Node* node = o->node(); 1896 Node* mediaNode = node ? node->shadowAncestorNode() : 0; 1897 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) 1898 return false; 1899 1900 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); 1901 if (!mediaElement) 1902 return false; 1903 1904 float timeLoaded = 0; 1905 float currentTime = 0; 1906 float duration = 0; 1907 if (MediaPlayer* player = mediaElement->player()) { 1908 duration = player->duration(); 1909 timeLoaded = player->maxTimeBuffered(); 1910 currentTime = player->currentTime(); 1911 } 1912 1913 bool shouldDrawEndCaps = !toRenderMedia(mediaElement->renderer())->shouldShowTimeDisplayControls(); 1914 wkDrawMediaSliderTrack(MediaControllerThemeClassic, paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration, shouldDrawEndCaps ? MediaUIPartDrawEndCapsFlag : 0); 1915#endif 1916 return false; 1917} 1918 1919bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 1920{ 1921#if ENABLE(VIDEO) 1922 Node* node = o->node(); 1923 if (!node) 1924 return false; 1925 1926 LocalCurrentGraphicsContext localContext(paintInfo.context); 1927 wkDrawMediaUIPart(MediaSliderThumb, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, 1928 node->active() ? MediaUIPartPressedFlag : 0); 1929#endif 1930 return false; 1931} 1932 1933// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 1934NSButtonCell* RenderThemeChromiumMac::checkbox() const 1935{ 1936 if (!m_checkbox) { 1937 m_checkbox.adoptNS([[NSButtonCell alloc] init]); 1938 [m_checkbox.get() setButtonType:NSSwitchButton]; 1939 [m_checkbox.get() setTitle:nil]; 1940 [m_checkbox.get() setAllowsMixedState:YES]; 1941 [m_checkbox.get() setFocusRingType:NSFocusRingTypeExterior]; 1942 } 1943 1944 return m_checkbox.get(); 1945} 1946 1947// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 1948NSButtonCell* RenderThemeChromiumMac::radio() const 1949{ 1950 if (!m_radio) { 1951 m_radio.adoptNS([[NSButtonCell alloc] init]); 1952 [m_radio.get() setButtonType:NSRadioButton]; 1953 [m_radio.get() setTitle:nil]; 1954 [m_radio.get() setFocusRingType:NSFocusRingTypeExterior]; 1955 } 1956 1957 return m_radio.get(); 1958} 1959 1960// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. 1961NSButtonCell* RenderThemeChromiumMac::button() const 1962{ 1963 if (!m_button) { 1964 m_button.adoptNS([[NSButtonCell alloc] init]); 1965 [m_button.get() setTitle:nil]; 1966 [m_button.get() setButtonType:NSMomentaryPushInButton]; 1967 } 1968 1969 return m_button.get(); 1970} 1971 1972NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const 1973{ 1974 if (!m_popupButton) { 1975 m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); 1976 [m_popupButton.get() setUsesItemFromMenu:NO]; 1977 [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior]; 1978 } 1979 1980 return m_popupButton.get(); 1981} 1982 1983NSSearchFieldCell* RenderThemeChromiumMac::search() const 1984{ 1985 if (!m_search) { 1986 m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]); 1987 [m_search.get() setBezelStyle:NSTextFieldRoundedBezel]; 1988 [m_search.get() setBezeled:YES]; 1989 [m_search.get() setEditable:YES]; 1990 [m_search.get() setFocusRingType:NSFocusRingTypeExterior]; 1991 } 1992 1993 return m_search.get(); 1994} 1995 1996NSMenu* RenderThemeChromiumMac::searchMenuTemplate() const 1997{ 1998 if (!m_searchMenuTemplate) 1999 m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]); 2000 2001 return m_searchMenuTemplate.get(); 2002} 2003 2004NSSliderCell* RenderThemeChromiumMac::sliderThumbHorizontal() const 2005{ 2006 if (!m_sliderThumbHorizontal) { 2007 m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]); 2008 [m_sliderThumbHorizontal.get() setTitle:nil]; 2009 [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider]; 2010 [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize]; 2011 [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior]; 2012 } 2013 2014 return m_sliderThumbHorizontal.get(); 2015} 2016 2017NSSliderCell* RenderThemeChromiumMac::sliderThumbVertical() const 2018{ 2019 if (!m_sliderThumbVertical) { 2020 m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]); 2021 [m_sliderThumbVertical.get() setTitle:nil]; 2022 [m_sliderThumbVertical.get() setSliderType:NSLinearSlider]; 2023 [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize]; 2024 [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior]; 2025 } 2026 2027 return m_sliderThumbVertical.get(); 2028} 2029 2030} // namespace WebCore 2031