~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/mac/ScrollbarThemeMac.mm

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "GraphicsLayer.h"
 
31
#include "LocalCurrentGraphicsContext.h"
 
32
#include "NSScrollerImpDetails.h"
 
33
#include "PlatformMouseEvent.h"
 
34
#include "ScrollAnimatorMac.h"
 
35
#include "ScrollView.h"
 
36
#include "WebCoreSystemInterface.h"
 
37
#include <Carbon/Carbon.h>
 
38
#include <wtf/HashMap.h>
 
39
#include <wtf/StdLibExtras.h>
 
40
#include <wtf/TemporaryChange.h>
 
41
#include <wtf/UnusedParam.h>
 
42
 
 
43
// FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow.
 
44
 
 
45
using namespace std;
 
46
using namespace WebCore;
 
47
 
 
48
@interface NSColor (WebNSColorDetails)
 
49
+ (NSImage *)_linenPatternImage;
 
50
@end
 
51
 
 
52
namespace WebCore {
 
53
 
 
54
typedef HashMap<ScrollbarThemeClient*, RetainPtr<ScrollbarPainter> > ScrollbarPainterMap;
 
55
 
 
56
static 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
 
 
113
namespace WebCore {
 
114
 
 
115
#if !PLATFORM(CHROMIUM)
 
116
ScrollbarTheme* ScrollbarTheme::nativeTheme()
 
117
{
 
118
    DEFINE_STATIC_LOCAL(ScrollbarThemeMac, theme, ());
 
119
    return &theme;
 
120
}
 
121
#endif
 
122
 
 
123
// FIXME: Get these numbers from CoreUI.
 
124
static int cRealButtonLength[] = { 28, 21 };
 
125
static int cButtonHitInset[] = { 3, 2 };
 
126
// cRealButtonLength - cButtonInset
 
127
static int cButtonLength[] = { 14, 10 };
 
128
static int cScrollbarThickness[] = { 15, 11 };
 
129
static int cButtonInset[] = { 14, 11 };
 
130
static int cThumbMinLength[] = { 26, 20 };
 
131
 
 
132
static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double button pair is a bit bigger.
 
133
static int cOuterButtonOverlap = 2;
 
134
 
 
135
static float gInitialButtonDelay = 0.5f;
 
136
static float gAutoscrollButtonDelay = 0.05f;
 
137
static bool gJumpOnTrackClick = false;
 
138
 
 
139
static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd;
 
140
 
 
141
static bool supportsExpandedScrollbars()
 
142
{
 
143
    // FIXME: This is temporary until all platforms that support ScrollbarPainter support this part of the API.
 
144
    static bool globalSupportsExpandedScrollbars = [NSClassFromString(@"NSScrollerImp") instancesRespondToSelector:@selector(setExpanded:)];
 
145
    return globalSupportsExpandedScrollbars;
 
146
}
 
147
 
 
148
static void updateArrowPlacement()
 
149
{
 
150
    if (isScrollbarOverlayAPIAvailable())
 
151
        return;
 
152
 
 
153
    NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
 
154
    if ([buttonPlacement isEqualToString:@"Single"])
 
155
        gButtonPlacement = ScrollbarButtonsSingle;
 
156
    else if ([buttonPlacement isEqualToString:@"DoubleMin"])
 
157
        gButtonPlacement = ScrollbarButtonsDoubleStart;
 
158
    else if ([buttonPlacement isEqualToString:@"DoubleBoth"])
 
159
        gButtonPlacement = ScrollbarButtonsDoubleBoth;
 
160
    else {
 
161
 
 
162
        gButtonPlacement = ScrollbarButtonsDoubleEnd;
 
163
    }
 
164
}
 
165
 
 
166
void ScrollbarThemeMac::registerScrollbar(ScrollbarThemeClient* scrollbar)
 
167
{
 
168
    if (isScrollbarOverlayAPIAvailable()) {
 
169
        bool isHorizontal = scrollbar->orientation() == HorizontalScrollbar;
 
170
        ScrollbarPainter scrollbarPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:recommendedScrollerStyle() controlSize:(NSControlSize)scrollbar->controlSize() horizontal:isHorizontal replacingScrollerImp:nil];
 
171
        scrollbarMap()->add(scrollbar, scrollbarPainter);
 
172
        updateEnabledState(scrollbar);
 
173
        updateScrollbarOverlayStyle(scrollbar);
 
174
    } else {
 
175
        scrollbarMap()->add(scrollbar, nil);
 
176
    }
 
177
}
 
178
 
 
179
void ScrollbarThemeMac::unregisterScrollbar(ScrollbarThemeClient* scrollbar)
 
180
{
 
181
    scrollbarMap()->remove(scrollbar);
 
182
}
 
183
 
 
184
void ScrollbarThemeMac::setNewPainterForScrollbar(ScrollbarThemeClient* scrollbar, ScrollbarPainter newPainter)
 
185
{
 
186
    scrollbarMap()->set(scrollbar, newPainter);
 
187
    updateEnabledState(scrollbar);
 
188
    updateScrollbarOverlayStyle(scrollbar);
 
189
}
 
190
 
 
191
ScrollbarPainter ScrollbarThemeMac::painterForScrollbar(ScrollbarThemeClient* scrollbar)
 
192
{
 
193
    return scrollbarMap()->get(scrollbar).get();
 
194
}
 
195
 
 
196
static bool g_isCurrentlyDrawingIntoLayer;
 
197
    
 
198
bool ScrollbarThemeMac::isCurrentlyDrawingIntoLayer()
 
199
{
 
200
    return g_isCurrentlyDrawingIntoLayer;
 
201
}
 
202
 
 
203
void ScrollbarThemeMac::setIsCurrentlyDrawingIntoLayer(bool b)
 
204
{
 
205
    g_isCurrentlyDrawingIntoLayer = b;
 
206
}
 
207
 
 
208
ScrollbarThemeMac::ScrollbarThemeMac()
 
209
{
 
210
    static bool initialized;
 
211
    if (!initialized) {
 
212
        initialized = true;
 
213
        gButtonPlacement = isScrollbarOverlayAPIAvailable() ? ScrollbarButtonsNone : ScrollbarButtonsDoubleEnd;
 
214
        [WebScrollbarPrefsObserver registerAsObserver];
 
215
        preferencesChanged();
 
216
    }
 
217
}
 
218
 
 
219
ScrollbarThemeMac::~ScrollbarThemeMac()
 
220
{
 
221
}
 
222
 
 
223
void ScrollbarThemeMac::preferencesChanged()
 
224
{
 
225
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
 
226
    [defaults synchronize];
 
227
    updateArrowPlacement();
 
228
    gInitialButtonDelay = [defaults floatForKey:@"NSScrollerButtonDelay"];
 
229
    gAutoscrollButtonDelay = [defaults floatForKey:@"NSScrollerButtonPeriod"];
 
230
    gJumpOnTrackClick = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
 
231
}
 
232
 
 
233
int ScrollbarThemeMac::scrollbarThickness(ScrollbarControlSize controlSize)
 
234
{
 
235
    if (isScrollbarOverlayAPIAvailable()) {
 
236
        ScrollbarPainter scrollbarPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:recommendedScrollerStyle() controlSize:controlSize horizontal:NO replacingScrollerImp:nil];
 
237
        if (supportsExpandedScrollbars())
 
238
            [scrollbarPainter setExpanded:YES];
 
239
        return [scrollbarPainter trackBoxWidth];
 
240
    } else
 
241
        return cScrollbarThickness[controlSize];
 
242
}
 
243
 
 
244
bool ScrollbarThemeMac::usesOverlayScrollbars() const
 
245
{
 
246
    if (isScrollbarOverlayAPIAvailable())
 
247
        return recommendedScrollerStyle() == NSScrollerStyleOverlay;
 
248
    else
 
249
        return false;
 
250
}
 
251
 
 
252
void ScrollbarThemeMac::updateScrollbarOverlayStyle(ScrollbarThemeClient* scrollbar)
 
253
{
 
254
    ScrollbarPainter painter = painterForScrollbar(scrollbar);
 
255
    switch (scrollbar->scrollbarOverlayStyle()) {
 
256
    case ScrollbarOverlayStyleDefault:
 
257
        [painter setKnobStyle:NSScrollerKnobStyleDefault];
 
258
        break;
 
259
    case ScrollbarOverlayStyleDark:
 
260
        [painter setKnobStyle:NSScrollerKnobStyleDark];
 
261
        break;
 
262
    case ScrollbarOverlayStyleLight:
 
263
        [painter setKnobStyle:NSScrollerKnobStyleLight];
 
264
        break;
 
265
    }
 
266
}
 
267
 
 
268
double ScrollbarThemeMac::initialAutoscrollTimerDelay()
 
269
{
 
270
    return gInitialButtonDelay;
 
271
}
 
272
 
 
273
double ScrollbarThemeMac::autoscrollTimerDelay()
 
274
{
 
275
    return gAutoscrollButtonDelay;
 
276
}
 
277
    
 
278
ScrollbarButtonsPlacement ScrollbarThemeMac::buttonsPlacement() const
 
279
{
 
280
    return gButtonPlacement;
 
281
}
 
282
 
 
283
bool ScrollbarThemeMac::hasButtons(ScrollbarThemeClient* scrollbar)
 
284
{
 
285
    return scrollbar->enabled() && buttonsPlacement() != ScrollbarButtonsNone
 
286
             && (scrollbar->orientation() == HorizontalScrollbar
 
287
             ? scrollbar->width()
 
288
             : scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]);
 
289
}
 
290
 
 
291
bool ScrollbarThemeMac::hasThumb(ScrollbarThemeClient* scrollbar)
 
292
{
 
293
    int minLengthForThumb;
 
294
    if (isScrollbarOverlayAPIAvailable()) {
 
295
        ScrollbarPainter painter = scrollbarMap()->get(scrollbar).get();
 
296
        minLengthForThumb = [painter knobMinLength] + [painter trackOverlapEndInset] + [painter knobOverlapEndInset]
 
297
            + 2 * ([painter trackEndInset] + [painter knobEndInset]);
 
298
    } else
 
299
        minLengthForThumb = 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1;
 
300
    return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? 
 
301
             scrollbar->width() : 
 
302
             scrollbar->height()) >= minLengthForThumb;
 
303
}
 
304
 
 
305
static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
 
306
{
 
307
    ASSERT(gButtonPlacement != ScrollbarButtonsNone);
 
308
 
 
309
    IntRect paintRect(buttonRect);
 
310
    if (orientation == HorizontalScrollbar) {
 
311
        paintRect.setWidth(cRealButtonLength[controlSize]);
 
312
        if (!start)
 
313
            paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width()));
 
314
    } else {
 
315
        paintRect.setHeight(cRealButtonLength[controlSize]);
 
316
        if (!start)
 
317
            paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height()));
 
318
    }
 
319
 
 
320
    return paintRect;
 
321
}
 
322
 
 
323
IntRect ScrollbarThemeMac::backButtonRect(ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting)
 
324
{
 
325
    IntRect result;
 
326
    
 
327
    if (part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd))
 
328
        return result;
 
329
    
 
330
    if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsSingle))
 
331
        return result;
 
332
        
 
333
    int thickness = scrollbarThickness(scrollbar->controlSize());
 
334
    bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsDoubleBoth);
 
335
    if (outerButton) {
 
336
        if (scrollbar->orientation() == HorizontalScrollbar)
 
337
            result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0), thickness);
 
338
        else
 
339
            result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterButtonLength[scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0));
 
340
        return result;
 
341
    }
 
342
    
 
343
    // Our repaint rect is slightly larger, since we are a button that is adjacent to the track.
 
344
    if (scrollbar->orientation() == HorizontalScrollbar) {
 
345
        int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x() + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
 
346
        result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->controlSize()], thickness);
 
347
    } else {
 
348
        int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y() + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()];
 
349
        result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollbar->controlSize()]);
 
350
    }
 
351
    
 
352
    if (painting)
 
353
        return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == BackButtonStartPart);
 
354
    return result;
 
355
}
 
356
 
 
357
IntRect ScrollbarThemeMac::forwardButtonRect(ScrollbarThemeClient* scrollbar, ScrollbarPart part, bool painting)
 
358
{
 
359
    IntRect result;
 
360
    
 
361
    if (part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart))
 
362
        return result;
 
363
    
 
364
    if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsSingle))
 
365
        return result;
 
366
        
 
367
    int thickness = scrollbarThickness(scrollbar->controlSize());
 
368
    int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
 
369
    int buttonLength = cButtonLength[scrollbar->controlSize()];
 
370
    
 
371
    bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsDoubleBoth);
 
372
    if (outerButton) {
 
373
        if (scrollbar->orientation() == HorizontalScrollbar) {
 
374
            result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLength, scrollbar->y(), outerButtonLength, thickness);
 
375
            if (painting)
 
376
                result.inflateX(cOuterButtonOverlap);
 
377
        } else {
 
378
            result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - outerButtonLength, thickness, outerButtonLength);
 
379
            if (painting)
 
380
                result.inflateY(cOuterButtonOverlap);
 
381
        }
 
382
        return result;
 
383
    }
 
384
    
 
385
    if (scrollbar->orientation() == HorizontalScrollbar) {
 
386
        int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->width() - buttonLength : scrollbar->x() + outerButtonLength;
 
387
        result = IntRect(start, scrollbar->y(), buttonLength, thickness);
 
388
    } else {
 
389
        int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->height() - buttonLength : scrollbar->y() + outerButtonLength;
 
390
        result = IntRect(scrollbar->x(), start, thickness, buttonLength);
 
391
    }
 
392
    if (painting)
 
393
        return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == ForwardButtonStartPart);
 
394
    return result;
 
395
}
 
396
 
 
397
IntRect ScrollbarThemeMac::trackRect(ScrollbarThemeClient* scrollbar, bool painting)
 
398
{
 
399
    if (painting || !hasButtons(scrollbar))
 
400
        return scrollbar->frameRect();
 
401
    
 
402
    IntRect result;
 
403
    int thickness = scrollbarThickness(scrollbar->controlSize());
 
404
    int startWidth = 0;
 
405
    int endWidth = 0;
 
406
    int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()];
 
407
    int buttonLength = cButtonLength[scrollbar->controlSize()];
 
408
    int doubleButtonLength = outerButtonLength + buttonLength;
 
409
    switch (buttonsPlacement()) {
 
410
        case ScrollbarButtonsSingle:
 
411
            startWidth = buttonLength;
 
412
            endWidth = buttonLength;
 
413
            break;
 
414
        case ScrollbarButtonsDoubleStart:
 
415
            startWidth = doubleButtonLength;
 
416
            break;
 
417
        case ScrollbarButtonsDoubleEnd:
 
418
            endWidth = doubleButtonLength;
 
419
            break;
 
420
        case ScrollbarButtonsDoubleBoth:
 
421
            startWidth = doubleButtonLength;
 
422
            endWidth = doubleButtonLength;
 
423
            break;
 
424
        default:
 
425
            break;
 
426
    }
 
427
    
 
428
    int totalWidth = startWidth + endWidth;
 
429
    if (scrollbar->orientation() == HorizontalScrollbar)
 
430
        return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->width() - totalWidth, thickness);
 
431
    return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrollbar->height() - totalWidth);
 
432
}
 
433
 
 
434
int ScrollbarThemeMac::minimumThumbLength(ScrollbarThemeClient* scrollbar)
 
435
{
 
436
    if (isScrollbarOverlayAPIAvailable())
 
437
        return [scrollbarMap()->get(scrollbar).get() knobMinLength];
 
438
    else
 
439
        return cThumbMinLength[scrollbar->controlSize()];
 
440
}
 
441
 
 
442
bool ScrollbarThemeMac::shouldCenterOnThumb(ScrollbarThemeClient*, const PlatformMouseEvent& evt)
 
443
{
 
444
    if (evt.button() != LeftButton)
 
445
        return false;
 
446
    if (gJumpOnTrackClick)
 
447
        return !evt.altKey();
 
448
    return evt.altKey();
 
449
}
 
450
 
 
451
bool ScrollbarThemeMac::shouldDragDocumentInsteadOfThumb(ScrollbarThemeClient*, const PlatformMouseEvent& event)
 
452
{
 
453
    return event.altKey();
 
454
}
 
455
 
 
456
int ScrollbarThemeMac::scrollbarPartToHIPressedState(ScrollbarPart part)
 
457
{
 
458
    switch (part) {
 
459
        case BackButtonStartPart:
 
460
            return kThemeTopOutsideArrowPressed;
 
461
        case BackButtonEndPart:
 
462
            return kThemeTopOutsideArrowPressed; // This does not make much sense.  For some reason the outside constant is required.
 
463
        case ForwardButtonStartPart:
 
464
            return kThemeTopInsideArrowPressed;
 
465
        case ForwardButtonEndPart:
 
466
            return kThemeBottomOutsideArrowPressed;
 
467
        case ThumbPart:
 
468
            return kThemeThumbPressed;
 
469
        default:
 
470
            return 0;
 
471
    }
 
472
}
 
473
 
 
474
void ScrollbarThemeMac::updateEnabledState(ScrollbarThemeClient* scrollbar)
 
475
{
 
476
    if (isScrollbarOverlayAPIAvailable())
 
477
        [scrollbarMap()->get(scrollbar).get() setEnabled:scrollbar->enabled()];
 
478
}
 
479
 
 
480
#if !PLATFORM(CHROMIUM)
 
481
static void scrollbarPainterPaint(ScrollbarPainter scrollbarPainter, bool enabled, double value, CGFloat proportion, CGRect frameRect)
 
482
{
 
483
    [scrollbarPainter setEnabled:enabled];
 
484
    [scrollbarPainter setBoundsSize: NSSizeFromCGSize(frameRect.size)];
 
485
    [scrollbarPainter setDoubleValue:value];
 
486
    [scrollbarPainter setKnobProportion:proportion];
 
487
 
 
488
    // Use rectForPart: here; it will take the expansion transition progress into account.
 
489
    NSRect trackRect = [scrollbarPainter rectForPart:NSScrollerKnobSlot];
 
490
    [scrollbarPainter drawKnobSlotInRect:trackRect highlight:NO];
 
491
 
 
492
    // If the scrollbar is not enabled, then there is nothing to scroll to, and we shouldn't
 
493
    // call drawKnob.
 
494
    if (enabled)
 
495
        [scrollbarPainter drawKnob];
 
496
}
 
497
 
 
498
bool ScrollbarThemeMac::paint(ScrollbarThemeClient* scrollbar, GraphicsContext* context, const IntRect& damageRect)
 
499
{
 
500
    if (isScrollbarOverlayAPIAvailable()) {
 
501
        float value = 0;
 
502
        float overhang = 0;
 
503
 
 
504
        if (scrollbar->currentPos() < 0) {
 
505
            // Scrolled past the top.
 
506
            value = 0;
 
507
            overhang = -scrollbar->currentPos();
 
508
        } else if (scrollbar->visibleSize() + scrollbar->currentPos() > scrollbar->totalSize()) {
 
509
            // Scrolled past the bottom.
 
510
            value = 1;
 
511
            overhang = scrollbar->currentPos() + scrollbar->visibleSize() - scrollbar->totalSize();
 
512
        } else {
 
513
            // Within the bounds of the scrollable area.
 
514
            int maximum = scrollbar->maximum();
 
515
            if (maximum > 0)
 
516
                value = scrollbar->currentPos() / maximum;
 
517
            else
 
518
                value = 0;
 
519
        }
 
520
 
 
521
        TemporaryChange<bool> isCurrentlyDrawingIntoLayer(g_isCurrentlyDrawingIntoLayer, context->isCALayerContext());
 
522
        
 
523
        GraphicsContextStateSaver stateSaver(*context);
 
524
        context->clip(damageRect);
 
525
        context->translate(scrollbar->frameRect().x(), scrollbar->frameRect().y());
 
526
        LocalCurrentGraphicsContext localContext(context);
 
527
        scrollbarPainterPaint(scrollbarMap()->get(scrollbar).get(),
 
528
                                scrollbar->enabled(),
 
529
                                value,
 
530
                                (static_cast<CGFloat>(scrollbar->visibleSize()) - overhang) / scrollbar->totalSize(),
 
531
                                scrollbar->frameRect());
 
532
 
 
533
        return true;
 
534
    }
 
535
 
 
536
    HIThemeTrackDrawInfo trackInfo;
 
537
    trackInfo.version = 0;
 
538
    trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar;
 
539
    trackInfo.bounds = scrollbar->frameRect();
 
540
 
 
541
    float maximum = 0.0f;
 
542
    float position = 0.0f;
 
543
    if (scrollbar->currentPos() < 0) {
 
544
        // Scrolled past the top.
 
545
        maximum = (scrollbar->totalSize() - scrollbar->currentPos()) - scrollbar->visibleSize();
 
546
        position = 0;
 
547
    } else if (scrollbar->visibleSize() + scrollbar->currentPos() > scrollbar->totalSize()) {
 
548
        // Scrolled past the bottom.
 
549
        maximum = scrollbar->currentPos();
 
550
        position = maximum;
 
551
    } else {
 
552
        // Within the bounds of the scrollable area.
 
553
        maximum = scrollbar->maximum();
 
554
        position = scrollbar->currentPos();
 
555
    }
 
556
 
 
557
    trackInfo.min = 0;
 
558
    trackInfo.max = static_cast<int>(maximum);
 
559
    trackInfo.value = static_cast<int>(position);
 
560
 
 
561
    trackInfo.trackInfo.scrollbar.viewsize = scrollbar->visibleSize();
 
562
    trackInfo.attributes = 0;
 
563
    if (scrollbar->orientation() == HorizontalScrollbar)
 
564
        trackInfo.attributes |= kThemeTrackHorizontal;
 
565
 
 
566
    if (!scrollbar->enabled())
 
567
        trackInfo.enableState = kThemeTrackDisabled;
 
568
    else
 
569
        trackInfo.enableState = scrollbar->isScrollableAreaActive() ? kThemeTrackActive : kThemeTrackInactive;
 
570
 
 
571
    if (hasThumb(scrollbar))
 
572
        trackInfo.attributes |= kThemeTrackShowThumb;
 
573
    else if (!hasButtons(scrollbar))
 
574
        trackInfo.enableState = kThemeTrackNothingToScroll;
 
575
    trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar->pressedPart());
 
576
    
 
577
    // The Aqua scrollbar is buggy when rotated and scaled. We will just draw into a bitmap if we detect a scale or rotation.
 
578
    // FIXME: This workaround is unnecessary for integral scale factors.
 
579
    bool canDrawDirectly = context->getCTM().isIdentityOrTranslationOrFlipped();
 
580
    if (canDrawDirectly)
 
581
        HIThemeDrawTrack(&trackInfo, 0, context->platformContext(), kHIThemeOrientationNormal);
 
582
    else {
 
583
        trackInfo.bounds = IntRect(IntPoint(), scrollbar->frameRect().size());
 
584
        
 
585
        IntRect bufferRect(scrollbar->frameRect());
 
586
        bufferRect.intersect(damageRect);
 
587
        
 
588
        OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(bufferRect.size(), 1);
 
589
        if (!imageBuffer)
 
590
            return true;
 
591
 
 
592
        imageBuffer->context()->translate(scrollbar->frameRect().x() - bufferRect.x(), scrollbar->frameRect().y() - bufferRect.y());
 
593
        HIThemeDrawTrack(&trackInfo, 0, imageBuffer->context()->platformContext(), kHIThemeOrientationNormal);
 
594
        context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, bufferRect.location());
 
595
    }
 
596
 
 
597
    return true;
 
598
}
 
599
#endif
 
600
 
 
601
#if !PLATFORM(CHROMIUM) && USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING)
 
602
static RetainPtr<CGColorRef> linenBackgroundColor()
 
603
{
 
604
    NSImage *image = [NSColor _linenPatternImage];
 
605
    CGImageRef cgImage = [image CGImageForProposedRect:NULL context:NULL hints:nil];
 
606
 
 
607
    RetainPtr<CGPatternRef> pattern = adoptCF(wkCGPatternCreateWithImageAndTransform(cgImage, CGAffineTransformIdentity, wkPatternTilingNoDistortion));
 
608
    RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreatePattern(0));
 
609
 
 
610
    const CGFloat alpha = 1.0;
 
611
    return adoptCF(CGColorCreateWithPattern(colorSpace.get(), pattern.get(), &alpha));
 
612
}
 
613
 
 
614
void ScrollbarThemeMac::setUpOverhangAreasLayerContents(GraphicsLayer* graphicsLayer)
 
615
{
 
616
    static CGColorRef cachedLinenBackgroundColor = linenBackgroundColor().leakRef();
 
617
 
 
618
    // We operate on the CALayer directly here, since GraphicsLayer doesn't have the concept
 
619
    // of pattern images, and we know that WebCore won't touch this layer.
 
620
    graphicsLayer->platformLayer().backgroundColor = cachedLinenBackgroundColor;
 
621
}
 
622
 
 
623
void ScrollbarThemeMac::setUpContentShadowLayer(GraphicsLayer* graphicsLayer)
 
624
{
 
625
    // We operate on the CALayer directly here, since GraphicsLayer doesn't have the concept
 
626
    // of shadows, and we know that WebCore won't touch this layer.
 
627
    CALayer *contentShadowLayer = graphicsLayer->platformLayer();
 
628
 
 
629
    static const CGFloat shadowOpacity = 0.66;
 
630
    static const CGFloat shadowRadius = 3;
 
631
 
 
632
    // We only need to set these shadow properties once.
 
633
    if (!contentShadowLayer.shadowOpacity) {
 
634
        contentShadowLayer.shadowColor = CGColorGetConstantColor(kCGColorBlack);
 
635
        contentShadowLayer.shadowOffset = CGSizeZero;
 
636
        contentShadowLayer.shadowOpacity = shadowOpacity;
 
637
        contentShadowLayer.shadowRadius = shadowRadius;
 
638
    }
 
639
 
 
640
    RetainPtr<CGPathRef> shadowPath = adoptCF(CGPathCreateWithRect(CGRectMake(0, 0, graphicsLayer->size().width(), graphicsLayer->size().height()), NULL));
 
641
    contentShadowLayer.shadowPath = shadowPath.get();
 
642
}
 
643
 
 
644
#endif
 
645
 
 
646
} // namespace WebCore