1/* 2 * Copyright (C) 2008, 2011 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "ScrollbarThemeMac.h" 28 29#include "BlockExceptions.h" 30#include "ColorMac.h" 31#include "ImageBuffer.h" 32#include "GraphicsLayer.h" 33#include "LocalCurrentGraphicsContext.h" 34#include "NSScrollerImpDetails.h" 35#include "PlatformMouseEvent.h" 36#include "ScrollAnimatorMac.h" 37#include "ScrollView.h" 38#include "WebCoreSystemInterface.h" 39#include <Carbon/Carbon.h> 40#include <wtf/HashMap.h> 41#include <wtf/StdLibExtras.h> 42#include <wtf/TemporaryChange.h> 43 44// FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow. 45 46using namespace WebCore; 47 48@interface NSColor (WebNSColorDetails) 49+ (NSImage *)_linenPatternImage; 50@end 51 52namespace WebCore { 53 54typedef HashMap<ScrollbarThemeClient*, RetainPtr<ScrollbarPainter>> ScrollbarPainterMap; 55 56static ScrollbarPainterMap* scrollbarMap() 57{ 58 static ScrollbarPainterMap* map = new ScrollbarPainterMap; 59 return map; 60} 61 62} 63 64@interface WebScrollbarPrefsObserver : NSObject 65{ 66} 67 68+ (void)registerAsObserver; 69+ (void)appearancePrefsChanged:(NSNotification*)theNotification; 70+ (void)behaviorPrefsChanged:(NSNotification*)theNotification; 71 72@end 73 74@implementation WebScrollbarPrefsObserver 75 76+ (void)appearancePrefsChanged:(NSNotification*)unusedNotification 77{ 78 UNUSED_PARAM(unusedNotification); 79 80 ScrollbarTheme* theme = ScrollbarTheme::theme(); 81 if (theme->isMockTheme()) 82 return; 83 84 static_cast<ScrollbarThemeMac*>(ScrollbarTheme::theme())->preferencesChanged(); 85 if (scrollbarMap()->isEmpty()) 86 return; 87 ScrollbarPainterMap::iterator end = scrollbarMap()->end(); 88 for (ScrollbarPainterMap::iterator it = scrollbarMap()->begin(); it != end; ++it) { 89 it->key->styleChanged(); 90 it->key->invalidate(); 91 } 92} 93 94+ (void)behaviorPrefsChanged:(NSNotification*)unusedNotification 95{ 96 UNUSED_PARAM(unusedNotification); 97 98 ScrollbarTheme* theme = ScrollbarTheme::theme(); 99 if (theme->isMockTheme()) 100 return; 101 102 static_cast<ScrollbarThemeMac*>(ScrollbarTheme::theme())->preferencesChanged(); 103} 104 105+ (void)registerAsObserver 106{ 107 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(appearancePrefsChanged:) name:@"AppleAquaScrollBarVariantChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 108 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"AppleNoRedisplayAppearancePreferenceChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce]; 109} 110 111@end 112 113namespace WebCore { 114 115ScrollbarTheme* ScrollbarTheme::nativeTheme() 116{ 117 DEPRECATED_DEFINE_STATIC_LOCAL(ScrollbarThemeMac, theme, ()); 118 return &theme; 119} 120 121// FIXME: Get these numbers from CoreUI. 122static int cRealButtonLength[] = { 28, 21 }; 123static int cButtonHitInset[] = { 3, 2 }; 124// cRealButtonLength - cButtonInset 125static int cButtonLength[] = { 14, 10 }; 126 127static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double button pair is a bit bigger. 128static int cOuterButtonOverlap = 2; 129 130static float gInitialButtonDelay = 0.5f; 131static float gAutoscrollButtonDelay = 0.05f; 132static bool gJumpOnTrackClick = false; 133static bool gUsesOverlayScrollbars = false; 134 135static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd; 136 137static bool supportsExpandedScrollbars() 138{ 139 // FIXME: This is temporary until all platforms that support ScrollbarPainter support this part of the API. 140 static bool globalSupportsExpandedScrollbars = [NSClassFromString(@"NSScrollerImp") instancesRespondToSelector:@selector(setExpanded:)]; 141 return globalSupportsExpandedScrollbars; 142} 143 144static NSControlSize scrollbarControlSizeToNSControlSize(ScrollbarControlSize controlSize) 145{ 146 switch (controlSize) { 147 case RegularScrollbar: 148 return NSRegularControlSize; 149 case SmallScrollbar: 150 return NSSmallControlSize; 151 } 152 153 ASSERT_NOT_REACHED(); 154 return NSRegularControlSize; 155} 156 157void ScrollbarThemeMac::registerScrollbar(ScrollbarThemeClient* scrollbar) 158{ 159 if (scrollbar->isCustomScrollbar()) 160 return; 161 162 bool isHorizontal = scrollbar->orientation() == HorizontalScrollbar; 163 ScrollbarPainter scrollbarPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:recommendedScrollerStyle() controlSize:scrollbarControlSizeToNSControlSize(scrollbar->controlSize()) horizontal:isHorizontal replacingScrollerImp:nil]; 164 scrollbarMap()->add(scrollbar, scrollbarPainter); 165 updateEnabledState(scrollbar); 166 updateScrollbarOverlayStyle(scrollbar); 167} 168 169void ScrollbarThemeMac::unregisterScrollbar(ScrollbarThemeClient* scrollbar) 170{ 171 scrollbarMap()->remove(scrollbar); 172} 173 174void ScrollbarThemeMac::setNewPainterForScrollbar(ScrollbarThemeClient* scrollbar, ScrollbarPainter newPainter) 175{ 176 scrollbarMap()->set(scrollbar, newPainter); 177 updateEnabledState(scrollbar); 178 updateScrollbarOverlayStyle(scrollbar); 179} 180 181ScrollbarPainter ScrollbarThemeMac::painterForScrollbar(ScrollbarThemeClient* scrollbar) 182{ 183 return scrollbarMap()->get(scrollbar).get(); 184} 185 186static bool g_isCurrentlyDrawingIntoLayer; 187 188bool ScrollbarThemeMac::isCurrentlyDrawingIntoLayer() 189{ 190 return g_isCurrentlyDrawingIntoLayer; 191} 192 193void ScrollbarThemeMac::setIsCurrentlyDrawingIntoLayer(bool b) 194{ 195 g_isCurrentlyDrawingIntoLayer = b; 196} 197 198ScrollbarThemeMac::ScrollbarThemeMac() 199{ 200 static bool initialized; 201 if (!initialized) { 202 initialized = true; 203 gButtonPlacement = ScrollbarButtonsNone; 204 [WebScrollbarPrefsObserver registerAsObserver]; 205 preferencesChanged(); 206 } 207} 208 209ScrollbarThemeMac::~ScrollbarThemeMac() 210{ 211} 212 213void ScrollbarThemeMac::preferencesChanged() 214{ 215 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 216 [defaults synchronize]; 217 gInitialButtonDelay = [defaults floatForKey:@"NSScrollerButtonDelay"]; 218 gAutoscrollButtonDelay = [defaults floatForKey:@"NSScrollerButtonPeriod"]; 219 gJumpOnTrackClick = [defaults boolForKey:@"AppleScrollerPagingBehavior"]; 220 usesOverlayScrollbarsChanged(); 221} 222 223int ScrollbarThemeMac::scrollbarThickness(ScrollbarControlSize controlSize) 224{ 225 BEGIN_BLOCK_OBJC_EXCEPTIONS; 226 ScrollbarPainter scrollbarPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:recommendedScrollerStyle() controlSize:scrollbarControlSizeToNSControlSize(controlSize) horizontal:NO replacingScrollerImp:nil]; 227 if (supportsExpandedScrollbars()) 228 [scrollbarPainter setExpanded:YES]; 229 return [scrollbarPainter trackBoxWidth]; 230 END_BLOCK_OBJC_EXCEPTIONS; 231} 232 233bool ScrollbarThemeMac::usesOverlayScrollbars() const 234{ 235 return gUsesOverlayScrollbars; 236} 237 238void ScrollbarThemeMac::usesOverlayScrollbarsChanged() 239{ 240 gUsesOverlayScrollbars = recommendedScrollerStyle() == NSScrollerStyleOverlay; 241} 242 243void ScrollbarThemeMac::updateScrollbarOverlayStyle(ScrollbarThemeClient* scrollbar) 244{ 245 BEGIN_BLOCK_OBJC_EXCEPTIONS; 246 ScrollbarPainter painter = painterForScrollbar(scrollbar); 247 switch (scrollbar->scrollbarOverlayStyle()) { 248 case ScrollbarOverlayStyleDefault: 249 [painter setKnobStyle:NSScrollerKnobStyleDefault]; 250 break; 251 case ScrollbarOverlayStyleDark: 252 [painter setKnobStyle:NSScrollerKnobStyleDark]; 253 break; 254 case ScrollbarOverlayStyleLight: 255 [painter setKnobStyle:NSScrollerKnobStyleLight]; 256 break; 257 } 258 END_BLOCK_OBJC_EXCEPTIONS; 259} 260 261double ScrollbarThemeMac::initialAutoscrollTimerDelay() 262{ 263 return gInitialButtonDelay; 264} 265 266double ScrollbarThemeMac::autoscrollTimerDelay() 267{ 268 return gAutoscrollButtonDelay; 269} 270 271ScrollbarButtonsPlacement ScrollbarThemeMac::buttonsPlacement() const 272{ 273 return gButtonPlacement; 274} 275 276bool ScrollbarThemeMac::hasButtons(ScrollbarThemeClient* scrollbar) 277{ 278 return scrollbar->enabled() && buttonsPlacement() != ScrollbarButtonsNone 279 && (scrollbar->orientation() == HorizontalScrollbar 280 ? scrollbar->width() 281 : scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]); 282} 283 284bool ScrollbarThemeMac::hasThumb(ScrollbarThemeClient* scrollbar) 285{ 286 int minLengthForThumb; 287 288 ScrollbarPainter painter = scrollbarMap()->get(scrollbar).get(); 289 minLengthForThumb = [painter knobMinLength] + [painter trackOverlapEndInset] + [painter knobOverlapEndInset] 290 + 2 * ([painter trackEndInset] + [painter knobEndInset]); 291 292 return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? 293 scrollbar->width() : 294 scrollbar->height()) >= minLengthForThumb; 295} 296 297static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start) 298{ 299 ASSERT(gButtonPlacement != ScrollbarButtonsNone); 300 301 IntRect paintRect(buttonRect); 302 if (orientation == HorizontalScrollbar) { 303 paintRect.setWidth(cRealButtonLength[controlSize]); 304 if (!start) 305 paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width())); 306 } else { 307 paintRect.setHeight(cRealButtonLength[controlSize]); 308 if (!start) 309 paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height())); 310 } 311 312 return paintRect; 313} 314 315IntRect ScrollbarThemeMac::backButtonRect(ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting) 316{ 317 IntRect result; 318 319 if (part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd)) 320 return result; 321 322 if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsSingle)) 323 return result; 324 325 int thickness = scrollbarThickness(scrollbar->controlSize()); 326 bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsDoubleBoth); 327 if (outerButton) { 328 if (scrollbar->orientation() == HorizontalScrollbar) 329 result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0), thickness); 330 else 331 result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterButtonLength[scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0)); 332 return result; 333 } 334 335 // Our repaint rect is slightly larger, since we are a button that is adjacent to the track. 336 if (scrollbar->orientation() == HorizontalScrollbar) { 337 int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x() + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()]; 338 result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->controlSize()], thickness); 339 } else { 340 int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y() + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()]; 341 result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollbar->controlSize()]); 342 } 343 344 if (painting) 345 return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == BackButtonStartPart); 346 return result; 347} 348 349IntRect ScrollbarThemeMac::forwardButtonRect(ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting) 350{ 351 IntRect result; 352 353 if (part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart)) 354 return result; 355 356 if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsSingle)) 357 return result; 358 359 int thickness = scrollbarThickness(scrollbar->controlSize()); 360 int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; 361 int buttonLength = cButtonLength[scrollbar->controlSize()]; 362 363 bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsDoubleBoth); 364 if (outerButton) { 365 if (scrollbar->orientation() == HorizontalScrollbar) { 366 result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLength, scrollbar->y(), outerButtonLength, thickness); 367 if (painting) 368 result.inflateX(cOuterButtonOverlap); 369 } else { 370 result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - outerButtonLength, thickness, outerButtonLength); 371 if (painting) 372 result.inflateY(cOuterButtonOverlap); 373 } 374 return result; 375 } 376 377 if (scrollbar->orientation() == HorizontalScrollbar) { 378 int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->width() - buttonLength : scrollbar->x() + outerButtonLength; 379 result = IntRect(start, scrollbar->y(), buttonLength, thickness); 380 } else { 381 int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->height() - buttonLength : scrollbar->y() + outerButtonLength; 382 result = IntRect(scrollbar->x(), start, thickness, buttonLength); 383 } 384 if (painting) 385 return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == ForwardButtonStartPart); 386 return result; 387} 388 389IntRect ScrollbarThemeMac::trackRect(ScrollbarThemeClient* scrollbar, bool painting) 390{ 391 if (painting || !hasButtons(scrollbar)) 392 return scrollbar->frameRect(); 393 394 IntRect result; 395 int thickness = scrollbarThickness(scrollbar->controlSize()); 396 int startWidth = 0; 397 int endWidth = 0; 398 int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; 399 int buttonLength = cButtonLength[scrollbar->controlSize()]; 400 int doubleButtonLength = outerButtonLength + buttonLength; 401 switch (buttonsPlacement()) { 402 case ScrollbarButtonsSingle: 403 startWidth = buttonLength; 404 endWidth = buttonLength; 405 break; 406 case ScrollbarButtonsDoubleStart: 407 startWidth = doubleButtonLength; 408 break; 409 case ScrollbarButtonsDoubleEnd: 410 endWidth = doubleButtonLength; 411 break; 412 case ScrollbarButtonsDoubleBoth: 413 startWidth = doubleButtonLength; 414 endWidth = doubleButtonLength; 415 break; 416 default: 417 break; 418 } 419 420 int totalWidth = startWidth + endWidth; 421 if (scrollbar->orientation() == HorizontalScrollbar) 422 return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->width() - totalWidth, thickness); 423 return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrollbar->height() - totalWidth); 424} 425 426int ScrollbarThemeMac::minimumThumbLength(ScrollbarThemeClient* scrollbar) 427{ 428 BEGIN_BLOCK_OBJC_EXCEPTIONS; 429 return [scrollbarMap()->get(scrollbar) knobMinLength]; 430 END_BLOCK_OBJC_EXCEPTIONS; 431} 432 433bool ScrollbarThemeMac::shouldCenterOnThumb(ScrollbarThemeClient*, const PlatformMouseEvent& evt) 434{ 435 if (evt.button() != LeftButton) 436 return false; 437 if (gJumpOnTrackClick) 438 return !evt.altKey(); 439 return evt.altKey(); 440} 441 442bool ScrollbarThemeMac::shouldDragDocumentInsteadOfThumb(ScrollbarThemeClient*, const PlatformMouseEvent& event) 443{ 444 return event.altKey(); 445} 446 447int ScrollbarThemeMac::scrollbarPartToHIPressedState(ScrollbarPart part) 448{ 449 switch (part) { 450 case BackButtonStartPart: 451 return kThemeTopOutsideArrowPressed; 452 case BackButtonEndPart: 453 return kThemeTopOutsideArrowPressed; // This does not make much sense. For some reason the outside constant is required. 454 case ForwardButtonStartPart: 455 return kThemeTopInsideArrowPressed; 456 case ForwardButtonEndPart: 457 return kThemeBottomOutsideArrowPressed; 458 case ThumbPart: 459 return kThemeThumbPressed; 460 default: 461 return 0; 462 } 463} 464 465void ScrollbarThemeMac::updateEnabledState(ScrollbarThemeClient* scrollbar) 466{ 467 BEGIN_BLOCK_OBJC_EXCEPTIONS; 468 [scrollbarMap()->get(scrollbar) setEnabled:scrollbar->enabled()]; 469 END_BLOCK_OBJC_EXCEPTIONS; 470} 471 472void ScrollbarThemeMac::setPaintCharacteristicsForScrollbar(ScrollbarThemeClient* scrollbar) 473{ 474 BEGIN_BLOCK_OBJC_EXCEPTIONS; 475 ScrollbarPainter painter = painterForScrollbar(scrollbar); 476 477 float value; 478 float overhang; 479 ScrollableArea::computeScrollbarValueAndOverhang(scrollbar->currentPos(), scrollbar->totalSize(), scrollbar->visibleSize(), value, overhang); 480 float proportion = scrollbar->totalSize() > 0 ? (static_cast<CGFloat>(scrollbar->visibleSize()) - overhang) / scrollbar->totalSize() : 1; 481 482 [painter setEnabled:scrollbar->enabled()]; 483 [painter setBoundsSize:scrollbar->frameRect().size()]; 484 [painter setDoubleValue:value]; 485#if ENABLE(ASYNC_SCROLLING) && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 486 [painter setPresentationValue:value]; 487#endif 488 [painter setKnobProportion:proportion]; 489 END_BLOCK_OBJC_EXCEPTIONS; 490} 491 492static void scrollbarPainterPaint(ScrollbarPainter scrollbarPainter, bool enabled) 493{ 494 BEGIN_BLOCK_OBJC_EXCEPTIONS; 495 // Use rectForPart: here; it will take the expansion transition progress into account. 496 NSRect trackRect = [scrollbarPainter rectForPart:NSScrollerKnobSlot]; 497 [scrollbarPainter drawKnobSlotInRect:trackRect highlight:NO]; 498 499 // If the scrollbar is not enabled, then there is nothing to scroll to, and we shouldn't 500 // call drawKnob. 501 if (enabled) 502 [scrollbarPainter drawKnob]; 503 END_BLOCK_OBJC_EXCEPTIONS; 504} 505 506bool ScrollbarThemeMac::paint(ScrollbarThemeClient* scrollbar, GraphicsContext* context, const IntRect& damageRect) 507{ 508 setPaintCharacteristicsForScrollbar(scrollbar); 509 510 if (!scrollbar->supportsUpdateOnSecondaryThread()) { 511 TemporaryChange<bool> isCurrentlyDrawingIntoLayer(g_isCurrentlyDrawingIntoLayer, context->isCALayerContext()); 512 513 GraphicsContextStateSaver stateSaver(*context); 514 context->clip(damageRect); 515 context->translate(scrollbar->frameRect().x(), scrollbar->frameRect().y()); 516 LocalCurrentGraphicsContext localContext(context); 517 scrollbarPainterPaint(scrollbarMap()->get(scrollbar).get(), scrollbar->enabled()); 518 } 519 520 return true; 521} 522 523#if ENABLE(RUBBER_BANDING) 524static RetainPtr<CGColorRef> linenBackgroundColor() 525{ 526 NSImage *image = nil; 527 CGImageRef cgImage = nullptr; 528 BEGIN_BLOCK_OBJC_EXCEPTIONS; 529 image = [NSColor _linenPatternImage]; 530 cgImage = [image CGImageForProposedRect:NULL context:NULL hints:nil]; 531 END_BLOCK_OBJC_EXCEPTIONS; 532 533 if (!cgImage) 534 return nullptr; 535 536 RetainPtr<CGPatternRef> pattern = adoptCF(wkCGPatternCreateWithImageAndTransform(cgImage, CGAffineTransformIdentity, wkPatternTilingNoDistortion)); 537 RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreatePattern(0)); 538 539 const CGFloat alpha = 1.0; 540 return adoptCF(CGColorCreateWithPattern(colorSpace.get(), pattern.get(), &alpha)); 541} 542 543void ScrollbarThemeMac::setUpOverhangAreaBackground(CALayer *layer, const Color& customBackgroundColor) 544{ 545 static CGColorRef cachedLinenBackgroundColor = linenBackgroundColor().leakRef(); 546 // We operate on the CALayer directly here, since GraphicsLayer doesn't have the concept 547 // of pattern images, and we know that WebCore won't touch this layer. 548 layer.backgroundColor = customBackgroundColor.isValid() ? cachedCGColor(customBackgroundColor, ColorSpaceDeviceRGB) : cachedLinenBackgroundColor; 549} 550 551void ScrollbarThemeMac::removeOverhangAreaBackground(CALayer *layer) 552{ 553 layer.backgroundColor = nil; 554} 555 556void ScrollbarThemeMac::setUpOverhangAreaShadow(CALayer *layer) 557{ 558 static const CGFloat shadowOpacity = 0.66; 559 static const CGFloat shadowRadius = 3; 560 561 // We only need to set these shadow properties once. 562 if (!layer.shadowOpacity) { 563 layer.shadowColor = CGColorGetConstantColor(kCGColorBlack); 564 layer.shadowOffset = CGSizeZero; 565 layer.shadowOpacity = shadowOpacity; 566 layer.shadowRadius = shadowRadius; 567 } 568 569 RetainPtr<CGPathRef> shadowPath = adoptCF(CGPathCreateWithRect(layer.bounds, NULL)); 570 layer.shadowPath = shadowPath.get(); 571} 572 573void ScrollbarThemeMac::removeOverhangAreaShadow(CALayer *layer) 574{ 575 layer.shadowPath = nil; 576 layer.shadowOpacity = 0; 577} 578 579void ScrollbarThemeMac::setUpOverhangAreasLayerContents(GraphicsLayer* graphicsLayer, const Color& customBackgroundColor) 580{ 581 ScrollbarThemeMac::setUpOverhangAreaBackground(graphicsLayer->platformLayer(), customBackgroundColor); 582} 583 584void ScrollbarThemeMac::setUpContentShadowLayer(GraphicsLayer* graphicsLayer) 585{ 586 // We operate on the CALayer directly here, since GraphicsLayer doesn't have the concept 587 // of shadows, and we know that WebCore won't touch this layer. 588 setUpOverhangAreaShadow(graphicsLayer->platformLayer()); 589} 590 591#endif 592 593} // namespace WebCore 594