2008-02-29 Brent Fulgham <bfulgham@gmail.com>
authorpewtermoose@webkit.org <pewtermoose@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Mar 2008 00:29:22 +0000 (00:29 +0000)
committerpewtermoose@webkit.org <pewtermoose@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Mar 2008 00:29:22 +0000 (00:29 +0000)
JavaScriptCore:

        http://bugs.webkit.org/show_bug.cgi?id=17483
        Implement scrollbars on Windows (Cairo)

        Reviewed by Adam Roben.

        * wtf/Platform.h:

WebCore:

        http://bugs.webkit.org/show_bug.cgi?id=17483
        Implement scrollbars on Windows (Cairo)

        Reviewed by Adam Roben.

        * platform/win/PlatfromScrollBarWin.cpp: Duplicate implementation
          from PlatformScrollBarWinSafari.cpp, then modify to use the
          native Windows theme engine.  Use SOFT_LINK.  Use platform
          'GetSystemMetrics' call to decide size of scrollbars and buttons.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@30687 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/wtf/Platform.h
WebCore/ChangeLog
WebCore/platform/win/PlatformScrollBarWin.cpp [new file with mode: 0644]

index e6d64b4..a7ad558 100644 (file)
@@ -1,3 +1,12 @@
+2008-02-29  Brent Fulgham  <bfulgham@gmail.com>
+
+        http://bugs.webkit.org/show_bug.cgi?id=17483
+        Implement scrollbars on Windows (Cairo)
+
+        Reviewed by Adam Roben.
+
+        * wtf/Platform.h:
+
 2008-02-29  Adam Roben  <aroben@apple.com>
 
         Remove unused DebuggerImp::abort and DebuggerImp::aborted
index 5cde2fe..5396f8e 100644 (file)
 #define WTF_PLATFORM_CAIRO 1
 #endif
 
+#if PLATFORM(WIN)&& PLATFORM(CG)
+#define WTF_USE_SAFARI_THEME 1
+#endif
 
 #ifdef __S60__
 // we are cross-compiling, it is not really windows
index f35950c..df9c370 100644 (file)
@@ -1,3 +1,15 @@
+2008-02-29  Brent Fulgham  <bfulgham@gmail.com>
+
+        http://bugs.webkit.org/show_bug.cgi?id=17483
+        Implement scrollbars on Windows (Cairo)
+
+        Reviewed by Adam Roben.
+
+        * platform/win/PlatfromScrollBarWin.cpp: Duplicate implementation
+          from PlatformScrollBarWinSafari.cpp, then modify to use the
+          native Windows theme engine.  Use SOFT_LINK.  Use platform
+          'GetSystemMetrics' call to decide size of scrollbars and buttons.
+
 2008-02-29  Adam Roben  <aroben@apple.com>
 
         Windows build fix
diff --git a/WebCore/platform/win/PlatformScrollBarWin.cpp b/WebCore/platform/win/PlatformScrollBarWin.cpp
new file mode 100644 (file)
index 0000000..f59f27a
--- /dev/null
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2007 Apple Inc.  All rights reserved.
+ * Copyright (C) 2008 Brent Fulgham
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "PlatformScrollBar.h"
+
+#include "EventHandler.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "PlatformMouseEvent.h"
+#include "SoftLinking.h"
+
+#include <windows.h>
+#include "RenderThemeWin.h"
+
+// Generic state constants
+#define TS_NORMAL    1
+#define TS_HOVER     2
+#define TS_ACTIVE    3
+#define TS_DISABLED  4
+#define TS_FOCUSED   5
+
+#define ABS_UPNORMAL 1
+#define ABS_DOWNNORMAL 5
+#define ABS_LEFTNORMAL 9
+#define ABS_RIGHTNORMAL 13
+
+static const unsigned SP_ABS_HOT_MODIFIER = 1;
+static const unsigned SP_ABS_PRESSED_MODIFIER = 2;
+static const unsigned SP_ABS_DISABLE_MODIFIER = 3;
+
+// Scrollbar constants
+#define SP_BUTTON 1
+#define SP_THUMBHOR 2
+#define SP_THUMBVERT 3
+#define SP_TRACKSTARTHOR 4
+#define SP_TRACKENDHOR 5
+#define SP_TRACKSTARTVERT 6
+#define SP_TRACKENDVERT 7
+#define SP_GRIPPERHOR 8
+#define SP_GRIPPERVERT 9
+
+using namespace std;
+
+namespace WebCore {
+
+// FIXME: We should get these numbers from SafariTheme
+static int cHorizontalWidth;
+static int cHorizontalHeight;
+static int cVerticalWidth;
+static int cVerticalHeight;
+static int cHorizontalButtonWidth;
+static int cVerticalButtonHeight;
+static int cRealButtonLength = 28;
+static int cButtonInset = 14;
+static int cButtonHitInset = 3;
+// cRealButtonLength - cButtonInset
+static int cThumbWidth;
+static int cThumbHeight;
+static int cThumbMinLength = 26;
+
+static HANDLE cScrollBarTheme = 0;
+
+// FIXME:  Refactor the soft-linking code so that it can be shared with RenderThemeWin
+SOFT_LINK_LIBRARY(uxtheme)
+SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
+SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
+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))
+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))
+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))
+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))
+SOFT_LINK(uxtheme, GetThemeSysFont, HRESULT, WINAPI, (HANDLE hTheme, int iFontId, OUT LOGFONT* pFont), (hTheme, iFontId, pFont))
+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))
+
+static void checkAndInitScrollbarTheme()
+{
+    if (uxthemeLibrary() && !cScrollBarTheme)
+        cScrollBarTheme = OpenThemeData(0, L"Scrollbar");
+}
+
+// May need to add stuff to these later, so keep the graphics context retrieval/release in some helpers.
+static HDC prepareForDrawing(GraphicsContext* g, const IntRect& r)
+{
+    return g->getWindowsContext(r);
+}
+static void doneDrawing(GraphicsContext* g, HDC hdc, const IntRect& r)
+{
+    g->releaseWindowsContext(hdc, r);
+}
+// End Copied from RenderThemeWin
+
+const double cInitialTimerDelay = 0.25;
+const double cNormalTimerDelay = 0.05;
+
+PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
+    : Scrollbar(client, orientation, size)
+    , m_hoveredPart(NoPart)
+    , m_pressedPart(NoPart)
+    , m_pressedPos(0)
+    , m_scrollTimer(this, &PlatformScrollbar::autoscrollTimerFired)
+    , m_overlapsResizer(false)
+{
+    // Obtain the correct scrollbar sizes from the system.
+    // FIXME:  We should update these on a WM_SETTINGSCHANGE, too.
+    if (!cHorizontalHeight) {
+       cHorizontalHeight = ::GetSystemMetrics(SM_CYHSCROLL);
+       cHorizontalWidth = ::GetSystemMetrics(SM_CXHSCROLL);
+       cVerticalHeight = ::GetSystemMetrics(SM_CYVSCROLL);
+       cVerticalWidth = ::GetSystemMetrics(SM_CXVSCROLL);
+       cThumbWidth = ::GetSystemMetrics(SM_CXHTHUMB);
+       cThumbHeight = ::GetSystemMetrics(SM_CYVTHUMB);
+       cHorizontalButtonWidth = ::GetSystemMetrics(SM_CYVSCROLL);
+       cVerticalButtonHeight = ::GetSystemMetrics(SM_CXHSCROLL);
+    }
+
+    if (orientation == VerticalScrollbar)
+        setFrameGeometry(IntRect(0, 0, cVerticalWidth, cVerticalHeight));
+    else
+        setFrameGeometry(IntRect(0, 0, cHorizontalWidth, cHorizontalHeight));
+}
+
+PlatformScrollbar::~PlatformScrollbar()
+{
+    stopTimerIfNeeded();
+}
+
+void PlatformScrollbar::updateThumbPosition()
+{
+    invalidateTrack();
+}
+
+void PlatformScrollbar::updateThumbProportion()
+{
+    invalidateTrack();
+}
+
+static IntRect trackRepaintRect(const IntRect& trackRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
+{
+    const int cButtonLength = (orientation == VerticalScrollbar) ? cVerticalButtonHeight : cHorizontalButtonWidth;
+
+    IntRect paintRect(trackRect);
+    if (orientation == HorizontalScrollbar)
+        paintRect.inflateX(cButtonLength);
+    else
+        paintRect.inflateY(cButtonLength);
+
+    return paintRect;
+}
+
+static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
+{
+    IntRect paintRect(buttonRect);
+    if (orientation == HorizontalScrollbar) {
+        paintRect.setWidth(cRealButtonLength);
+        if (!start)
+            paintRect.setX(buttonRect.x() - (cRealButtonLength - buttonRect.width()));
+    } else {
+        paintRect.setHeight(cRealButtonLength);
+        if (!start)
+            paintRect.setY(buttonRect.y() - (cRealButtonLength - buttonRect.height()));
+    }
+
+    return paintRect;
+}
+
+void PlatformScrollbar::invalidateTrack()
+{
+    IntRect rect = trackRepaintRect(trackRect(), m_orientation, controlSize());
+    rect.move(-x(), -y());
+    invalidateRect(rect);
+}
+
+void PlatformScrollbar::invalidatePart(ScrollbarPart part)
+{
+    if (part == NoPart)
+        return;
+
+    IntRect result;    
+    switch (part) {
+        case BackButtonPart:
+            result = buttonRepaintRect(backButtonRect(), m_orientation, controlSize(), true);
+            break;
+        case ForwardButtonPart:
+            result = buttonRepaintRect(forwardButtonRect(), m_orientation, controlSize(), false);
+            break;
+        default: {
+            IntRect beforeThumbRect, thumbRect, afterThumbRect;
+            splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
+            if (part == BackTrackPart)
+                result = beforeThumbRect;
+            else if (part == ForwardTrackPart)
+                result = afterThumbRect;
+            else
+                result = thumbRect;
+        }
+    }
+    result.move(-x(), -y());
+    invalidateRect(result);
+}
+
+int PlatformScrollbar::width() const
+{
+    return Widget::width();
+}
+
+int PlatformScrollbar::height() const
+{
+    return Widget::height();
+}
+
+void PlatformScrollbar::setRect(const IntRect& rect)
+{
+    // Get our window resizer rect and see if we overlap.  Adjust to avoid the overlap
+    // if necessary.
+    IntRect adjustedRect(rect);
+    if (parent() && parent()->isFrameView()) {
+        bool overlapsResizer = false;
+        FrameView* view = static_cast<FrameView*>(parent());
+        IntRect resizerRect = view->windowResizerRect();
+        resizerRect.setLocation(view->convertFromContainingWindow(resizerRect.location()));
+        if (rect.intersects(resizerRect)) {
+            if (orientation() == HorizontalScrollbar) {
+                int overlap = rect.right() - resizerRect.x();
+                if (overlap > 0 && resizerRect.right() >= rect.right()) {
+                    adjustedRect.setWidth(rect.width() - overlap);
+                    overlapsResizer = true;
+                }
+            } else {
+                int overlap = rect.bottom() - resizerRect.y();
+                if (overlap > 0 && resizerRect.bottom() >= rect.bottom()) {
+                    adjustedRect.setHeight(rect.height() - overlap);
+                    overlapsResizer = true;
+                }
+            }
+        }
+
+        if (overlapsResizer != m_overlapsResizer) {
+            m_overlapsResizer = overlapsResizer;
+            view->adjustOverlappingScrollbarCount(m_overlapsResizer ? 1 : -1);
+        }
+    }
+
+    setFrameGeometry(adjustedRect);
+}
+
+void PlatformScrollbar::setParent(ScrollView* parentView)
+{
+    if (!parentView && m_overlapsResizer && parent() && parent()->isFrameView())
+        static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(-1);
+    Widget::setParent(parentView);
+}
+
+void PlatformScrollbar::setEnabled(bool enabled)
+{
+    if (enabled != isEnabled()) {
+        Widget::setEnabled(enabled);
+        invalidate();
+    }
+}
+
+void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect)
+{
+    if (graphicsContext->updatingControlTints()) {
+        invalidate();
+        return;
+    }
+
+    if (graphicsContext->paintingDisabled())
+        return;
+
+    // Don't paint anything if the scrollbar doesn't intersect the damage rect.
+    if (!frameGeometry().intersects(damageRect))
+        return;
+
+    IntRect track = trackRect();
+    paintTrack(graphicsContext, track, true, damageRect);
+
+    if (hasButtons()) {
+        paintButton(graphicsContext, backButtonRect(), true, damageRect);
+        paintButton(graphicsContext, forwardButtonRect(), false, damageRect);
+    }
+
+    if (hasThumb() && damageRect.intersects(track)) {
+        IntRect startTrackRect, thumbRect, endTrackRect;
+        splitTrack(track, startTrackRect, thumbRect, endTrackRect);
+        paintThumb(graphicsContext, thumbRect, damageRect);
+    }
+}
+
+bool PlatformScrollbar::hasButtons() const
+{
+    return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * (cRealButtonLength - cButtonHitInset);
+}
+
+bool PlatformScrollbar::hasThumb() const
+{
+    return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * cButtonInset + cThumbMinLength + 1;
+}
+
+IntRect PlatformScrollbar::backButtonRect() const
+{
+    // Our actual rect will shrink to half the available space when
+    // we have < 34 pixels left.  This allows the scrollbar
+    // to scale down and function even at tiny sizes.
+    if (m_orientation == HorizontalScrollbar)
+        return IntRect(x(), y(), cHorizontalButtonWidth, cHorizontalHeight);
+    return IntRect(x(), y(), cVerticalWidth, cVerticalButtonHeight);
+}
+
+IntRect PlatformScrollbar::forwardButtonRect() const
+{
+    // Our desired rect is essentially 17x17.
+    
+    // Our actual rect will shrink to half the available space when
+    // we have < 34 pixels left.  This allows the scrollbar
+    // to scale down and function even at tiny sizes.
+    if (m_orientation == HorizontalScrollbar)
+        return IntRect(x() + width() - cHorizontalButtonWidth, y(), cHorizontalButtonWidth, cHorizontalHeight);
+    return IntRect(x(), y() + height() - cVerticalButtonHeight, cVerticalWidth, cVerticalButtonHeight);
+}
+
+IntRect PlatformScrollbar::trackRect() const
+{
+    if (m_orientation == HorizontalScrollbar) {
+        if (!hasButtons())
+            return IntRect(x(), y(), width(), cHorizontalHeight);
+        return IntRect(x() + cHorizontalButtonWidth, y(), width() - 2 * cHorizontalButtonWidth, cHorizontalHeight);
+    }
+
+    if (!hasButtons())
+        return IntRect(x(), y(), cVerticalWidth, height());
+    return IntRect(x(), y() + cVerticalButtonHeight, cVerticalWidth, height() - 2 * cVerticalButtonHeight);
+}
+
+IntRect PlatformScrollbar::thumbRect() const
+{
+    IntRect beforeThumbRect, thumbRect, afterThumbRect;
+    splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
+    return thumbRect;
+}
+
+IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
+{
+    return IntRect();
+}
+
+void PlatformScrollbar::splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const
+{
+    // This function won't even get called unless we're big enough to have some combination of these three rects where at least
+    // one of them is non-empty.
+    int thumbPos = thumbPosition();
+    if (m_orientation == HorizontalScrollbar) {
+        thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - cThumbHeight) / 2, thumbLength(), cThumbHeight);
+        beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos, trackRect.height());
+        afterThumbRect = IntRect(thumbRect.x() + thumbRect.width(), trackRect.y(), trackRect.right() - thumbRect.right(), trackRect.height());
+    } else {
+        thumbRect = IntRect(trackRect.x() + (trackRect.width() - cThumbWidth) / 2, trackRect.y() + thumbPos, cThumbWidth, thumbLength());
+        beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos);
+        afterThumbRect = IntRect(trackRect.x(), thumbRect.y() + thumbRect.height(), trackRect.width(), trackRect.bottom() - thumbRect.bottom());
+    }
+}
+
+int PlatformScrollbar::thumbPosition() const
+{
+    if (isEnabled())
+        return (float)m_currentPos * (trackLength() - thumbLength()) / (m_totalSize - m_visibleSize);
+    return 0;
+}
+
+int PlatformScrollbar::thumbLength() const
+{
+    if (!isEnabled())
+        return 0;
+
+    float proportion = (float)(m_visibleSize) / m_totalSize;
+    int trackLen = trackLength();
+    int length = proportion * trackLen;
+    int minLength = cThumbMinLength;
+    length = max(length, minLength);
+    if (length > trackLen)
+        length = 0; // Once the thumb is below the track length, it just goes away (to make more room for the track).
+    return length;
+}
+
+int PlatformScrollbar::trackLength() const
+{
+    return (m_orientation == HorizontalScrollbar) ? trackRect().width() : trackRect().height();
+}
+
+void PlatformScrollbar::paintButton(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
+{
+    IntRect paintRect = buttonRepaintRect(rect, m_orientation, controlSize(), start);
+    
+    if (!damageRect.intersects(paintRect))
+        return;
+
+    unsigned part = 0;
+    unsigned state = 0;
+    unsigned classicPart = 0;
+    unsigned classicState = 0;
+
+    if (m_orientation == HorizontalScrollbar) {
+       state = start ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL;
+       classicPart = start ? DFCS_SCROLLLEFT : DFCS_SCROLLRIGHT;
+    } else {
+       state = start ? ABS_UPNORMAL : ABS_DOWNNORMAL;
+       classicPart = start ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
+    }
+
+    if (!isEnabled()) {
+        state += SP_ABS_DISABLE_MODIFIER;
+        classicState |= DFCS_INACTIVE;
+    } else if ((m_pressedPart == BackButtonPart && start)
+            || (m_pressedPart == ForwardButtonPart && !start)) {
+        state += SP_ABS_PRESSED_MODIFIER;
+        classicState |= DFCS_PUSHED | DFCS_FLAT;
+    } else if (m_client->isActive()) {
+       state += SP_ABS_HOT_MODIFIER;
+       classicState |= DFCS_HOT;
+    }
+
+    HDC hdc = prepareForDrawing(context, rect);
+    RECT widgetRect = rect;
+    checkAndInitScrollbarTheme();
+
+    if (cScrollBarTheme)
+        DrawThemeBackground(cScrollBarTheme, hdc, SP_BUTTON, state, &widgetRect, NULL);
+    else
+        DrawFrameControl(hdc, &widgetRect, classicPart, classicState);
+
+    doneDrawing(context, hdc, rect);
+}
+
+void PlatformScrollbar::paintTrack(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
+{
+    IntRect paintRect = hasButtons() ? trackRepaintRect(rect, m_orientation, controlSize()) : rect;
+    
+    if (!damageRect.intersects(paintRect))
+        return;
+
+    unsigned part = 0;
+    unsigned classicPart = DFC_SCROLL;
+    if (m_orientation == HorizontalScrollbar)
+       part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
+    else
+       part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;
+
+    unsigned state = TS_DISABLED;
+    unsigned classicState = DFCS_MONO;
+    if (m_client->isActive())
+        state |= TS_ACTIVE;
+    else
+       classicState |= DFCS_INACTIVE;
+
+    if (hasButtons())
+        state |= TS_NORMAL;
+
+    HDC hdc = prepareForDrawing(context, rect);
+    RECT widgetRect = rect;
+    checkAndInitScrollbarTheme();
+
+    if (cScrollBarTheme)
+        DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
+    else
+        DrawFrameControl(hdc, &widgetRect, DFC_SCROLL, classicState);
+
+    doneDrawing(context, hdc, rect);
+}
+
+void PlatformScrollbar::paintThumb(GraphicsContext* context, const IntRect& rect, const IntRect& damageRect) const
+{
+    if (!damageRect.intersects(rect))
+        return;
+
+    unsigned part = (m_orientation == HorizontalScrollbar) ? SP_THUMBHOR : SP_THUMBVERT;
+    unsigned state = 0;
+
+    if (!isEnabled())
+        state += SP_ABS_DISABLE_MODIFIER;
+    else if (m_client->isActive())
+       state += SP_ABS_HOT_MODIFIER;
+
+    HDC hdc = prepareForDrawing(context, rect);
+    RECT widgetRect = rect;
+    checkAndInitScrollbarTheme();
+
+    if (cScrollBarTheme) {
+        DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
+        paintGripper(hdc, widgetRect);
+    } else {
+        HGDIOBJ hSaveBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
+        DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT);
+        SelectObject(hdc,hSaveBrush);
+    }
+
+    doneDrawing(context, hdc, rect);
+}
+
+void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
+{
+    unsigned part = (m_orientation == HorizontalScrollbar) ? SP_GRIPPERHOR : SP_GRIPPERVERT;
+    unsigned state = 0;
+
+    if (m_client->isActive())
+        state |= TS_ACTIVE;
+
+    RECT widgetRect = rect;
+    checkAndInitScrollbarTheme();
+
+    if (cScrollBarTheme)
+        DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
+}
+
+ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt)
+{
+    if (!isEnabled())
+        return NoPart;
+
+    IntPoint mousePosition = convertFromContainingWindow(evt.pos());
+    mousePosition.move(x(), y());
+
+    if (hasButtons()) {
+        if (backButtonRect().contains(mousePosition))
+            return BackButtonPart;
+
+        if (forwardButtonRect().contains(mousePosition))
+            return ForwardButtonPart;
+    }
+
+    if (!hasThumb())
+        return NoPart;
+
+    IntRect track = trackRect();
+    if (track.contains(mousePosition)) {
+        IntRect beforeThumbRect, thumbRect, afterThumbRect;
+        splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect);
+        if (beforeThumbRect.contains(mousePosition))
+            return BackTrackPart;
+        if (thumbRect.contains(mousePosition))
+            return ThumbPart;
+        return ForwardTrackPart;
+    }
+
+    return NoPart;
+}
+
+bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt)
+{
+    if (m_pressedPart == ThumbPart) {
+        // Drag the thumb.
+        int thumbPos = thumbPosition();
+        int thumbLen = thumbLength();
+        int trackLen = trackLength();
+        int maxPos = trackLen - thumbLen;
+        int delta = 0;
+        if (m_orientation == HorizontalScrollbar)
+            delta = convertFromContainingWindow(evt.pos()).x() - m_pressedPos;
+        else
+            delta = convertFromContainingWindow(evt.pos()).y() - m_pressedPos;
+
+        if (delta > 0)
+            // The mouse moved down/right.
+            delta = min(maxPos - thumbPos, delta);
+        else if (delta < 0)
+            // The mouse moved up/left.
+            delta = max(-thumbPos, delta);
+
+        if (delta != 0) {
+            setValue((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen));
+            m_pressedPos += thumbPosition() - thumbPos;
+        }
+
+        return true;
+    }
+
+    if (m_pressedPart != NoPart)
+        m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
+
+    ScrollbarPart part = hitTest(evt);    
+    if (part != m_hoveredPart) {
+        if (m_pressedPart != NoPart) {
+            if (part == m_pressedPart) {
+                // The mouse is moving back over the pressed part.  We
+                // need to start up the timer action again.
+                startTimerIfNeeded(cNormalTimerDelay);
+                invalidatePart(m_pressedPart);
+            } else if (m_hoveredPart == m_pressedPart) {
+                // The mouse is leaving the pressed part.  Kill our timer
+                // if needed.
+                stopTimerIfNeeded();
+                invalidatePart(m_pressedPart);
+            }
+        } else {
+            invalidatePart(part);
+            invalidatePart(m_hoveredPart);
+        }
+        m_hoveredPart = part;
+    } 
+
+    return true;
+}
+
+bool PlatformScrollbar::handleMouseOutEvent(const PlatformMouseEvent& evt)
+{
+    invalidatePart(m_hoveredPart);
+    m_hoveredPart = NoPart;
+
+    return true;
+}
+
+bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt)
+{
+    m_pressedPart = hitTest(evt);
+    m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
+    invalidatePart(m_pressedPart);
+    autoscrollPressedPart(cInitialTimerDelay);
+    return true;
+}
+
+bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& evt)
+{
+    invalidatePart(m_pressedPart);
+    m_pressedPart = NoPart;
+    m_pressedPos = 0;
+    stopTimerIfNeeded();
+
+    if (parent() && parent()->isFrameView())
+        static_cast<FrameView*>(parent())->frame()->eventHandler()->setMousePressed(false);
+
+    return true;
+}
+
+void PlatformScrollbar::startTimerIfNeeded(double delay)
+{
+    // Don't do anything for the thumb.
+    if (m_pressedPart == ThumbPart)
+        return;
+
+    // Handle the track.  We halt track scrolling once the thumb is level
+    // with us.
+    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
+        invalidatePart(m_pressedPart);
+        m_hoveredPart = ThumbPart;
+        return;
+    }
+
+    // We can't scroll if we've hit the beginning or end.
+    ScrollDirection dir = pressedPartScrollDirection();
+    if (dir == ScrollUp || dir == ScrollLeft) {
+        if (m_currentPos == 0)
+            return;
+    } else {
+        if (m_currentPos == m_totalSize - m_visibleSize)
+            return;
+    }
+
+    m_scrollTimer.startOneShot(delay);
+}
+
+void PlatformScrollbar::stopTimerIfNeeded()
+{
+    if (m_scrollTimer.isActive())
+        m_scrollTimer.stop();
+}
+
+void PlatformScrollbar::autoscrollPressedPart(double delay)
+{
+    // Don't do anything for the thumb or if nothing was pressed.
+    if (m_pressedPart == ThumbPart || m_pressedPart == NoPart)
+        return;
+
+    // Handle the track.
+    if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
+        invalidatePart(m_pressedPart);
+        m_hoveredPart = ThumbPart;
+        return;
+    }
+
+    // Handle the arrows and track.
+    if (scroll(pressedPartScrollDirection(), pressedPartScrollGranularity()))
+        startTimerIfNeeded(delay);
+}
+
+void PlatformScrollbar::autoscrollTimerFired(Timer<PlatformScrollbar>*)
+{
+    autoscrollPressedPart(cNormalTimerDelay);
+}
+
+ScrollDirection PlatformScrollbar::pressedPartScrollDirection()
+{
+    if (m_orientation == HorizontalScrollbar) {
+        if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
+            return ScrollLeft;
+        return ScrollRight;
+    } else {
+        if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
+            return ScrollUp;
+        return ScrollDown;
+    }
+}
+
+ScrollGranularity PlatformScrollbar::pressedPartScrollGranularity()
+{
+    if (m_pressedPart == BackButtonPart || m_pressedPart == ForwardButtonPart)
+        return ScrollByLine;
+    return ScrollByPage;
+}
+
+bool PlatformScrollbar::thumbUnderMouse()
+{
+    // Construct a rect.
+    IntRect thumb = thumbRect();
+    thumb.move(-x(), -y());
+    int begin = (m_orientation == HorizontalScrollbar) ? thumb.x() : thumb.y();
+    int end = (m_orientation == HorizontalScrollbar) ? thumb.right() : thumb.bottom();
+    return (begin <= m_pressedPos && m_pressedPos < end);
+}
+
+int PlatformScrollbar::horizontalScrollbarHeight(ScrollbarControlSize controlSize)
+{
+    return cHorizontalWidth;
+}
+
+int PlatformScrollbar::verticalScrollbarWidth(ScrollbarControlSize controlSize)
+{
+    return cVerticalHeight;
+}
+
+IntRect PlatformScrollbar::windowClipRect() const
+{
+    IntRect clipRect(0, 0, width(), height());
+
+    clipRect = convertToContainingWindow(clipRect);
+    if (m_client)
+        clipRect.intersect(m_client->windowClipRect());
+
+    return clipRect;
+}
+
+void PlatformScrollbar::themeChanged()
+{
+}
+
+}
+