2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Brent Fulgham
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 COMPUTER, 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.
29 #include "PlatformScrollBar.h"
31 #include "EventHandler.h"
32 #include "FrameView.h"
34 #include "GraphicsContext.h"
36 #include "PlatformMouseEvent.h"
37 #include "SoftLinking.h"
40 #include "RenderThemeWin.h"
42 // Generic state constants
49 #define ABS_UPNORMAL 1
50 #define ABS_DOWNNORMAL 5
51 #define ABS_LEFTNORMAL 9
52 #define ABS_RIGHTNORMAL 13
54 static const unsigned SP_ABS_HOT_MODIFIER = 1;
55 static const unsigned SP_ABS_PRESSED_MODIFIER = 2;
56 static const unsigned SP_ABS_DISABLE_MODIFIER = 3;
58 // Scrollbar constants
61 #define SP_THUMBVERT 3
62 #define SP_TRACKSTARTHOR 4
63 #define SP_TRACKENDHOR 5
64 #define SP_TRACKSTARTVERT 6
65 #define SP_TRACKENDVERT 7
66 #define SP_GRIPPERHOR 8
67 #define SP_GRIPPERVERT 9
73 // FIXME: We should get these numbers from SafariTheme
74 static int cHorizontalWidth;
75 static int cHorizontalHeight;
76 static int cVerticalWidth;
77 static int cVerticalHeight;
78 static int cHorizontalButtonWidth;
79 static int cVerticalButtonHeight;
80 static int cRealButtonLength = 28;
81 static int cButtonInset = 14;
82 static int cButtonHitInset = 3;
83 // cRealButtonLength - cButtonInset
84 static int cThumbWidth;
85 static int cThumbHeight;
86 static int cThumbMinLength = 26;
88 static HANDLE cScrollBarTheme = 0;
90 // FIXME: Refactor the soft-linking code so that it can be shared with RenderThemeWin
91 SOFT_LINK_LIBRARY(uxtheme)
92 SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
93 SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
94 SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
95 SOFT_LINK(uxtheme, DrawThemeEdge, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, unsigned uEdge, unsigned uFlags, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, uEdge, uFlags, pClipRect))
96 SOFT_LINK(uxtheme, GetThemeContentRect, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pContentRect), (hTheme, hdc, iPartId, iStateId, pRect, pContentRect))
97 SOFT_LINK(uxtheme, GetThemePartSize, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, RECT* pRect, int ts, SIZE* psz), (hTheme, hdc, iPartId, iStateId, pRect, ts, psz))
98 SOFT_LINK(uxtheme, GetThemeSysFont, HRESULT, WINAPI, (HANDLE hTheme, int iFontId, OUT LOGFONT* pFont), (hTheme, iFontId, pFont))
99 SOFT_LINK(uxtheme, GetThemeColor, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, int iPropId, OUT COLORREF* pColor), (hTheme, hdc, iPartId, iStateId, iPropId, pColor))
101 static void checkAndInitScrollbarTheme()
103 if (uxthemeLibrary() && !cScrollBarTheme)
104 cScrollBarTheme = OpenThemeData(0, L"Scrollbar");
107 // May need to add stuff to these later, so keep the graphics context retrieval/release in some helpers.
108 static HDC prepareForDrawing(GraphicsContext* g, const IntRect& r)
110 return g->getWindowsContext(r);
113 static void doneDrawing(GraphicsContext* g, HDC hdc, const IntRect& r)
115 g->releaseWindowsContext(hdc, r);
117 // End Copied from RenderThemeWin
119 const double cInitialTimerDelay = 0.25;
120 const double cNormalTimerDelay = 0.05;
122 PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
123 : Scrollbar(client, orientation, size)
124 , m_hoveredPart(NoPart)
125 , m_pressedPart(NoPart)
127 , m_scrollTimer(this, &PlatformScrollbar::autoscrollTimerFired)
128 , m_overlapsResizer(false)
130 // Obtain the correct scrollbar sizes from the system.
131 // FIXME: We should update these on a WM_SETTINGSCHANGE, too.
132 if (!cHorizontalHeight) {
133 cHorizontalHeight = ::GetSystemMetrics(SM_CYHSCROLL);
134 cHorizontalWidth = ::GetSystemMetrics(SM_CXHSCROLL);
135 cVerticalHeight = ::GetSystemMetrics(SM_CYVSCROLL);
136 cVerticalWidth = ::GetSystemMetrics(SM_CXVSCROLL);
137 cThumbWidth = ::GetSystemMetrics(SM_CXHTHUMB);
138 cThumbHeight = ::GetSystemMetrics(SM_CYVTHUMB);
139 cHorizontalButtonWidth = ::GetSystemMetrics(SM_CYVSCROLL);
140 cVerticalButtonHeight = ::GetSystemMetrics(SM_CXHSCROLL);
143 if (orientation == VerticalScrollbar)
144 setFrameGeometry(IntRect(0, 0, cVerticalWidth, cVerticalHeight));
146 setFrameGeometry(IntRect(0, 0, cHorizontalWidth, cHorizontalHeight));
149 PlatformScrollbar::~PlatformScrollbar()
154 void PlatformScrollbar::updateThumbPosition()
159 void PlatformScrollbar::updateThumbProportion()
164 static IntRect trackRepaintRect(const IntRect& trackRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
166 const int cButtonLength = (orientation == VerticalScrollbar) ? cVerticalButtonHeight : cHorizontalButtonWidth;
168 IntRect paintRect(trackRect);
169 if (orientation == HorizontalScrollbar)
170 paintRect.inflateX(cButtonLength);
172 paintRect.inflateY(cButtonLength);
177 static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
179 IntRect paintRect(buttonRect);
180 if (orientation == HorizontalScrollbar) {
181 paintRect.setWidth(cRealButtonLength);
183 paintRect.setX(buttonRect.x() - (cRealButtonLength - buttonRect.width()));
185 paintRect.setHeight(cRealButtonLength);
187 paintRect.setY(buttonRect.y() - (cRealButtonLength - buttonRect.height()));
193 void PlatformScrollbar::invalidateTrack()
195 IntRect rect = trackRepaintRect(trackRect(), m_orientation, controlSize());
196 rect.move(-x(), -y());
197 invalidateRect(rect);
200 void PlatformScrollbar::invalidatePart(ScrollbarPart part)
208 result = buttonRepaintRect(backButtonRect(), m_orientation, controlSize(), true);
210 case ForwardButtonPart:
211 result = buttonRepaintRect(forwardButtonRect(), m_orientation, controlSize(), false);
214 IntRect beforeThumbRect, thumbRect, afterThumbRect;
215 splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
216 if (part == BackTrackPart)
217 result = beforeThumbRect;
218 else if (part == ForwardTrackPart)
219 result = afterThumbRect;
224 result.move(-x(), -y());
225 invalidateRect(result);
228 int PlatformScrollbar::width() const
230 return Widget::width();
233 int PlatformScrollbar::height() const
235 return Widget::height();
238 void PlatformScrollbar::setRect(const IntRect& rect)
240 // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
242 IntRect adjustedRect(rect);
243 if (parent() && parent()->isFrameView()) {
244 bool overlapsResizer = false;
245 FrameView* view = static_cast<FrameView*>(parent());
246 IntRect resizerRect = view->windowResizerRect();
247 resizerRect.setLocation(view->convertFromContainingWindow(resizerRect.location()));
248 if (rect.intersects(resizerRect)) {
249 if (orientation() == HorizontalScrollbar) {
250 int overlap = rect.right() - resizerRect.x();
251 if (overlap > 0 && resizerRect.right() >= rect.right()) {
252 adjustedRect.setWidth(rect.width() - overlap);
253 overlapsResizer = true;
256 int overlap = rect.bottom() - resizerRect.y();
257 if (overlap > 0 && resizerRect.bottom() >= rect.bottom()) {
258 adjustedRect.setHeight(rect.height() - overlap);
259 overlapsResizer = true;
264 if (overlapsResizer != m_overlapsResizer) {
265 m_overlapsResizer = overlapsResizer;
266 view->adjustOverlappingScrollbarCount(m_overlapsResizer ? 1 : -1);
270 setFrameGeometry(adjustedRect);
273 void PlatformScrollbar::setParent(ScrollView* parentView)
275 if (!parentView && m_overlapsResizer && parent() && parent()->isFrameView())
276 static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(-1);
277 Widget::setParent(parentView);
280 void PlatformScrollbar::setEnabled(bool enabled)
282 if (enabled != isEnabled()) {
283 Widget::setEnabled(enabled);
288 void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect)
290 if (graphicsContext->updatingControlTints()) {
295 if (graphicsContext->paintingDisabled())
298 // Don't paint anything if the scrollbar doesn't intersect the damage rect.
299 if (!frameGeometry().intersects(damageRect))
302 IntRect track = trackRect();
303 paintTrack(graphicsContext, track, true, damageRect);
306 paintButton(graphicsContext, backButtonRect(), true, damageRect);
307 paintButton(graphicsContext, forwardButtonRect(), false, damageRect);
310 if (hasThumb() && damageRect.intersects(track)) {
311 IntRect startTrackRect, thumbRect, endTrackRect;
312 splitTrack(track, startTrackRect, thumbRect, endTrackRect);
313 paintThumb(graphicsContext, thumbRect, damageRect);
317 bool PlatformScrollbar::hasButtons() const
319 return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * (cRealButtonLength - cButtonHitInset);
322 bool PlatformScrollbar::hasThumb() const
324 return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * cButtonInset + cThumbMinLength + 1;
327 IntRect PlatformScrollbar::backButtonRect() const
329 // Our actual rect will shrink to half the available space when
330 // we have < 34 pixels left. This allows the scrollbar
331 // to scale down and function even at tiny sizes.
332 if (m_orientation == HorizontalScrollbar)
333 return IntRect(x(), y(), cHorizontalButtonWidth, cHorizontalHeight);
334 return IntRect(x(), y(), cVerticalWidth, cVerticalButtonHeight);
337 IntRect PlatformScrollbar::forwardButtonRect() const
339 // Our desired rect is essentially 17x17.
341 // Our actual rect will shrink to half the available space when
342 // we have < 34 pixels left. This allows the scrollbar
343 // to scale down and function even at tiny sizes.
344 if (m_orientation == HorizontalScrollbar)
345 return IntRect(x() + width() - cHorizontalButtonWidth, y(), cHorizontalButtonWidth, cHorizontalHeight);
346 return IntRect(x(), y() + height() - cVerticalButtonHeight, cVerticalWidth, cVerticalButtonHeight);
349 IntRect PlatformScrollbar::trackRect() const
351 if (m_orientation == HorizontalScrollbar) {
353 return IntRect(x(), y(), width(), cHorizontalHeight);
354 return IntRect(x() + cHorizontalButtonWidth, y(), width() - 2 * cHorizontalButtonWidth, cHorizontalHeight);
358 return IntRect(x(), y(), cVerticalWidth, height());
359 return IntRect(x(), y() + cVerticalButtonHeight, cVerticalWidth, height() - 2 * cVerticalButtonHeight);
362 IntRect PlatformScrollbar::thumbRect() const
364 IntRect beforeThumbRect, thumbRect, afterThumbRect;
365 splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
369 IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
374 void PlatformScrollbar::splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const
376 // This function won't even get called unless we're big enough to have some combination of these three rects where at least
377 // one of them is non-empty.
378 int thumbPos = thumbPosition();
379 if (m_orientation == HorizontalScrollbar) {
380 thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - cThumbHeight) / 2, thumbLength(), cThumbHeight);
381 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos, trackRect.height());
382 afterThumbRect = IntRect(thumbRect.x() + thumbRect.width(), trackRect.y(), trackRect.right() - thumbRect.right(), trackRect.height());
384 thumbRect = IntRect(trackRect.x() + (trackRect.width() - cThumbWidth) / 2, trackRect.y() + thumbPos, cThumbWidth, thumbLength());
385 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos);
386 afterThumbRect = IntRect(trackRect.x(), thumbRect.y() + thumbRect.height(), trackRect.width(), trackRect.bottom() - thumbRect.bottom());
390 int PlatformScrollbar::thumbPosition() const
393 return (float)m_currentPos * (trackLength() - thumbLength()) / (m_totalSize - m_visibleSize);
397 int PlatformScrollbar::thumbLength() const
402 float proportion = (float)(m_visibleSize) / m_totalSize;
403 int trackLen = trackLength();
404 int length = proportion * trackLen;
405 int minLength = cThumbMinLength;
406 length = max(length, minLength);
407 if (length > trackLen)
408 length = 0; // Once the thumb is below the track length, it just goes away (to make more room for the track).
412 int PlatformScrollbar::trackLength() const
414 return (m_orientation == HorizontalScrollbar) ? trackRect().width() : trackRect().height();
417 void PlatformScrollbar::paintButton(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
419 IntRect paintRect = buttonRepaintRect(rect, m_orientation, controlSize(), start);
421 if (!damageRect.intersects(paintRect))
426 unsigned classicPart = 0;
427 unsigned classicState = 0;
429 if (m_orientation == HorizontalScrollbar) {
430 state = start ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL;
431 classicPart = start ? DFCS_SCROLLLEFT : DFCS_SCROLLRIGHT;
433 state = start ? ABS_UPNORMAL : ABS_DOWNNORMAL;
434 classicPart = start ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
438 state += SP_ABS_DISABLE_MODIFIER;
439 classicState |= DFCS_INACTIVE;
440 } else if ((m_pressedPart == BackButtonPart && start)
441 || (m_pressedPart == ForwardButtonPart && !start)) {
442 state += SP_ABS_PRESSED_MODIFIER;
443 classicState |= DFCS_PUSHED | DFCS_FLAT;
444 } else if (m_client->isActive()) {
445 state += SP_ABS_HOT_MODIFIER;
446 classicState |= DFCS_HOT;
449 HDC hdc = prepareForDrawing(context, rect);
450 RECT widgetRect = rect;
451 checkAndInitScrollbarTheme();
454 DrawThemeBackground(cScrollBarTheme, hdc, SP_BUTTON, state, &widgetRect, NULL);
456 DrawFrameControl(hdc, &widgetRect, classicPart, classicState);
458 doneDrawing(context, hdc, rect);
461 void PlatformScrollbar::paintTrack(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
463 IntRect paintRect = hasButtons() ? trackRepaintRect(rect, m_orientation, controlSize()) : rect;
465 if (!damageRect.intersects(paintRect))
469 unsigned classicPart = DFC_SCROLL;
470 if (m_orientation == HorizontalScrollbar)
471 part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
473 part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;
475 unsigned state = TS_DISABLED;
476 unsigned classicState = DFCS_MONO;
477 if (m_client->isActive())
480 classicState |= DFCS_INACTIVE;
485 HDC hdc = prepareForDrawing(context, rect);
486 RECT widgetRect = rect;
487 checkAndInitScrollbarTheme();
490 DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
492 DrawFrameControl(hdc, &widgetRect, DFC_SCROLL, classicState);
494 doneDrawing(context, hdc, rect);
497 void PlatformScrollbar::paintThumb(GraphicsContext* context, const IntRect& rect, const IntRect& damageRect) const
499 if (!damageRect.intersects(rect))
502 unsigned part = (m_orientation == HorizontalScrollbar) ? SP_THUMBHOR : SP_THUMBVERT;
506 state += SP_ABS_DISABLE_MODIFIER;
507 else if (m_client->isActive())
508 state += SP_ABS_HOT_MODIFIER;
510 HDC hdc = prepareForDrawing(context, rect);
511 RECT widgetRect = rect;
512 checkAndInitScrollbarTheme();
514 if (cScrollBarTheme) {
515 DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
516 paintGripper(hdc, widgetRect);
518 HGDIOBJ hSaveBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
519 DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT);
520 SelectObject(hdc,hSaveBrush);
523 doneDrawing(context, hdc, rect);
526 void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
528 unsigned part = (m_orientation == HorizontalScrollbar) ? SP_GRIPPERHOR : SP_GRIPPERVERT;
531 if (m_client->isActive())
534 RECT widgetRect = rect;
535 checkAndInitScrollbarTheme();
538 DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
541 ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt)
546 IntPoint mousePosition = convertFromContainingWindow(evt.pos());
547 mousePosition.move(x(), y());
550 if (backButtonRect().contains(mousePosition))
551 return BackButtonPart;
553 if (forwardButtonRect().contains(mousePosition))
554 return ForwardButtonPart;
560 IntRect track = trackRect();
561 if (track.contains(mousePosition)) {
562 IntRect beforeThumbRect, thumbRect, afterThumbRect;
563 splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect);
564 if (beforeThumbRect.contains(mousePosition))
565 return BackTrackPart;
566 if (thumbRect.contains(mousePosition))
568 return ForwardTrackPart;
574 bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt)
576 if (m_pressedPart == ThumbPart) {
578 int thumbPos = thumbPosition();
579 int thumbLen = thumbLength();
580 int trackLen = trackLength();
581 int maxPos = trackLen - thumbLen;
583 if (m_orientation == HorizontalScrollbar)
584 delta = convertFromContainingWindow(evt.pos()).x() - m_pressedPos;
586 delta = convertFromContainingWindow(evt.pos()).y() - m_pressedPos;
589 // The mouse moved down/right.
590 delta = min(maxPos - thumbPos, delta);
592 // The mouse moved up/left.
593 delta = max(-thumbPos, delta);
596 setValue((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen));
597 m_pressedPos += thumbPosition() - thumbPos;
603 if (m_pressedPart != NoPart)
604 m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
606 ScrollbarPart part = hitTest(evt);
607 if (part != m_hoveredPart) {
608 if (m_pressedPart != NoPart) {
609 if (part == m_pressedPart) {
610 // The mouse is moving back over the pressed part. We
611 // need to start up the timer action again.
612 startTimerIfNeeded(cNormalTimerDelay);
613 invalidatePart(m_pressedPart);
614 } else if (m_hoveredPart == m_pressedPart) {
615 // The mouse is leaving the pressed part. Kill our timer
618 invalidatePart(m_pressedPart);
621 invalidatePart(part);
622 invalidatePart(m_hoveredPart);
624 m_hoveredPart = part;
630 bool PlatformScrollbar::handleMouseOutEvent(const PlatformMouseEvent& evt)
632 invalidatePart(m_hoveredPart);
633 m_hoveredPart = NoPart;
638 bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt)
640 m_pressedPart = hitTest(evt);
641 m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
642 invalidatePart(m_pressedPart);
643 autoscrollPressedPart(cInitialTimerDelay);
647 bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& evt)
649 invalidatePart(m_pressedPart);
650 m_pressedPart = NoPart;
654 if (parent() && parent()->isFrameView())
655 static_cast<FrameView*>(parent())->frame()->eventHandler()->setMousePressed(false);
660 void PlatformScrollbar::startTimerIfNeeded(double delay)
662 // Don't do anything for the thumb.
663 if (m_pressedPart == ThumbPart)
666 // Handle the track. We halt track scrolling once the thumb is level
668 if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
669 invalidatePart(m_pressedPart);
670 m_hoveredPart = ThumbPart;
674 // We can't scroll if we've hit the beginning or end.
675 ScrollDirection dir = pressedPartScrollDirection();
676 if (dir == ScrollUp || dir == ScrollLeft) {
677 if (m_currentPos == 0)
680 if (m_currentPos == m_totalSize - m_visibleSize)
684 m_scrollTimer.startOneShot(delay);
687 void PlatformScrollbar::stopTimerIfNeeded()
689 if (m_scrollTimer.isActive())
690 m_scrollTimer.stop();
693 void PlatformScrollbar::autoscrollPressedPart(double delay)
695 // Don't do anything for the thumb or if nothing was pressed.
696 if (m_pressedPart == ThumbPart || m_pressedPart == NoPart)
700 if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
701 invalidatePart(m_pressedPart);
702 m_hoveredPart = ThumbPart;
706 // Handle the arrows and track.
707 if (scroll(pressedPartScrollDirection(), pressedPartScrollGranularity()))
708 startTimerIfNeeded(delay);
711 void PlatformScrollbar::autoscrollTimerFired(Timer<PlatformScrollbar>*)
713 autoscrollPressedPart(cNormalTimerDelay);
716 ScrollDirection PlatformScrollbar::pressedPartScrollDirection()
718 if (m_orientation == HorizontalScrollbar) {
719 if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
723 if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
729 ScrollGranularity PlatformScrollbar::pressedPartScrollGranularity()
731 if (m_pressedPart == BackButtonPart || m_pressedPart == ForwardButtonPart)
736 bool PlatformScrollbar::thumbUnderMouse()
739 IntRect thumb = thumbRect();
740 thumb.move(-x(), -y());
741 int begin = (m_orientation == HorizontalScrollbar) ? thumb.x() : thumb.y();
742 int end = (m_orientation == HorizontalScrollbar) ? thumb.right() : thumb.bottom();
743 return (begin <= m_pressedPos && m_pressedPos < end);
746 int PlatformScrollbar::horizontalScrollbarHeight(ScrollbarControlSize controlSize)
748 return cHorizontalWidth;
751 int PlatformScrollbar::verticalScrollbarWidth(ScrollbarControlSize controlSize)
753 return cVerticalHeight;
756 IntRect PlatformScrollbar::windowClipRect() const
758 IntRect clipRect(0, 0, width(), height());
760 clipRect = convertToContainingWindow(clipRect);
762 clipRect.intersect(m_client->windowClipRect());
767 void PlatformScrollbar::themeChanged()