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