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