Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  * Copyright (C) 2009 Google Inc. All Rights Reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "ScrollbarThemeChromiumMac.h"
     29 
     30 #include "FrameView.h"
     31 #include "ImageBuffer.h"
     32 #include "PlatformBridge.h"
     33 #include "PlatformMouseEvent.h"
     34 #include "ScrollView.h"
     35 #include <Carbon/Carbon.h>
     36 #include <wtf/StdLibExtras.h>
     37 #include <wtf/UnusedParam.h>
     38 
     39 
     40 // FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow.
     41 
     42 using namespace std;
     43 using namespace WebCore;
     44 
     45 // This file (and its associated .h file) is a clone of ScrollbarThemeMac.mm.
     46 // Because we want to draw tickmarks in the scrollbar, we must maintain a fork.
     47 // Please maintain this file by performing parallel changes to it.
     48 //
     49 // The only changes from ScrollbarThemeMac should be:
     50 // - The classname change from ScrollbarThemeMac to ScrollbarThemeChromiumMac.
     51 // - In paint() the code to paint the track, tickmarks, and thumb separately.
     52 // - In paint() the thumb is drawn via ChromeBridge/WebThemeEngine.
     53 //
     54 // For all other differences, if it was introduced in this file, then the
     55 // maintainer forgot to include it in the list; otherwise it is an update that
     56 // should have been applied to this file but was not.
     57 
     58 static HashSet<Scrollbar*>* gScrollbars;
     59 
     60 @interface ScrollbarPrefsObserver : NSObject
     61 {
     62 
     63 }
     64 
     65 + (void)registerAsObserver;
     66 + (void)appearancePrefsChanged:(NSNotification*)theNotification;
     67 + (void)behaviorPrefsChanged:(NSNotification*)theNotification;
     68 
     69 @end
     70 
     71 @implementation ScrollbarPrefsObserver
     72 
     73 + (void)appearancePrefsChanged:(NSNotification*)unusedNotification
     74 {
     75     UNUSED_PARAM(unusedNotification);
     76 
     77     static_cast<ScrollbarThemeChromiumMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged();
     78     if (!gScrollbars)
     79         return;
     80     HashSet<Scrollbar*>::iterator end = gScrollbars->end();
     81     for (HashSet<Scrollbar*>::iterator it = gScrollbars->begin(); it != end; ++it) {
     82         (*it)->styleChanged();
     83         (*it)->invalidate();
     84     }
     85 }
     86 
     87 + (void)behaviorPrefsChanged:(NSNotification*)unusedNotification
     88 {
     89     UNUSED_PARAM(unusedNotification);
     90 
     91     static_cast<ScrollbarThemeChromiumMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged();
     92 }
     93 
     94 + (void)registerAsObserver
     95 {
     96     [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(appearancePrefsChanged:) name:@"AppleAquaScrollBarVariantChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
     97     [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"AppleNoRedisplayAppearancePreferenceChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce];
     98 }
     99 
    100 @end
    101 
    102 namespace WebCore {
    103 
    104 ScrollbarTheme* ScrollbarTheme::nativeTheme()
    105 {
    106     DEFINE_STATIC_LOCAL(ScrollbarThemeChromiumMac, theme, ());
    107     return &theme;
    108 }
    109 
    110 // FIXME: Get these numbers from CoreUI.
    111 static int cScrollbarThickness[] = { 15, 11 };
    112 static int cRealButtonLength[] = { 28, 21 };
    113 static int cButtonInset[] = { 14, 11 };
    114 static int cButtonHitInset[] = { 3, 2 };
    115 // cRealButtonLength - cButtonInset
    116 static int cButtonLength[] = { 14, 10 };
    117 static int cThumbMinLength[] = { 26, 20 };
    118 
    119 static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double button pair is a bit bigger.
    120 static int cOuterButtonOverlap = 2;
    121 
    122 static float gInitialButtonDelay = 0.5f;
    123 static float gAutoscrollButtonDelay = 0.05f;
    124 static bool gJumpOnTrackClick = false;
    125 static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd;
    126 
    127 static void updateArrowPlacement()
    128 {
    129     NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
    130     if ([buttonPlacement isEqualToString:@"Single"])
    131         gButtonPlacement = ScrollbarButtonsSingle;
    132     else if ([buttonPlacement isEqualToString:@"DoubleMin"])
    133         gButtonPlacement = ScrollbarButtonsDoubleStart;
    134     else if ([buttonPlacement isEqualToString:@"DoubleBoth"])
    135         gButtonPlacement = ScrollbarButtonsDoubleBoth;
    136     else
    137         gButtonPlacement = ScrollbarButtonsDoubleEnd; // The default is ScrollbarButtonsDoubleEnd.
    138 }
    139 
    140 void ScrollbarThemeChromiumMac::registerScrollbar(Scrollbar* scrollbar)
    141 {
    142     if (!gScrollbars)
    143         gScrollbars = new HashSet<Scrollbar*>;
    144     gScrollbars->add(scrollbar);
    145 }
    146 
    147 void ScrollbarThemeChromiumMac::unregisterScrollbar(Scrollbar* scrollbar)
    148 {
    149     gScrollbars->remove(scrollbar);
    150     if (gScrollbars->isEmpty()) {
    151         delete gScrollbars;
    152         gScrollbars = 0;
    153     }
    154 }
    155 
    156 ScrollbarThemeChromiumMac::ScrollbarThemeChromiumMac()
    157 {
    158     static bool initialized;
    159     if (!initialized) {
    160         initialized = true;
    161         [ScrollbarPrefsObserver registerAsObserver];
    162         preferencesChanged();
    163     }
    164 }
    165 
    166 ScrollbarThemeChromiumMac::~ScrollbarThemeChromiumMac()
    167 {
    168 }
    169 
    170 void ScrollbarThemeChromiumMac::preferencesChanged()
    171 {
    172     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    173     [defaults synchronize];
    174     updateArrowPlacement();
    175     gInitialButtonDelay = [defaults floatForKey:@"NSScrollerButtonDelay"];
    176     gAutoscrollButtonDelay = [defaults floatForKey:@"NSScrollerButtonPeriod"];
    177     gJumpOnTrackClick = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
    178 }
    179 
    180 int ScrollbarThemeChromiumMac::scrollbarThickness(ScrollbarControlSize controlSize)
    181 {
    182     return cScrollbarThickness[controlSize];
    183 }
    184 
    185 double ScrollbarThemeChromiumMac::initialAutoscrollTimerDelay()
    186 {
    187     return gInitialButtonDelay;
    188 }
    189 
    190 double ScrollbarThemeChromiumMac::autoscrollTimerDelay()
    191 {
    192     return gAutoscrollButtonDelay;
    193 }
    194 
    195 ScrollbarButtonsPlacement ScrollbarThemeChromiumMac::buttonsPlacement() const
    196 {
    197     return gButtonPlacement;
    198 }
    199 
    200 bool ScrollbarThemeChromiumMac::hasButtons(Scrollbar* scrollbar)
    201 {
    202     return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ?
    203              scrollbar->width() :
    204              scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]);
    205 }
    206 
    207 bool ScrollbarThemeChromiumMac::hasThumb(Scrollbar* scrollbar)
    208 {
    209     return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ?
    210              scrollbar->width() :
    211              scrollbar->height()) >= 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1;
    212 }
    213 
    214 static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
    215 {
    216     IntRect paintRect(buttonRect);
    217     if (orientation == HorizontalScrollbar) {
    218         paintRect.setWidth(cRealButtonLength[controlSize]);
    219         if (!start)
    220             paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width()));
    221     } else {
    222         paintRect.setHeight(cRealButtonLength[controlSize]);
    223         if (!start)
    224             paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height()));
    225     }
    226 
    227     return paintRect;
    228 }
    229 
    230 IntRect ScrollbarThemeChromiumMac::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting)
    231 {
    232     IntRect result;
    233 
    234     if (part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd))
    235         return result;
    236 
    237     if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsSingle))
    238         return result;
    239 
    240     int thickness = scrollbarThickness(scrollbar->controlSize());
    241     bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsDoubleBoth);
    242     if (outerButton) {
    243         if (scrollbar->orientation() == HorizontalScrollbar)
    244             result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0, thickness);
    245         else
    246             result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0);
    247         return result;
    248     }
    249 
    250     // Our repaint rect is slightly larger, since we are a button that is adjacent to the track.
    251     if (scrollbar->orientation() == HorizontalScrollbar) {
    252         int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x() + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
    253         result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->controlSize()], thickness);
    254     } else {
    255         int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y() + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
    256         result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollbar->controlSize()]);
    257     }
    258 
    259     if (painting)
    260         return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == BackButtonStartPart);
    261     return result;
    262 }
    263 
    264 IntRect ScrollbarThemeChromiumMac::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting)
    265 {
    266     IntRect result;
    267 
    268     if (part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart))
    269         return result;
    270 
    271     if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsSingle))
    272         return result;
    273 
    274     int thickness = scrollbarThickness(scrollbar->controlSize());
    275     int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
    276     int buttonLength = cButtonLength[scrollbar->controlSize()];
    277 
    278     bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsDoubleBoth);
    279     if (outerButton) {
    280         if (scrollbar->orientation() == HorizontalScrollbar) {
    281             result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLength, scrollbar->y(), outerButtonLength, thickness);
    282             if (painting)
    283                 result.inflateX(cOuterButtonOverlap);
    284         } else {
    285             result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - outerButtonLength, thickness, outerButtonLength);
    286             if (painting)
    287                 result.inflateY(cOuterButtonOverlap);
    288         }
    289         return result;
    290     }
    291 
    292     if (scrollbar->orientation() == HorizontalScrollbar) {
    293         int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->width() - buttonLength : scrollbar->x() + outerButtonLength;
    294         result = IntRect(start, scrollbar->y(), buttonLength, thickness);
    295     } else {
    296         int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->height() - buttonLength : scrollbar->y() + outerButtonLength;
    297         result = IntRect(scrollbar->x(), start, thickness, buttonLength);
    298     }
    299     if (painting)
    300         return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == ForwardButtonStartPart);
    301     return result;
    302 }
    303 
    304 IntRect ScrollbarThemeChromiumMac::trackRect(Scrollbar* scrollbar, bool painting)
    305 {
    306     if (painting || !hasButtons(scrollbar))
    307         return scrollbar->frameRect();
    308 
    309     IntRect result;
    310     int thickness = scrollbarThickness(scrollbar->controlSize());
    311     int startWidth = 0;
    312     int endWidth = 0;
    313     int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
    314     int buttonLength = cButtonLength[scrollbar->controlSize()];
    315     int doubleButtonLength = outerButtonLength + buttonLength;
    316     switch (buttonsPlacement()) {
    317         case ScrollbarButtonsSingle:
    318             startWidth = buttonLength;
    319             endWidth = buttonLength;
    320             break;
    321         case ScrollbarButtonsDoubleStart:
    322             startWidth = doubleButtonLength;
    323             break;
    324         case ScrollbarButtonsDoubleEnd:
    325             endWidth = doubleButtonLength;
    326             break;
    327         case ScrollbarButtonsDoubleBoth:
    328             startWidth = doubleButtonLength;
    329             endWidth = doubleButtonLength;
    330             break;
    331         default:
    332             break;
    333     }
    334 
    335     int totalWidth = startWidth + endWidth;
    336     if (scrollbar->orientation() == HorizontalScrollbar)
    337         return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->width() - totalWidth, thickness);
    338     return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrollbar->height() - totalWidth);
    339 }
    340 
    341 int ScrollbarThemeChromiumMac::minimumThumbLength(Scrollbar* scrollbar)
    342 {
    343     return cThumbMinLength[scrollbar->controlSize()];
    344 }
    345 
    346 bool ScrollbarThemeChromiumMac::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
    347 {
    348     if (evt.button() != LeftButton)
    349         return false;
    350     if (gJumpOnTrackClick)
    351         return !evt.altKey();
    352     return evt.altKey();
    353 }
    354 
    355 static int scrollbarPartToHIPressedState(ScrollbarPart part)
    356 {
    357     switch (part) {
    358         case BackButtonStartPart:
    359             return kThemeTopOutsideArrowPressed;
    360         case BackButtonEndPart:
    361             return kThemeTopOutsideArrowPressed; // This does not make much sense.  For some reason the outside constant is required.
    362         case ForwardButtonStartPart:
    363             return kThemeTopInsideArrowPressed;
    364         case ForwardButtonEndPart:
    365             return kThemeBottomOutsideArrowPressed;
    366         case ThumbPart:
    367             return kThemeThumbPressed;
    368         default:
    369             return 0;
    370     }
    371 }
    372 
    373 static PlatformBridge::ThemePaintState scrollbarStateToThemeState(Scrollbar* scrollbar) {
    374     if (!scrollbar->enabled())
    375         return PlatformBridge::StateDisabled;
    376     if (!scrollbar->scrollableArea()->isActive())
    377         return PlatformBridge::StateInactive;
    378     if (scrollbar->pressedPart() == ThumbPart)
    379         return PlatformBridge::StatePressed;
    380 
    381     return PlatformBridge::StateActive;
    382 }
    383 
    384 bool ScrollbarThemeChromiumMac::paint(Scrollbar* scrollbar, GraphicsContext* context, const IntRect& damageRect)
    385 {
    386     HIThemeTrackDrawInfo trackInfo;
    387     trackInfo.version = 0;
    388     trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar;
    389     trackInfo.bounds = scrollbar->frameRect();
    390     trackInfo.min = 0;
    391     trackInfo.max = scrollbar->maximum();
    392     trackInfo.value = scrollbar->currentPos();
    393     trackInfo.trackInfo.scrollbar.viewsize = scrollbar->visibleSize();
    394     trackInfo.attributes = 0;
    395     if (scrollbar->orientation() == HorizontalScrollbar)
    396         trackInfo.attributes |= kThemeTrackHorizontal;
    397 
    398     if (!scrollbar->enabled())
    399         trackInfo.enableState = kThemeTrackDisabled;
    400     else
    401         trackInfo.enableState = scrollbar->scrollableArea()->isActive() ? kThemeTrackActive : kThemeTrackInactive;
    402 
    403     if (!hasButtons(scrollbar))
    404         trackInfo.enableState = kThemeTrackNothingToScroll;
    405     trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar->pressedPart());
    406 
    407     CGAffineTransform currentCTM = CGContextGetCTM(context->platformContext());
    408 
    409     // The Aqua scrollbar is buggy when rotated and scaled.  We will just draw into a bitmap if we detect a scale or rotation.
    410     bool canDrawDirectly = currentCTM.a == 1.0f && currentCTM.b == 0.0f && currentCTM.c == 0.0f && (currentCTM.d == 1.0f || currentCTM.d == -1.0f);
    411     GraphicsContext* drawingContext = context;
    412     OwnPtr<ImageBuffer> imageBuffer;
    413     if (!canDrawDirectly) {
    414         trackInfo.bounds = IntRect(IntPoint(), scrollbar->frameRect().size());
    415 
    416         IntRect bufferRect(scrollbar->frameRect());
    417         bufferRect.intersect(damageRect);
    418         bufferRect.move(-scrollbar->frameRect().x(), -scrollbar->frameRect().y());
    419 
    420         imageBuffer = ImageBuffer::create(bufferRect.size());
    421         if (!imageBuffer)
    422             return true;
    423 
    424         drawingContext = imageBuffer->context();
    425     }
    426 
    427     // Draw thumbless.
    428     HIThemeDrawTrack(&trackInfo, 0, drawingContext->platformContext(), kHIThemeOrientationNormal);
    429 
    430     Vector<IntRect> tickmarks;
    431     scrollbar->scrollableArea()->getTickmarks(tickmarks);
    432     if (scrollbar->orientation() == VerticalScrollbar && tickmarks.size()) {
    433         drawingContext->save();
    434         drawingContext->setShouldAntialias(false);
    435         drawingContext->setStrokeColor(Color(0xCC, 0xAA, 0x00, 0xFF), ColorSpaceDeviceRGB);
    436         drawingContext->setFillColor(Color(0xFF, 0xDD, 0x00, 0xFF), ColorSpaceDeviceRGB);
    437 
    438         IntRect thumbArea = trackRect(scrollbar, false);
    439         if (!canDrawDirectly) {
    440             thumbArea.setX(0);
    441             thumbArea.setY(0);
    442         }
    443         // The ends are rounded and the thumb doesn't go there.
    444         thumbArea.inflateY(-thumbArea.width());
    445 
    446         for (Vector<IntRect>::const_iterator i = tickmarks.begin(); i != tickmarks.end(); ++i) {
    447             // Calculate how far down (in %) the tick-mark should appear.
    448             const float percent = static_cast<float>(i->y()) / scrollbar->totalSize();
    449             if (percent < 0.0 || percent > 1.0)
    450               continue;
    451 
    452             // Calculate how far down (in pixels) the tick-mark should appear.
    453             const int yPos = static_cast<int>((thumbArea.y() + (thumbArea.height() * percent))) & ~1;
    454 
    455             // Paint.
    456             const int indent = 2;
    457             FloatRect tickRect(thumbArea.x() + indent, yPos, thumbArea.width() - 2 * indent - 1, 2);
    458             drawingContext->fillRect(tickRect);
    459             drawingContext->strokeRect(tickRect, 1);
    460         }
    461 
    462         drawingContext->restore();
    463     }
    464 
    465     if (hasThumb(scrollbar)) {
    466         PlatformBridge::ThemePaintScrollbarInfo scrollbarInfo;
    467         scrollbarInfo.orientation = scrollbar->orientation() == HorizontalScrollbar ? PlatformBridge::ScrollbarOrientationHorizontal : PlatformBridge::ScrollbarOrientationVertical;
    468         scrollbarInfo.parent = scrollbar->parent() && scrollbar->parent()->isFrameView() && static_cast<FrameView*>(scrollbar->parent())->isScrollViewScrollbar(scrollbar) ? PlatformBridge::ScrollbarParentScrollView : PlatformBridge::ScrollbarParentRenderLayer;
    469         scrollbarInfo.maxValue = scrollbar->maximum();
    470         scrollbarInfo.currentValue = scrollbar->currentPos();
    471         scrollbarInfo.visibleSize = scrollbar->visibleSize();
    472         scrollbarInfo.totalSize = scrollbar->totalSize();
    473 
    474         PlatformBridge::paintScrollbarThumb(
    475             drawingContext,
    476             scrollbarStateToThemeState(scrollbar),
    477             scrollbar->controlSize() == RegularScrollbar ? PlatformBridge::SizeRegular : PlatformBridge::SizeSmall,
    478             scrollbar->frameRect(),
    479             scrollbarInfo);
    480     }
    481 
    482     if (!canDrawDirectly)
    483         context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, scrollbar->frameRect().location());
    484 
    485     return true;
    486 }
    487 
    488 }
    489 
    490