Don't crash if SafariTheme can't be loaded
[WebKit-https.git] / WebCore / platform / win / PlatformScrollBarSafari.cpp
1 /*
2  * Copyright (C) 2007 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 COMPUTER, 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 COMPUTER, 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
28 #ifdef USE_SAFARI_THEME 
29
30 #include "PlatformScrollBar.h"
31
32 #include "EventHandler.h"
33 #include "FrameView.h"
34 #include "Frame.h"
35 #include "GraphicsContext.h"
36 #include "IntRect.h"
37 #include "PlatformMouseEvent.h"
38
39 #include <CoreGraphics/CoreGraphics.h>
40 #include <SafariTheme/SafariTheme.h>
41
42 // FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow.
43
44 using namespace std;
45
46 namespace WebCore {
47
48 using namespace SafariTheme;
49
50 // FIXME: We should get these numbers from SafariTheme
51 static int cHorizontalWidth[] = { 15, 11 };
52 static int cHorizontalHeight[] = { 15, 11 };
53 static int cVerticalWidth[] = { 15, 11 };
54 static int cVerticalHeight[] = { 15, 11 };
55 static int cRealButtonLength[] = { 28, 21 };
56 static int cButtonInset[] = { 14, 11 };
57 // cRealButtonLength - cButtonInset
58 static int cButtonLength[] = { 14, 10 };
59 static int cThumbWidth[] = { 15, 11 };
60 static int cThumbHeight[] = { 15, 11 };
61 static int cThumbMinLength[] = { 26, 20 };
62
63 static paintThemePartPtr paintThemePart;
64
65 static HMODULE themeDLL;
66
67 const double cInitialTimerDelay = 0.25;
68 const double cNormalTimerDelay = 0.05;
69
70 PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
71     : Scrollbar(client, orientation, size), m_hoveredPart(NoPart), m_pressedPart(NoPart), m_pressedPos(0),
72       m_scrollTimer(this, &PlatformScrollbar::autoscrollTimerFired),
73       m_overlapsResizer(false)
74 {
75     // Obtain the correct scrollbar sizes from the system.
76     if (!cHorizontalWidth) {
77         // FIXME: Get metics from SafariTheme
78     }
79
80     if (!themeDLL)
81         themeDLL = ::LoadLibrary(SAFARITHEMEDLL);
82
83     if (themeDLL)
84         paintThemePart = (paintThemePartPtr)GetProcAddress(themeDLL, "paintThemePart");
85
86     if (orientation == VerticalScrollbar)
87         setFrameGeometry(IntRect(0, 0, cVerticalWidth[controlSize()], cVerticalHeight[controlSize()]));
88     else
89         setFrameGeometry(IntRect(0, 0, cHorizontalWidth[controlSize()], cHorizontalHeight[controlSize()]));
90 }
91
92 PlatformScrollbar::~PlatformScrollbar()
93 {
94     stopTimerIfNeeded();
95 }
96
97 void PlatformScrollbar::updateThumbPosition()
98 {
99     invalidateTrack();
100 }
101
102 void PlatformScrollbar::updateThumbProportion()
103 {
104     invalidateTrack();
105 }
106
107 static IntRect trackRepaintRect(const IntRect& trackRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
108 {
109     IntRect paintRect(trackRect);
110     if (orientation == HorizontalScrollbar)
111         paintRect.inflateX(cButtonLength[controlSize]);
112     else
113         paintRect.inflateY(cButtonLength[controlSize]);
114
115     return paintRect;
116 }
117
118 static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
119 {
120     IntRect paintRect(buttonRect);
121     if (orientation == HorizontalScrollbar) {
122         paintRect.setWidth(cRealButtonLength[controlSize]);
123         if (!start)
124             paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width()));
125     } else {
126         paintRect.setHeight(cRealButtonLength[controlSize]);
127         if (!start)
128             paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height()));
129     }
130
131     return paintRect;
132 }
133
134 void PlatformScrollbar::invalidateTrack()
135 {
136     IntRect rect = trackRepaintRect(trackRect(), m_orientation, controlSize());
137     rect.move(-x(), -y());
138     invalidateRect(rect);
139 }
140
141 void PlatformScrollbar::invalidatePart(ScrollbarPart part)
142 {
143     if (part == NoPart)
144         return;
145
146     IntRect result;    
147     switch (part) {
148         case BackButtonPart:
149             result = buttonRepaintRect(backButtonRect(), m_orientation, controlSize(), true);
150             break;
151         case ForwardButtonPart:
152             result = buttonRepaintRect(forwardButtonRect(), m_orientation, controlSize(), false);
153             break;
154         default: {
155             IntRect beforeThumbRect, thumbRect, afterThumbRect;
156             splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
157             if (part == BackTrackPart)
158                 result = beforeThumbRect;
159             else if (part == ForwardTrackPart)
160                 result = afterThumbRect;
161             else
162                 result = thumbRect;
163         }
164     }
165     result.move(-x(), -y());
166     invalidateRect(result);
167 }
168
169 int PlatformScrollbar::width() const
170 {
171     return Widget::width();
172 }
173
174 int PlatformScrollbar::height() const
175 {
176     return Widget::height();
177 }
178
179 void PlatformScrollbar::setRect(const IntRect& rect)
180 {
181     // Get our window resizer rect and see if we overlap.  Adjust to avoid the overlap
182     // if necessary.
183     IntRect adjustedRect(rect);
184     if (parent() && parent()->isFrameView()) {
185         bool overlapsResizer = false;
186         FrameView* view = static_cast<FrameView*>(parent());
187         IntRect resizerRect = view->windowResizerRect();
188         resizerRect.setLocation(view->convertFromContainingWindow(resizerRect.location()));
189         if (rect.intersects(resizerRect)) {
190             if (orientation() == HorizontalScrollbar) {
191                 int overlap = rect.right() - resizerRect.x();
192                 if (overlap > 0 && resizerRect.right() >= rect.right()) {
193                     adjustedRect.setWidth(rect.width() - overlap);
194                     overlapsResizer = true;
195                 }
196             } else {
197                 int overlap = rect.bottom() - resizerRect.y();
198                 if (overlap > 0 && resizerRect.bottom() >= rect.bottom()) {
199                     adjustedRect.setHeight(rect.height() - overlap);
200                     overlapsResizer = true;
201                 }
202             }
203         }
204
205         if (overlapsResizer != m_overlapsResizer) {
206             m_overlapsResizer = overlapsResizer;
207             view->adjustOverlappingScrollbarCount(m_overlapsResizer ? 1 : -1);
208         }
209     }
210
211     setFrameGeometry(adjustedRect);
212 }
213
214 void PlatformScrollbar::setParent(ScrollView* parentView)
215 {
216     if (!parentView && m_overlapsResizer && parent() && parent()->isFrameView())
217         static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(-1);
218     Widget::setParent(parentView);
219 }
220
221 void PlatformScrollbar::setEnabled(bool enabled)
222 {
223     if (enabled != isEnabled()) {
224         Widget::setEnabled(enabled);
225         invalidate();
226     }
227 }
228
229 void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect)
230 {
231     if (graphicsContext->paintingDisabled())
232         return;
233
234     // Don't paint anything if the scrollbar doesn't intersect the damage rect.
235     if (!frameGeometry().intersects(damageRect))
236         return;
237
238     IntRect track = trackRect();
239     paintTrack(graphicsContext, track, true, damageRect);
240
241     if (isEnabled()) {
242         paintButton(graphicsContext, backButtonRect(), true, damageRect);
243         paintButton(graphicsContext, forwardButtonRect(), false, damageRect);
244     }
245
246     if (damageRect.intersects(track) && isEnabled()) {
247         IntRect startTrackRect, thumbRect, endTrackRect;
248         splitTrack(track, startTrackRect, thumbRect, endTrackRect);
249         paintThumb(graphicsContext, thumbRect, damageRect);
250     }
251 }
252
253 IntRect PlatformScrollbar::backButtonRect() const
254 {
255     // Our desired rect is essentially 17x17.
256     
257     // Our actual rect will shrink to half the available space when
258     // we have < 34 pixels left.  This allows the scrollbar
259     // to scale down and function even at tiny sizes.
260     if (m_orientation == HorizontalScrollbar)
261         return IntRect(x(), y(), cButtonLength[controlSize()], cHorizontalHeight[controlSize()]);
262     return IntRect(x(), y(), cVerticalWidth[controlSize()], cButtonLength[controlSize()]);
263 }
264
265 IntRect PlatformScrollbar::forwardButtonRect() const
266 {
267     // Our desired rect is essentially 17x17.
268     
269     // Our actual rect will shrink to half the available space when
270     // we have < 34 pixels left.  This allows the scrollbar
271     // to scale down and function even at tiny sizes.
272
273     if (m_orientation == HorizontalScrollbar)
274         return IntRect(x() + width() - cButtonLength[controlSize()], y(), cButtonLength[controlSize()], cHorizontalHeight[controlSize()]);
275     
276     return IntRect(x(), y() + height() - cButtonLength[controlSize()], cVerticalWidth[controlSize()], cButtonLength[controlSize()]);
277 }
278
279 IntRect PlatformScrollbar::trackRect() const
280 {
281     if (m_orientation == HorizontalScrollbar) {
282         if (width() < 2 * cHorizontalWidth[controlSize()])
283             return IntRect();
284         return IntRect(x() + cButtonLength[controlSize()], y(), width() - 2 * cButtonLength[controlSize()], cHorizontalHeight[controlSize()]);
285     }
286
287     if (height() < 2 * cVerticalHeight[controlSize()])
288         return IntRect();
289     return IntRect(x(), y() + cButtonLength[controlSize()], cVerticalWidth[controlSize()], height() - 2 * cButtonLength[controlSize()]);
290 }
291
292 IntRect PlatformScrollbar::thumbRect() const
293 {
294     IntRect beforeThumbRect, thumbRect, afterThumbRect;
295     splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
296     return thumbRect;
297 }
298
299 void PlatformScrollbar::splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const
300 {
301     // This function won't even get called unless we're big enough to have some combination of these three rects where at least
302     // one of them is non-empty.
303     int thumbPos = thumbPosition();
304     if (m_orientation == HorizontalScrollbar) {
305         thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - cThumbHeight[controlSize()]) / 2, thumbLength(), cThumbHeight[controlSize()]);
306         beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos, trackRect.height());
307         afterThumbRect = IntRect(thumbRect.x() + thumbRect.width(), trackRect.y(), trackRect.right() - thumbRect.right(), trackRect.height());
308     } else {
309         thumbRect = IntRect(trackRect.x() + (trackRect.width() - cThumbWidth[controlSize()]) / 2, trackRect.y() + thumbPos, cThumbWidth[controlSize()], thumbLength());
310         beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos);
311         afterThumbRect = IntRect(trackRect.x(), thumbRect.y() + thumbRect.height(), trackRect.width(), trackRect.bottom() - thumbRect.bottom());
312     }
313 }
314
315 int PlatformScrollbar::thumbPosition() const
316 {
317     if (isEnabled())
318         return (float)m_currentPos * (trackLength() - thumbLength()) / (m_totalSize - m_visibleSize);
319     return 0;
320 }
321
322 int PlatformScrollbar::thumbLength() const
323 {
324     if (!isEnabled())
325         return 0;
326
327     float proportion = (float)(m_visibleSize) / m_totalSize;
328     int trackLen = trackLength();
329     int length = proportion * trackLen;
330     int minLength = cThumbMinLength[controlSize()];
331     length = max(length, minLength);
332     if (length > trackLen)
333         length = 0; // Once the thumb is below the track length, it just goes away (to make more room for the track).
334     return length;
335 }
336
337 int PlatformScrollbar::trackLength() const
338 {
339     return (m_orientation == HorizontalScrollbar) ? trackRect().width() : trackRect().height();
340 }
341
342 void PlatformScrollbar::paintButton(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
343 {
344     if (!paintThemePart)
345         return;
346
347     IntRect paintRect = buttonRepaintRect(rect, m_orientation, controlSize(), start);
348     
349     if (!damageRect.intersects(paintRect))
350         return;
351
352     ThemePart part;
353     ThemeControlState state = 0;
354     if (m_orientation == HorizontalScrollbar)
355         part = start ? ScrollLeftArrowPart : ScrollRightArrowPart;
356     else
357         part = start ? ScrollUpArrowPart : ScrollDownArrowPart;
358
359     if (isEnabled())
360         state |= EnabledState;
361     if ((m_pressedPart == BackButtonPart && start)
362         || (m_pressedPart == ForwardButtonPart && !start))
363         state |= PressedState;
364
365     paintThemePart(part, context->platformContext(), paintRect, controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize, state);
366 }
367
368 void PlatformScrollbar::paintTrack(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
369 {
370     if (!paintThemePart)
371         return;
372
373     IntRect paintRect = trackRepaintRect(rect, m_orientation, controlSize());
374     
375     if (!damageRect.intersects(paintRect))
376         return;
377
378     ThemePart part = m_orientation == HorizontalScrollbar ? HScrollTrackPart : VScrollTrackPart;
379     ThemeControlState state = 0;
380     if (isEnabled())
381         state |= EnabledState;
382
383     paintThemePart(part, context->platformContext(), paintRect, controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize, state);
384 }
385
386 void PlatformScrollbar::paintThumb(GraphicsContext* context, const IntRect& rect, const IntRect& damageRect) const
387 {
388     if (!paintThemePart)
389         return;
390
391     if (!damageRect.intersects(rect))
392         return;
393
394     ThemePart part = m_orientation == HorizontalScrollbar ? HScrollThumbPart : VScrollThumbPart;
395     ThemeControlState state = 0;
396     if (isEnabled())
397         state |= EnabledState;
398
399     paintThemePart(part, context->platformContext(), rect, controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize, state);
400 }
401
402 ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt)
403 {
404     ScrollbarPart result = NoPart;
405     if (!isEnabled())
406         return result;
407
408     IntPoint mousePosition = convertFromContainingWindow(evt.pos());
409     mousePosition.move(x(), y());
410     if (backButtonRect().contains(mousePosition))
411         result = BackButtonPart;
412     else if (forwardButtonRect().contains(mousePosition))
413         result = ForwardButtonPart;
414     else {
415         IntRect track = trackRect();
416         if (track.contains(mousePosition)) {
417             IntRect beforeThumbRect, thumbRect, afterThumbRect;
418             splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect);
419             if (beforeThumbRect.contains(mousePosition))
420                 result = BackTrackPart;
421             else if (thumbRect.contains(mousePosition))
422                 result = ThumbPart;
423             else
424                 result = ForwardTrackPart;
425         }
426     }
427     return result;
428 }
429
430 bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt)
431 {
432     if (m_pressedPart == ThumbPart) {
433         // Drag the thumb.
434         int thumbPos = thumbPosition();
435         int thumbLen = thumbLength();
436         int trackLen = trackLength();
437         int maxPos = trackLen - thumbLen;
438         int delta = 0;
439         if (m_orientation == HorizontalScrollbar)
440             delta = convertFromContainingWindow(evt.pos()).x() - m_pressedPos;
441         else
442             delta = convertFromContainingWindow(evt.pos()).y() - m_pressedPos;
443
444         if (delta > 0)
445             // The mouse moved down/right.
446             delta = min(maxPos - thumbPos, delta);
447         else if (delta < 0)
448             // The mouse moved up/left.
449             delta = max(-thumbPos, delta);
450
451         if (delta != 0) {
452             setValue((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen));
453             m_pressedPos += thumbPosition() - thumbPos;
454         }
455         
456         return true;
457     }
458
459     if (m_pressedPart != NoPart)
460         m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
461
462     ScrollbarPart part = hitTest(evt);    
463     if (part != m_hoveredPart) {
464         if (m_pressedPart != NoPart) {
465             if (part == m_pressedPart) {
466                 // The mouse is moving back over the pressed part.  We
467                 // need to start up the timer action again.
468                 startTimerIfNeeded(cNormalTimerDelay);
469                 invalidatePart(m_pressedPart);
470             } else if (m_hoveredPart == m_pressedPart) {
471                 // The mouse is leaving the pressed part.  Kill our timer
472                 // if needed.
473                 stopTimerIfNeeded();
474                 invalidatePart(m_pressedPart);
475             }
476         } else {
477             invalidatePart(part);
478             invalidatePart(m_hoveredPart);
479         }
480         m_hoveredPart = part;
481     } 
482
483     return true;
484 }
485
486 bool PlatformScrollbar::handleMouseOutEvent(const PlatformMouseEvent& evt)
487 {
488     invalidatePart(m_hoveredPart);
489     m_hoveredPart = NoPart;
490
491     return true;
492 }
493
494 bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt)
495 {
496     m_pressedPart = hitTest(evt);
497     m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
498     invalidatePart(m_pressedPart);
499     autoscrollPressedPart(cInitialTimerDelay);
500     return true;
501 }
502
503 bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& evt)
504 {
505     invalidatePart(m_pressedPart);
506     m_pressedPart = NoPart;
507     m_pressedPos = 0;
508     stopTimerIfNeeded();
509
510     if (parent() && parent()->isFrameView())
511         static_cast<FrameView*>(parent())->frame()->eventHandler()->setMousePressed(false);
512
513     return true;
514 }
515
516 void PlatformScrollbar::startTimerIfNeeded(double delay)
517 {
518     // Don't do anything for the thumb.
519     if (m_pressedPart == ThumbPart)
520         return;
521
522     // Handle the track.  We halt track scrolling once the thumb is level
523     // with us.
524     if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
525         invalidatePart(m_pressedPart);
526         m_hoveredPart = ThumbPart;
527         return;
528     }
529
530     // We can't scroll if we've hit the beginning or end.
531     ScrollDirection dir = pressedPartScrollDirection();
532     if (dir == ScrollUp || dir == ScrollLeft) {
533         if (m_currentPos == 0)
534             return;
535     } else {
536         if (m_currentPos == m_totalSize - m_visibleSize)
537             return;
538     }
539
540     m_scrollTimer.startOneShot(delay);
541 }
542
543 void PlatformScrollbar::stopTimerIfNeeded()
544 {
545     if (m_scrollTimer.isActive())
546         m_scrollTimer.stop();
547 }
548
549 void PlatformScrollbar::autoscrollPressedPart(double delay)
550 {
551     // Don't do anything for the thumb or if nothing was pressed.
552     if (m_pressedPart == ThumbPart || m_pressedPart == NoPart)
553         return;
554
555     // Handle the track.
556     if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
557         invalidatePart(m_pressedPart);
558         m_hoveredPart = ThumbPart;
559         return;
560     }
561
562     // Handle the arrows and track.
563     if (scroll(pressedPartScrollDirection(), pressedPartScrollGranularity()))
564         startTimerIfNeeded(delay);
565 }
566
567 void PlatformScrollbar::autoscrollTimerFired(Timer<PlatformScrollbar>*)
568 {
569     autoscrollPressedPart(cNormalTimerDelay);
570 }
571
572 ScrollDirection PlatformScrollbar::pressedPartScrollDirection()
573 {
574     if (m_orientation == HorizontalScrollbar) {
575         if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
576             return ScrollLeft;
577         return ScrollRight;
578     } else {
579         if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
580             return ScrollUp;
581         return ScrollDown;
582     }
583 }
584
585 ScrollGranularity PlatformScrollbar::pressedPartScrollGranularity()
586 {
587     if (m_pressedPart == BackButtonPart || m_pressedPart == ForwardButtonPart)
588         return ScrollByLine;
589     return ScrollByPage;
590 }
591
592 bool PlatformScrollbar::thumbUnderMouse()
593 {
594     // Construct a rect.
595     IntRect thumb = thumbRect();
596     thumb.move(-x(), -y());
597     int begin = (m_orientation == HorizontalScrollbar) ? thumb.x() : thumb.y();
598     int end = (m_orientation == HorizontalScrollbar) ? thumb.right() : thumb.bottom();
599     return (begin <= m_pressedPos && m_pressedPos < end);
600 }
601
602 int PlatformScrollbar::horizontalScrollbarHeight(ScrollbarControlSize controlSize)
603 {
604     return cHorizontalWidth[controlSize];
605 }
606
607 int PlatformScrollbar::verticalScrollbarWidth(ScrollbarControlSize controlSize)
608 {
609     return cVerticalHeight[controlSize];
610 }
611
612 IntRect PlatformScrollbar::windowClipRect() const
613 {
614     IntRect clipRect(0, 0, width(), height());
615     clipRect = convertToContainingWindow(clipRect);
616     if (m_client)
617         clipRect.intersect(m_client->windowClipRect());
618     return clipRect;
619 }
620
621 void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
622 {
623 }
624
625 IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
626 {
627     return IntRect();
628 }
629
630 void PlatformScrollbar::themeChanged()
631 {
632 }
633
634 }
635
636 #endif // defined(USE_SAFARI_THEME)