Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2008 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 "ImageBuffer.h"
     30 #include "LocalCurrentGraphicsContext.h"
     31 #include "PlatformMouseEvent.h"
     32 #include "ScrollAnimatorMac.h"
     33 #include "ScrollView.h"
     34 #include <Carbon/Carbon.h>
     35 #include <wtf/HashMap.h>
     36 #include <wtf/StdLibExtras.h>
     37 #include <wtf/UnusedParam.h>
     38 
     39 // FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow.
     40 
     41 using namespace std;
     42 using namespace WebCore;
     43 
     44 namespace WebCore {
     45 
     46 #if USE(WK_SCROLLBAR_PAINTER)
     47 typedef HashMap<Scrollbar*, RetainPtr<WKScrollbarPainterRef> > ScrollbarPainterMap;
     48 #else
     49 typedef HashSet<Scrollbar*> ScrollbarPainterMap;
     50 #endif
     51 
     52 static ScrollbarPainterMap* scrollbarMap()
     53 {
     54     static ScrollbarPainterMap* map = new ScrollbarPainterMap;
     55     return map;
     56 }
     57 
     58 }
     59 
     60 @interface ScrollbarPrefsObserver : NSObject
     61 {
     62 }
     63 
     64 + (void)registerAsObserver;
     65 + (void)appearancePrefsChanged:(NSNotification*)theNotification;
     66 + (void)behaviorPrefsChanged:(NSNotification*)theNotification;
     67 
     68 @end
     69 
     70 @implementation ScrollbarPrefsObserver
     71 
     72 + (void)appearancePrefsChanged:(NSNotification*)unusedNotification
     73 {
     74     UNUSED_PARAM(unusedNotification);
     75 
     76     static_cast<ScrollbarThemeMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged();
     77     if (scrollbarMap()->isEmpty())
     78         return;
     79     ScrollbarPainterMap::iterator end = scrollbarMap()->end();
     80     for (ScrollbarPainterMap::iterator it = scrollbarMap()->begin(); it != end; ++it) {
     81 #if USE(WK_SCROLLBAR_PAINTER)
     82         it->first->styleChanged();
     83         it->first->invalidate();
     84 #else
     85         (*it)->styleChanged();
     86         (*it)->invalidate();
     87 #endif
     88     }
     89 }
     90 
     91 + (void)behaviorPrefsChanged:(NSNotification*)unusedNotification
     92 {
     93     UNUSED_PARAM(unusedNotification);
     94 
     95     static_cast<ScrollbarThemeMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged();
     96 }
     97 
     98 + (void)registerAsObserver
     99 {
    100     [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(appearancePrefsChanged:) name:@"AppleAquaScrollBarVariantChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
    101     [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"AppleNoRedisplayAppearancePreferenceChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce];
    102 }
    103 
    104 @end
    105 
    106 namespace WebCore {
    107 
    108 ScrollbarTheme* ScrollbarTheme::nativeTheme()
    109 {
    110     DEFINE_STATIC_LOCAL(ScrollbarThemeMac, theme, ());
    111     return &theme;
    112 }
    113 
    114 // FIXME: Get these numbers from CoreUI.
    115 static int cRealButtonLength[] = { 28, 21 };
    116 static int cButtonHitInset[] = { 3, 2 };
    117 // cRealButtonLength - cButtonInset
    118 static int cButtonLength[] = { 14, 10 };
    119 #if !USE(WK_SCROLLBAR_PAINTER)
    120 static int cScrollbarThickness[] = { 15, 11 };
    121 static int cButtonInset[] = { 14, 11 };
    122 static int cThumbMinLength[] = { 26, 20 };
    123 #endif
    124 
    125 static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double button pair is a bit bigger.
    126 static int cOuterButtonOverlap = 2;
    127 
    128 static float gInitialButtonDelay = 0.5f;
    129 static float gAutoscrollButtonDelay = 0.05f;
    130 static bool gJumpOnTrackClick = false;
    131 
    132 #if USE(WK_SCROLLBAR_PAINTER)
    133 static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsNone;
    134 #else
    135 static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd;
    136 #endif
    137 
    138 static void updateArrowPlacement()
    139 {
    140     NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
    141     if ([buttonPlacement isEqualToString:@"Single"])
    142         gButtonPlacement = ScrollbarButtonsSingle;
    143     else if ([buttonPlacement isEqualToString:@"DoubleMin"])
    144         gButtonPlacement = ScrollbarButtonsDoubleStart;
    145     else if ([buttonPlacement isEqualToString:@"DoubleBoth"])
    146         gButtonPlacement = ScrollbarButtonsDoubleBoth;
    147     else {
    148 #if USE(WK_SCROLLBAR_PAINTER)
    149         gButtonPlacement = ScrollbarButtonsNone;
    150 #else
    151         gButtonPlacement = ScrollbarButtonsDoubleEnd;
    152 #endif
    153     }
    154 }
    155 
    156 void ScrollbarThemeMac::registerScrollbar(Scrollbar* scrollbar)
    157 {
    158 #if USE(WK_SCROLLBAR_PAINTER)
    159     bool isHorizontal = scrollbar->orientation() == HorizontalScrollbar;
    160     WKScrollbarPainterRef scrollbarPainter = wkMakeScrollbarPainter(scrollbar->controlSize(), isHorizontal);
    161     scrollbarMap()->add(scrollbar, scrollbarPainter);
    162 #else
    163     scrollbarMap()->add(scrollbar);
    164 #endif
    165 }
    166 
    167 void ScrollbarThemeMac::unregisterScrollbar(Scrollbar* scrollbar)
    168 {
    169     scrollbarMap()->remove(scrollbar);
    170 }
    171 
    172 #if USE(WK_SCROLLBAR_PAINTER)
    173 void ScrollbarThemeMac::setNewPainterForScrollbar(Scrollbar* scrollbar, WKScrollbarPainterRef newPainter)
    174 {
    175     scrollbarMap()->set(scrollbar, newPainter);
    176 }
    177 
    178 WKScrollbarPainterRef ScrollbarThemeMac::painterForScrollbar(Scrollbar* scrollbar)
    179 {
    180     return scrollbarMap()->get(scrollbar).get();
    181 }
    182 #endif
    183 
    184 ScrollbarThemeMac::ScrollbarThemeMac()
    185 {
    186     static bool initialized;
    187     if (!initialized) {
    188         initialized = true;
    189         [ScrollbarPrefsObserver registerAsObserver];
    190         preferencesChanged();
    191     }
    192 }
    193 
    194 ScrollbarThemeMac::~ScrollbarThemeMac()
    195 {
    196 }
    197 
    198 void ScrollbarThemeMac::preferencesChanged()
    199 {
    200     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    201     [defaults synchronize];
    202     updateArrowPlacement();
    203     gInitialButtonDelay = [defaults floatForKey:@"NSScrollerButtonDelay"];
    204     gAutoscrollButtonDelay = [defaults floatForKey:@"NSScrollerButtonPeriod"];
    205     gJumpOnTrackClick = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
    206 }
    207 
    208 int ScrollbarThemeMac::scrollbarThickness(ScrollbarControlSize controlSize)
    209 {
    210 #if USE(WK_SCROLLBAR_PAINTER)
    211     return wkScrollbarThickness(controlSize);
    212 #else
    213     return cScrollbarThickness[controlSize];
    214 #endif
    215 }
    216 
    217 bool ScrollbarThemeMac::usesOverlayScrollbars() const
    218 {
    219 #if USE(WK_SCROLLBAR_PAINTER)
    220     return wkScrollbarPainterUsesOverlayScrollers();
    221 #else
    222     return false;
    223 #endif
    224 }
    225 
    226 double ScrollbarThemeMac::initialAutoscrollTimerDelay()
    227 {
    228     return gInitialButtonDelay;
    229 }
    230 
    231 double ScrollbarThemeMac::autoscrollTimerDelay()
    232 {
    233     return gAutoscrollButtonDelay;
    234 }
    235 
    236 ScrollbarButtonsPlacement ScrollbarThemeMac::buttonsPlacement() const
    237 {
    238     return gButtonPlacement;
    239 }
    240 
    241 bool ScrollbarThemeMac::hasButtons(Scrollbar* scrollbar)
    242 {
    243     return scrollbar->enabled() && gButtonPlacement != ScrollbarButtonsNone
    244              && (scrollbar->orientation() == HorizontalScrollbar
    245              ? scrollbar->width()
    246              : scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]);
    247 }
    248 
    249 bool ScrollbarThemeMac::hasThumb(Scrollbar* scrollbar)
    250 {
    251     int minLengthForThumb;
    252 #if USE(WK_SCROLLBAR_PAINTER)
    253     minLengthForThumb = wkScrollbarMinimumTotalLengthNeededForThumb(scrollbarMap()->get(scrollbar).get());
    254 #else
    255     minLengthForThumb = 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1;
    256 #endif
    257     return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ?
    258              scrollbar->width() :
    259              scrollbar->height()) >= minLengthForThumb;
    260 }
    261 
    262 static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
    263 {
    264     ASSERT(gButtonPlacement != ScrollbarButtonsNone);
    265 
    266     IntRect paintRect(buttonRect);
    267     if (orientation == HorizontalScrollbar) {
    268         paintRect.setWidth(cRealButtonLength[controlSize]);
    269         if (!start)
    270             paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width()));
    271     } else {
    272         paintRect.setHeight(cRealButtonLength[controlSize]);
    273         if (!start)
    274             paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height()));
    275     }
    276 
    277     return paintRect;
    278 }
    279 
    280 IntRect ScrollbarThemeMac::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting)
    281 {
    282     IntRect result;
    283 
    284     if (part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd))
    285         return result;
    286 
    287     if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsSingle))
    288         return result;
    289 
    290     int thickness = scrollbarThickness(scrollbar->controlSize());
    291     bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsDoubleBoth);
    292     if (outerButton) {
    293         if (scrollbar->orientation() == HorizontalScrollbar)
    294             result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0, thickness);
    295         else
    296             result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0);
    297         return result;
    298     }
    299 
    300     // Our repaint rect is slightly larger, since we are a button that is adjacent to the track.
    301     if (scrollbar->orientation() == HorizontalScrollbar) {
    302         int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x() + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
    303         result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->controlSize()], thickness);
    304     } else {
    305         int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y() + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
    306         result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollbar->controlSize()]);
    307     }
    308 
    309     if (painting)
    310         return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == BackButtonStartPart);
    311     return result;
    312 }
    313 
    314 IntRect ScrollbarThemeMac::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting)
    315 {
    316     IntRect result;
    317 
    318     if (part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart))
    319         return result;
    320 
    321     if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsSingle))
    322         return result;
    323 
    324     int thickness = scrollbarThickness(scrollbar->controlSize());
    325     int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
    326     int buttonLength = cButtonLength[scrollbar->controlSize()];
    327 
    328     bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsDoubleBoth);
    329     if (outerButton) {
    330         if (scrollbar->orientation() == HorizontalScrollbar) {
    331             result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLength, scrollbar->y(), outerButtonLength, thickness);
    332             if (painting)
    333                 result.inflateX(cOuterButtonOverlap);
    334         } else {
    335             result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - outerButtonLength, thickness, outerButtonLength);
    336             if (painting)
    337                 result.inflateY(cOuterButtonOverlap);
    338         }
    339         return result;
    340     }
    341 
    342     if (scrollbar->orientation() == HorizontalScrollbar) {
    343         int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->width() - buttonLength : scrollbar->x() + outerButtonLength;
    344         result = IntRect(start, scrollbar->y(), buttonLength, thickness);
    345     } else {
    346         int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->height() - buttonLength : scrollbar->y() + outerButtonLength;
    347         result = IntRect(scrollbar->x(), start, thickness, buttonLength);
    348     }
    349     if (painting)
    350         return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == ForwardButtonStartPart);
    351     return result;
    352 }
    353 
    354 IntRect ScrollbarThemeMac::trackRect(Scrollbar* scrollbar, bool painting)
    355 {
    356     if (painting || !hasButtons(scrollbar))
    357         return scrollbar->frameRect();
    358 
    359     IntRect result;
    360     int thickness = scrollbarThickness(scrollbar->controlSize());
    361     int startWidth = 0;
    362     int endWidth = 0;
    363     int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
    364     int buttonLength = cButtonLength[scrollbar->controlSize()];
    365     int doubleButtonLength = outerButtonLength + buttonLength;
    366     switch (buttonsPlacement()) {
    367         case ScrollbarButtonsSingle:
    368             startWidth = buttonLength;
    369             endWidth = buttonLength;
    370             break;
    371         case ScrollbarButtonsDoubleStart:
    372             startWidth = doubleButtonLength;
    373             break;
    374         case ScrollbarButtonsDoubleEnd:
    375             endWidth = doubleButtonLength;
    376             break;
    377         case ScrollbarButtonsDoubleBoth:
    378             startWidth = doubleButtonLength;
    379             endWidth = doubleButtonLength;
    380             break;
    381         default:
    382             break;
    383     }
    384 
    385     int totalWidth = startWidth + endWidth;
    386     if (scrollbar->orientation() == HorizontalScrollbar)
    387         return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->width() - totalWidth, thickness);
    388     return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrollbar->height() - totalWidth);
    389 }
    390 
    391 int ScrollbarThemeMac::minimumThumbLength(Scrollbar* scrollbar)
    392 {
    393 #if USE(WK_SCROLLBAR_PAINTER)
    394     return wkScrollbarMinimumThumbLength(scrollbarMap()->get(scrollbar).get());
    395 #else
    396     return cThumbMinLength[scrollbar->controlSize()];
    397 #endif
    398 }
    399 
    400 bool ScrollbarThemeMac::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
    401 {
    402     if (evt.button() != LeftButton)
    403         return false;
    404     if (gJumpOnTrackClick)
    405         return !evt.altKey();
    406     return evt.altKey();
    407 }
    408 
    409 static int scrollbarPartToHIPressedState(ScrollbarPart part)
    410 {
    411     switch (part) {
    412         case BackButtonStartPart:
    413             return kThemeTopOutsideArrowPressed;
    414         case BackButtonEndPart:
    415             return kThemeTopOutsideArrowPressed; // This does not make much sense.  For some reason the outside constant is required.
    416         case ForwardButtonStartPart:
    417             return kThemeTopInsideArrowPressed;
    418         case ForwardButtonEndPart:
    419             return kThemeBottomOutsideArrowPressed;
    420         case ThumbPart:
    421             return kThemeThumbPressed;
    422         default:
    423             return 0;
    424     }
    425 }
    426 
    427 bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, const IntRect& damageRect)
    428 {
    429 #if USE(WK_SCROLLBAR_PAINTER)
    430     float value = 0;
    431     float overhang = 0;
    432 
    433     if (scrollbar->currentPos() < 0) {
    434         // Scrolled past the top.
    435         value = 0;
    436         overhang = -scrollbar->currentPos();
    437     } else if (scrollbar->visibleSize() + scrollbar->currentPos() > scrollbar->totalSize()) {
    438         // Scrolled past the bottom.
    439         value = 1;
    440         overhang = scrollbar->currentPos() + scrollbar->visibleSize() - scrollbar->totalSize();
    441     } else {
    442         // Within the bounds of the scrollable area.
    443         int maximum = scrollbar->maximum();
    444         if (maximum > 0)
    445             value = scrollbar->currentPos() / maximum;
    446         else
    447             value = 0;
    448     }
    449 
    450     ScrollAnimatorMac* scrollAnimator = static_cast<ScrollAnimatorMac*>(scrollbar->scrollableArea()->scrollAnimator());
    451     scrollAnimator->setIsDrawingIntoLayer(context->isCALayerContext());
    452 
    453     context->save();
    454     context->clip(damageRect);
    455     context->translate(scrollbar->frameRect().x(), scrollbar->frameRect().y());
    456     LocalCurrentGraphicsContext localContext(context);
    457     wkScrollbarPainterPaint(scrollbarMap()->get(scrollbar).get(),
    458                             scrollbar->enabled(),
    459                             value,
    460                             (static_cast<CGFloat>(scrollbar->visibleSize()) - overhang) / scrollbar->totalSize(),
    461                             scrollbar->frameRect());
    462 
    463     scrollAnimator->setIsDrawingIntoLayer(false);
    464 
    465     context->restore();
    466     return true;
    467 #endif
    468 
    469     HIThemeTrackDrawInfo trackInfo;
    470     trackInfo.version = 0;
    471     trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar;
    472     trackInfo.bounds = scrollbar->frameRect();
    473 
    474     float maximum = 0.0f;
    475     float position = 0.0f;
    476     if (scrollbar->currentPos() < 0) {
    477         // Scrolled past the top.
    478         maximum = (scrollbar->totalSize() - scrollbar->currentPos()) - scrollbar->visibleSize();
    479         position = 0;
    480     } else if (scrollbar->visibleSize() + scrollbar->currentPos() > scrollbar->totalSize()) {
    481         // Scrolled past the bottom.
    482         maximum = scrollbar->currentPos();
    483         position = maximum;
    484     } else {
    485         // Within the bounds of the scrollable area.
    486         maximum = scrollbar->maximum();
    487         position = scrollbar->currentPos();
    488     }
    489 
    490     trackInfo.min = 0;
    491     trackInfo.max = static_cast<int>(maximum);
    492     trackInfo.value = static_cast<int>(position);
    493 
    494     trackInfo.trackInfo.scrollbar.viewsize = scrollbar->visibleSize();
    495     trackInfo.attributes = 0;
    496     if (scrollbar->orientation() == HorizontalScrollbar)
    497         trackInfo.attributes |= kThemeTrackHorizontal;
    498 
    499     if (!scrollbar->enabled())
    500         trackInfo.enableState = kThemeTrackDisabled;
    501     else
    502         trackInfo.enableState = scrollbar->scrollableArea()->isActive() ? kThemeTrackActive : kThemeTrackInactive;
    503 
    504     if (hasThumb(scrollbar))
    505         trackInfo.attributes |= kThemeTrackShowThumb;
    506     else if (!hasButtons(scrollbar))
    507         trackInfo.enableState = kThemeTrackNothingToScroll;
    508     trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar->pressedPart());
    509 
    510     // The Aqua scrollbar is buggy when rotated and scaled.  We will just draw into a bitmap if we detect a scale or rotation.
    511     const AffineTransform& currentCTM = context->getCTM();
    512     bool canDrawDirectly = currentCTM.isIdentityOrTranslationOrFlipped();
    513     if (canDrawDirectly)
    514         HIThemeDrawTrack(&trackInfo, 0, context->platformContext(), kHIThemeOrientationNormal);
    515     else {
    516         trackInfo.bounds = IntRect(IntPoint(), scrollbar->frameRect().size());
    517 
    518         IntRect bufferRect(scrollbar->frameRect());
    519         bufferRect.intersect(damageRect);
    520 
    521         OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(bufferRect.size());
    522         if (!imageBuffer)
    523             return true;
    524 
    525         imageBuffer->context()->translate(scrollbar->frameRect().x() - bufferRect.x(), scrollbar->frameRect().y() - bufferRect.y());
    526         HIThemeDrawTrack(&trackInfo, 0, imageBuffer->context()->platformContext(), kHIThemeOrientationNormal);
    527         context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, bufferRect.location());
    528     }
    529 
    530     return true;
    531 }
    532 
    533 }
    534 
    535