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