Refactor painting of the native windows scrollbar and prepare for code sharing with the Aqua windows scrollbar.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36428 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 54a2963..16dd28c 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,55 @@
+2008-09-14  Dave Hyatt  <hyatt@apple.com>
+
+        Refactor PlatformScrollbarWin's painting so that it is now done by ScrollbarThemeWin.  PlatformScrollbarSafari
+        is still painting itself (a subsequent patch will move its painting into ScrollbarThemeSafari).
+       
+        Reviewed by Sam Weinig
+
+        * platform/ScrollBar.h:
+        (WebCore::Scrollbar::client):
+        (WebCore::Scrollbar::currentPos):
+        (WebCore::Scrollbar::totalSize):
+        * platform/ScrollbarTheme.h:
+        * platform/ScrollbarThemeComposite.cpp:
+        (WebCore::pageForScrollView):
+        (WebCore::ScrollbarThemeComposite::paint):
+        * platform/ScrollbarThemeComposite.h:
+        (WebCore::ScrollbarThemeComposite::trackIsSinglePiece):
+        * platform/win/PlatformScrollBar.h:
+        * platform/win/PlatformScrollBarSafari.cpp:
+        * platform/win/PlatformScrollBarWin.cpp:
+        * platform/win/ScrollbarThemeSafari.h:
+        (WebCore::ScrollbarThemeSafari::hasButtons):
+        (WebCore::ScrollbarThemeSafari::hasThumb):
+        (WebCore::ScrollbarThemeSafari::backButtonRect):
+        (WebCore::ScrollbarThemeSafari::forwardButtonRect):
+        (WebCore::ScrollbarThemeSafari::trackRect):
+        (WebCore::ScrollbarThemeSafari::splitTrack):
+        (WebCore::ScrollbarThemeSafari::paintTrack):
+        (WebCore::ScrollbarThemeSafari::paintButton):
+        (WebCore::ScrollbarThemeSafari::paintThumb):
+        * platform/win/ScrollbarThemeWin.cpp:
+        (WebCore::isRunningOnVistaOrLater):
+        (WebCore::checkAndInitScrollbarTheme):
+        (WebCore::ScrollbarThemeWin::ScrollbarThemeWin):
+        (WebCore::ScrollbarThemeWin::themeChanged):
+        (WebCore::ScrollbarThemeWin::hasThumb):
+        (WebCore::ScrollbarThemeWin::backButtonRect):
+        (WebCore::ScrollbarThemeWin::forwardButtonRect):
+        (WebCore::ScrollbarThemeWin::trackRect):
+        (WebCore::ScrollbarThemeWin::splitTrack):
+        (WebCore::ScrollbarThemeWin::paintTrack):
+        (WebCore::ScrollbarThemeWin::paintButton):
+        (WebCore::gripperRect):
+        (WebCore::paintGripper):
+        (WebCore::ScrollbarThemeWin::paintThumb):
+        (WebCore::ScrollbarThemeWin::thumbPosition):
+        (WebCore::ScrollbarThemeWin::thumbLength):
+        (WebCore::ScrollbarThemeWin::trackLength):
+        * platform/win/ScrollbarThemeWin.h:
+        (WebCore::ScrollbarThemeWin::hasButtons):
+        (WebCore::ScrollbarThemeWin::trackIsSinglePiece):
+
 2008-09-14  Anthony Ricaud  <rik24d@gmail.com>
 
         Moving all resource graphs under the same container for future scalable feature.
diff --git a/WebCore/platform/ScrollBar.h b/WebCore/platform/ScrollBar.h
index d5d1d3e..c7a0a46 100644
--- a/WebCore/platform/ScrollBar.h
+++ b/WebCore/platform/ScrollBar.h
@@ -52,11 +52,14 @@
     virtual ~Scrollbar();
 
     void setClient(ScrollbarClient* client) { m_client = client; }
+    ScrollbarClient* client() const { return m_client; }
 
     ScrollbarOrientation orientation() const { return m_orientation; }
     
     int value() const { return lroundf(m_currentPos); }
+    float currentPos() const { return m_currentPos; }
     int visibleSize() const { return m_visibleSize; }
+    int totalSize() const { return m_totalSize; }
     int maximum() const { return m_totalSize - m_visibleSize; }        
     ScrollbarControlSize controlSize() const { return m_controlSize; }
 
@@ -110,8 +113,6 @@
     ScrollDirection pressedPartScrollDirection();
     ScrollGranularity pressedPartScrollGranularity();
     
-    ScrollbarClient* client() const { return m_client; }
-
     ScrollbarClient* m_client;
     ScrollbarOrientation m_orientation;
     ScrollbarControlSize m_controlSize;
diff --git a/WebCore/platform/ScrollbarTheme.h b/WebCore/platform/ScrollbarTheme.h
index ff20a49..f74e9b0 100755
--- a/WebCore/platform/ScrollbarTheme.h
+++ b/WebCore/platform/ScrollbarTheme.h
@@ -46,7 +46,7 @@
 
     virtual void themeChanged() {}
     
-    static ScrollbarTheme* nativeTheme(); // Must be implemented by the theme subclass.
+    static ScrollbarTheme* nativeTheme(); // Must be implemented to return the correct theme subclass.
 };
 
 }
diff --git a/WebCore/platform/ScrollbarThemeComposite.cpp b/WebCore/platform/ScrollbarThemeComposite.cpp
index a45b692..4cdf173 100755
--- a/WebCore/platform/ScrollbarThemeComposite.cpp
+++ b/WebCore/platform/ScrollbarThemeComposite.cpp
@@ -26,11 +26,121 @@
 #include "config.h"
 #include "ScrollbarThemeComposite.h"
 
+#include "ChromeClient.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "Page.h"
+#include "Scrollbar.h"
+#include "ScrollbarClient.h"
+#include "Settings.h"
+
 namespace WebCore {
 
-bool ScrollbarThemeComposite::paint(Scrollbar*, GraphicsContext* context, const IntRect& damageRect)
+static Page* pageForScrollView(ScrollView* view)
 {
-    return false;
+    if (!view)
+        return 0;
+    if (!view->isFrameView())
+        return 0;
+    FrameView* frameView = static_cast<FrameView*>(view);
+    if (!frameView->frame())
+        return 0;
+    return frameView->frame()->page();
+}
+
+bool ScrollbarThemeComposite::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect)
+{
+    // Create the ScrollbarControlPartMask based on the damageRect
+    ScrollbarControlPartMask scrollMask = NoPart;
+
+    IntRect backButtonPaintRect;
+    IntRect forwardButtonPaintRect;
+    if (hasButtons(scrollbar)) {
+        backButtonPaintRect = backButtonRect(scrollbar, true);
+        if (damageRect.intersects(backButtonPaintRect))
+            scrollMask |= BackButtonPart;
+        forwardButtonPaintRect = forwardButtonRect(scrollbar, true);
+        if (damageRect.intersects(forwardButtonPaintRect))
+            scrollMask |= ForwardButtonPart;
+    }
+
+    IntRect startTrackRect;
+    IntRect thumbRect;
+    IntRect endTrackRect;
+    IntRect trackPaintRect = trackRect(scrollbar, true);
+    bool thumbPresent = hasThumb(scrollbar);
+    if (thumbPresent) {
+        IntRect track = trackRect(scrollbar);
+        splitTrack(scrollbar, track, startTrackRect, thumbRect, endTrackRect);
+        if (damageRect.intersects(thumbRect)) {
+            scrollMask |= ThumbPart;
+            if (trackIsSinglePiece()) {
+                // The track is a single strip that paints under the thumb.
+                // Add both components of the track to the mask.
+                scrollMask |= BackTrackPart;
+                scrollMask |= ForwardTrackPart;
+            }
+        }
+        if (damageRect.intersects(startTrackRect))
+            scrollMask |= BackTrackPart;
+        if (damageRect.intersects(endTrackRect))
+            scrollMask |= ForwardTrackPart;
+    } else if (damageRect.intersects(trackPaintRect)) {
+        scrollMask |= BackTrackPart;
+        scrollMask |= ForwardTrackPart;
+    }
+
+    // FIXME: This API makes the assumption that the custom scrollbar's metrics will match
+    // the theme's metrics.  This is not a valid assumption.  The ability for a client to paint
+    // custom scrollbars should be removed once scrollbars can be styled via CSS.
+    if (Page* page = pageForScrollView(scrollbar->parent())) {
+        if (page->settings()->shouldPaintCustomScrollbars()) {
+            float proportion = static_cast<float>(scrollbar->visibleSize()) / scrollbar->totalSize();
+            float value = scrollbar->currentPos() / static_cast<float>(scrollbar->maximum());
+            ScrollbarControlState s = 0;
+            if (scrollbar->client()->isActive())
+                s |= ActiveScrollbarState;
+            if (scrollbar->isEnabled())
+                s |= EnabledScrollbarState;
+            if (scrollbar->pressedPart() != NoPart)
+                s |= PressedScrollbarState;
+            if (page->chrome()->client()->paintCustomScrollbar(graphicsContext,
+                                                               scrollbar->frameGeometry(), 
+                                                               scrollbar->controlSize(),
+                                                               s, 
+                                                               scrollbar->pressedPart(), 
+                                                               scrollbar->orientation() == VerticalScrollbar,
+                                                               value,
+                                                               proportion,
+                                                               scrollMask))
+                return true;
+        }
+    }
+
+    // Paint the track.
+    if ((scrollMask & ForwardTrackPart) || (scrollMask & BackTrackPart)) {
+        if (!thumbPresent || trackIsSinglePiece())
+            paintTrack(graphicsContext, scrollbar, trackPaintRect, ForwardTrackPart | BackTrackPart);
+        else {
+            if (scrollMask & BackTrackPart)
+                paintTrack(graphicsContext, scrollbar, startTrackRect, BackTrackPart);
+            if (scrollMask & ForwardTrackPart)
+                paintTrack(graphicsContext, scrollbar, endTrackRect, ForwardTrackPart);
+        }
+    }
+
+    // Paint the back and forward buttons.
+    if (scrollMask & BackButtonPart)
+        paintButton(graphicsContext, scrollbar, backButtonPaintRect, BackButtonPart);
+    if (scrollMask & ForwardButtonPart)
+        paintButton(graphicsContext, scrollbar, forwardButtonPaintRect, ForwardButtonPart);
+    
+    // Paint the thumb.
+    if (scrollMask & ThumbPart)
+        paintThumb(graphicsContext, scrollbar, thumbRect);
+
+    return true;
 }
 
 }
diff --git a/WebCore/platform/ScrollbarThemeComposite.h b/WebCore/platform/ScrollbarThemeComposite.h
index f8249e4..ae6c010 100755
--- a/WebCore/platform/ScrollbarThemeComposite.h
+++ b/WebCore/platform/ScrollbarThemeComposite.h
@@ -33,6 +33,23 @@
 class ScrollbarThemeComposite : public ScrollbarTheme {
 public:
     virtual bool paint(Scrollbar*, GraphicsContext* context, const IntRect& damageRect);
+
+protected:
+    virtual bool hasButtons(Scrollbar*) = 0;
+    virtual bool hasThumb(Scrollbar*) = 0;
+
+    virtual IntRect backButtonRect(Scrollbar*, bool painting = false) = 0;
+    virtual IntRect forwardButtonRect(Scrollbar*, bool painting = false) = 0;
+    virtual IntRect trackRect(Scrollbar*, bool painting = false) = 0;
+
+    virtual void splitTrack(Scrollbar*, const IntRect& track, IntRect& startTrack, IntRect& thumb, IntRect& endTrack) = 0;
+    
+    // Assume the track is a single piece by default.
+    virtual bool trackIsSinglePiece() { return true; }
+
+    virtual void paintTrack(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarControlPartMask) = 0;
+    virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarControlPartMask) = 0;
+    virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&) = 0;
 };
 
 }
diff --git a/WebCore/platform/win/PlatformScrollBar.h b/WebCore/platform/win/PlatformScrollBar.h
index c748794..04f1ac7 100644
--- a/WebCore/platform/win/PlatformScrollBar.h
+++ b/WebCore/platform/win/PlatformScrollBar.h
@@ -68,18 +68,12 @@
     IntRect forwardButtonRect() const;
     IntRect trackRect() const;
     IntRect thumbRect() const;
-    IntRect gripperRect(const IntRect& thumbRect) const;    
     void splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const;
 
     int thumbPosition() const;
     int thumbLength() const;
     int trackLength() const;
-
-    void paintButton(GraphicsContext*, const IntRect& buttonRect, bool start, const IntRect& damageRect) const;
-    void paintTrack(GraphicsContext*, const IntRect& trackRect, bool start, const IntRect& damageRect) const;
-    void paintThumb(GraphicsContext*, const IntRect& thumbRect, const IntRect& damageRect) const;
-    void paintGripper(HDC, const IntRect& gripperRect) const;
-    
+   
     ScrollbarPart hitTest(const PlatformMouseEvent&);
 
     bool thumbUnderMouse();
diff --git a/WebCore/platform/win/PlatformScrollBarSafari.cpp b/WebCore/platform/win/PlatformScrollBarSafari.cpp
index a9d706d..f0c8a5f 100644
--- a/WebCore/platform/win/PlatformScrollBarSafari.cpp
+++ b/WebCore/platform/win/PlatformScrollBarSafari.cpp
@@ -551,15 +551,6 @@
     return clipRect;
 }
 
-void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
-{
-}
-
-IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
-{
-    return IntRect();
-}
-
 }
 
 #endif // USE(SAFARI_THEME)
diff --git a/WebCore/platform/win/PlatformScrollBarWin.cpp b/WebCore/platform/win/PlatformScrollBarWin.cpp
index fe0c75f..27dab8e 100644
--- a/WebCore/platform/win/PlatformScrollBarWin.cpp
+++ b/WebCore/platform/win/PlatformScrollBarWin.cpp
@@ -230,39 +230,6 @@
     Widget::setParent(parentView);
 }
 
-void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect)
-{
-    checkAndInitScrollbarTheme();
-
-    // A Windows scrollbar consists of six components:
-    // An arrow button, a track piece, a thumb, a gripper inside the thumb, another track piece, and another arrow button.
-    // Paint each piece if it intersects the damage rect.
-    
-    // (1) The first arrow button
-    paintButton(graphicsContext, backButtonRect(), true, damageRect);
-
-    IntRect rect;
-    if (damageRect.intersects(rect = trackRect())) {
-        if (isEnabled()) {
-            IntRect startTrackRect, thumbRect, endTrackRect;
-            splitTrack(rect, startTrackRect, thumbRect, endTrackRect);
-
-            // (2) The first track piece
-            paintTrack(graphicsContext, startTrackRect, true, damageRect);
-        
-            // (3) The thumb
-            paintThumb(graphicsContext, thumbRect, damageRect);
-
-            // (4) The second track piece
-            paintTrack(graphicsContext, endTrackRect, false, damageRect);
-        } else
-            // Just paint a disabled track throughout the track rect.
-            paintTrack(graphicsContext, rect, true, damageRect);
-    }
-
-    // (5) The second arrow button
-    paintButton(graphicsContext, forwardButtonRect(), false, damageRect);
-}
 
 bool PlatformScrollbar::hasButtons() const
 {
@@ -323,14 +290,6 @@
     return thumbRect;
 }
 
-IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
-{
-    // Center in the thumb.
-    return IntRect(thumbRect.x() + (thumbRect.width() - cGripperWidth) / 2,
-                   thumbRect.y() + (thumbRect.height() - cGripperHeight) / 2,
-                   cGripperWidth, cGripperHeight);
-}
-
 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
@@ -374,153 +333,6 @@
     return (m_orientation == HorizontalScrollbar) ? trackRect().width() : trackRect().height();
 }
 
-void PlatformScrollbar::paintButton(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
-{
-    if (!damageRect.intersects(rect))
-        return;
-
-    int xpState = 0;
-    int classicState = 0;
-    if (m_orientation == HorizontalScrollbar)
-        xpState = start ? TS_LEFT_BUTTON : TS_RIGHT_BUTTON;
-    else
-        xpState = start ? TS_UP_BUTTON : TS_DOWN_BUTTON;
-    classicState = xpState / 4;
-
-    if (!isEnabled()) {
-        xpState += TS_DISABLED;
-        classicState |= DFCS_INACTIVE;
-    } else if ((m_hoveredPart == BackButtonPart && start) ||
-               (m_hoveredPart == ForwardButtonPart && !start)) {
-        if (m_pressedPart == m_hoveredPart) {
-            xpState += TS_ACTIVE;
-            classicState |= DFCS_PUSHED | DFCS_FLAT;
-        } else
-            xpState += TS_HOVER;
-    } else {
-        if (m_hoveredPart == NoPart || !runningVista)
-            xpState += TS_NORMAL;
-        else {
-            if (m_orientation == HorizontalScrollbar)
-                xpState = start ? TS_LEFT_BUTTON_HOVER : TS_RIGHT_BUTTON_HOVER;
-            else
-                xpState = start ? TS_UP_BUTTON_HOVER : TS_DOWN_BUTTON_HOVER;
-        }
-    }
-
-    bool alphaBlend = false;
-    if (scrollbarTheme)
-        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, SP_BUTTON, xpState);
-    HDC hdc = context->getWindowsContext(rect, alphaBlend);
-
-    RECT themeRect(rect);
-    if (scrollbarTheme)
-        DrawThemeBackground(scrollbarTheme, hdc, SP_BUTTON, xpState, &themeRect, 0);
-    else
-        ::DrawFrameControl(hdc, &themeRect, DFC_SCROLL, classicState);
-    context->releaseWindowsContext(hdc, rect, alphaBlend);
-}
-
-void PlatformScrollbar::paintTrack(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
-{
-    if (!damageRect.intersects(rect))
-        return;
-
-    int part;
-    if (m_orientation == HorizontalScrollbar)
-        part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
-    else
-        part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;
-
-    int state;
-    if (!isEnabled())
-        state = TS_DISABLED;
-    else if ((m_hoveredPart == BackTrackPart && start) ||
-             (m_hoveredPart == ForwardTrackPart && !start))
-        state = (m_pressedPart == m_hoveredPart ? TS_ACTIVE : TS_HOVER);
-    else
-        state = TS_NORMAL;
-
-    bool alphaBlend = false;
-    if (scrollbarTheme)
-        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, part, state);
-    HDC hdc = context->getWindowsContext(rect, alphaBlend);
-    RECT themeRect(rect);
-    if (scrollbarTheme)
-        DrawThemeBackground(scrollbarTheme, hdc, part, state, &themeRect, 0);
-    else {
-        DWORD color3DFace = ::GetSysColor(COLOR_3DFACE);
-        DWORD colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR);
-        DWORD colorWindow = ::GetSysColor(COLOR_WINDOW);
-        if ((color3DFace != colorScrollbar) && (colorWindow != colorScrollbar))
-            ::FillRect(hdc, &themeRect, HBRUSH(COLOR_SCROLLBAR+1));
-        else {
-            static WORD patternBits[8] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
-            HBITMAP patternBitmap = ::CreateBitmap(8, 8, 1, 1, patternBits);
-            HBRUSH brush = ::CreatePatternBrush(patternBitmap);
-            SaveDC(hdc);
-            ::SetTextColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
-            ::SetBkColor(hdc, ::GetSysColor(COLOR_3DFACE));
-            ::SetBrushOrgEx(hdc, rect.x(), rect.y(), NULL);
-            ::SelectObject(hdc, brush);
-            ::FillRect(hdc, &themeRect, brush);
-            ::RestoreDC(hdc, -1);
-            ::DeleteObject(brush);  
-            ::DeleteObject(patternBitmap);
-        }
-    }
-    context->releaseWindowsContext(hdc, rect, alphaBlend);
-}
-
-void PlatformScrollbar::paintThumb(GraphicsContext* context, const IntRect& rect, const IntRect& damageRect) const
-{
-    if (!damageRect.intersects(rect))
-        return;
-
-    int state;
-    if (!isEnabled())
-        state = TS_DISABLED;
-    else if (m_pressedPart == ThumbPart)
-        state = TS_ACTIVE; // Thumb always stays active once pressed.
-    else if (m_hoveredPart == ThumbPart)
-        state = TS_HOVER;
-    else
-        state = TS_NORMAL;
-
-    bool alphaBlend = false;
-    if (scrollbarTheme)
-        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, m_orientation == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state);
-    HDC hdc = context->getWindowsContext(rect, alphaBlend);
-    RECT themeRect(rect);
-    if (scrollbarTheme) {
-        DrawThemeBackground(scrollbarTheme, hdc, m_orientation == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state, &themeRect, 0);
-        IntRect gripper;
-        if (damageRect.intersects(gripper = gripperRect(rect)))
-            paintGripper(hdc, gripper);
-    } else
-        ::DrawEdge(hdc, &themeRect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
-    context->releaseWindowsContext(hdc, rect, alphaBlend);
-}
-
-void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
-{
-    if (!scrollbarTheme)
-        return;  // Classic look has no gripper.
-   
-    int state;
-    if (!isEnabled())
-        state = TS_DISABLED;
-    else if (m_pressedPart == ThumbPart)
-        state = TS_ACTIVE; // Thumb always stays active once pressed.
-    else if (m_hoveredPart == ThumbPart)
-        state = TS_HOVER;
-    else
-        state = TS_NORMAL;
-
-    RECT themeRect(rect);
-    DrawThemeBackground(scrollbarTheme, hdc, m_orientation == HorizontalScrollbar ? SP_GRIPPERHOR : SP_GRIPPERVERT, state, &themeRect, 0);
-}
-
 ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt)
 {
     ScrollbarPart result = NoPart;
diff --git a/WebCore/platform/win/ScrollbarThemeSafari.h b/WebCore/platform/win/ScrollbarThemeSafari.h
index 5dc52ab..263dc2a 100755
--- a/WebCore/platform/win/ScrollbarThemeSafari.h
+++ b/WebCore/platform/win/ScrollbarThemeSafari.h
@@ -26,6 +26,8 @@
 #ifndef ScrollbarThemeSafari_h
 #define ScrollbarThemeSafari_h
 
+#if USE(SAFARI_THEME)
+
 #include "ScrollbarThemeComposite.h"
 
 namespace WebCore {
@@ -37,7 +39,24 @@
     virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar);
     
     virtual bool supportsControlTints() const { return true; }
+
+protected:
+    // FIXME: Implement the following functions to complete the theme.
+    virtual bool hasButtons(Scrollbar*) { return true; }
+    virtual bool hasThumb(Scrollbar*) { return true; }
+
+    virtual IntRect backButtonRect(Scrollbar*, bool painting = false) { return IntRect(); }
+    virtual IntRect forwardButtonRect(Scrollbar*, bool painting = false) { return IntRect(); }
+    virtual IntRect trackRect(Scrollbar*, bool painting = false) { return IntRect(); }
+
+    virtual void splitTrack(Scrollbar*, const IntRect& track, IntRect& startTrack, IntRect& thumb, IntRect& endTrack) {};
+
+    virtual void paintTrack(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarControlPartMask) {};
+    virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarControlPartMask) {};
+    virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&) {};
 };
 
 }
 #endif
+
+#endif
diff --git a/WebCore/platform/win/ScrollbarThemeWin.cpp b/WebCore/platform/win/ScrollbarThemeWin.cpp
index 7c18093..b596b35 100755
--- a/WebCore/platform/win/ScrollbarThemeWin.cpp
+++ b/WebCore/platform/win/ScrollbarThemeWin.cpp
@@ -26,8 +26,74 @@
 #include "config.h"
 #include "ScrollbarThemeWin.h"
 
+#include "GraphicsContext.h"
+#include "ScrollBar.h"
+#include "SoftLinking.h"
+
+// Generic state constants
+#define TS_NORMAL    1
+#define TS_HOVER     2
+#define TS_ACTIVE    3
+#define TS_DISABLED  4
+
+#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
+
+#define TS_UP_BUTTON       0
+#define TS_DOWN_BUTTON     4
+#define TS_LEFT_BUTTON     8
+#define TS_RIGHT_BUTTON    12
+#define TS_UP_BUTTON_HOVER   17
+#define TS_DOWN_BUTTON_HOVER  18
+#define TS_LEFT_BUTTON_HOVER  19
+#define TS_RIGHT_BUTTON_HOVER   20
+
+using namespace std;
+
 namespace WebCore {
-   
+
+static HANDLE scrollbarTheme;
+static bool haveTheme;
+static bool runningVista;
+
+// 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, IsThemeActive, BOOL, WINAPI, (), ())
+SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
+
+static bool isRunningOnVistaOrLater()
+{
+    static bool os = false;
+    static bool initialized = false;
+    if (!initialized) {
+        OSVERSIONINFOEX vi = {sizeof(vi), 0};
+        GetVersionEx((OSVERSIONINFO*)&vi);
+
+        // NOTE: This does not work under a debugger - Vista shims Visual Studio, 
+        // making it believe it is xpsp2, which is inherited by debugged applications
+        os = vi.dwMajorVersion >= 6;
+        initialized = true;
+    }
+    return os;
+}
+
+static void checkAndInitScrollbarTheme()
+{
+    if (uxthemeLibrary() && !scrollbarTheme)
+        scrollbarTheme = OpenThemeData(0, L"Scrollbar");
+    haveTheme = scrollbarTheme && IsThemeActive();
+}
+
 #if !USE(SAFARI_THEME)
 ScrollbarTheme* ScrollbarTheme::nativeTheme()
 {
@@ -36,6 +102,16 @@
 }
 #endif
 
+ScrollbarThemeWin::ScrollbarThemeWin()
+{
+    static bool initialized;
+    if (!initialized) {
+        initialized = true;
+        checkAndInitScrollbarTheme();
+        runningVista = isRunningOnVistaOrLater();
+    }
+}
+
 ScrollbarThemeWin::~ScrollbarThemeWin()
 {
 }
@@ -50,6 +126,254 @@
 
 void ScrollbarThemeWin::themeChanged()
 {
+    if (haveTheme)
+        CloseThemeData(scrollbarTheme);
+}
+
+bool ScrollbarThemeWin::hasThumb(Scrollbar* scrollbar)
+{
+    return thumbLength(scrollbar) > 0;
+}
+
+IntRect ScrollbarThemeWin::backButtonRect(Scrollbar* scrollbar, bool)
+{
+    // 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.
+    int thickness = scrollbarThickness();
+    if (scrollbar->orientation() == HorizontalScrollbar)
+        return IntRect(scrollbar->x(), scrollbar->y(),
+                       scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness, thickness);
+    return IntRect(scrollbar->x(), scrollbar->y(),
+                   thickness, scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness);
+}
+
+IntRect ScrollbarThemeWin::forwardButtonRect(Scrollbar* scrollbar, bool)
+{
+    // 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.
+    int thickness = scrollbarThickness();
+    if (scrollbar->orientation() == HorizontalScrollbar) {
+        int w = scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness;
+        return IntRect(scrollbar->x() + scrollbar->width() - w, scrollbar->y(), w, thickness);
+    }
+    
+    int h = scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness;
+    return IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - h, thickness, h);
+}
+
+IntRect ScrollbarThemeWin::trackRect(Scrollbar* scrollbar, bool)
+{
+    int thickness = scrollbarThickness();
+    if (scrollbar->orientation() == HorizontalScrollbar) {
+        if (scrollbar->width() < 2 * thickness)
+            return IntRect();
+        return IntRect(scrollbar->x() + thickness, scrollbar->y(), scrollbar->width() - 2 * thickness, thickness);
+    }
+    if (scrollbar->height() < 2 * thickness)
+        return IntRect();
+    return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness);
+}
+
+void ScrollbarThemeWin::splitTrack(Scrollbar* scrollbar, const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect)
+{
+    // 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 thickness = scrollbarThickness();
+    int thumbPos = thumbPosition(scrollbar);
+    if (scrollbar->orientation() == HorizontalScrollbar) {
+        thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - thickness) / 2, thumbLength(scrollbar), thickness);
+        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() - thickness) / 2, trackRect.y() + thumbPos, thickness, thumbLength(scrollbar));
+        beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos);
+        afterThumbRect = IntRect(trackRect.x(), thumbRect.y() + thumbRect.height(), trackRect.width(), trackRect.bottom() - thumbRect.bottom());
+    }
+}
+
+void ScrollbarThemeWin::paintTrack(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarControlPartMask mask)
+{
+    checkAndInitScrollbarTheme();
+
+    bool start = mask & BackTrackPart;
+    int part;
+    if (scrollbar->orientation() == HorizontalScrollbar)
+        part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
+    else
+        part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;
+
+    int state;
+    if (!scrollbar->isEnabled())
+        state = TS_DISABLED;
+    else if ((scrollbar->hoveredPart() == BackTrackPart && start) ||
+             (scrollbar->hoveredPart() == ForwardTrackPart && !start))
+        state = (scrollbar->pressedPart() == scrollbar->hoveredPart() ? TS_ACTIVE : TS_HOVER);
+    else
+        state = TS_NORMAL;
+
+    bool alphaBlend = false;
+    if (scrollbarTheme)
+        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, part, state);
+    HDC hdc = context->getWindowsContext(rect, alphaBlend);
+    RECT themeRect(rect);
+    if (scrollbarTheme)
+        DrawThemeBackground(scrollbarTheme, hdc, part, state, &themeRect, 0);
+    else {
+        DWORD color3DFace = ::GetSysColor(COLOR_3DFACE);
+        DWORD colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR);
+        DWORD colorWindow = ::GetSysColor(COLOR_WINDOW);
+        if ((color3DFace != colorScrollbar) && (colorWindow != colorScrollbar))
+            ::FillRect(hdc, &themeRect, HBRUSH(COLOR_SCROLLBAR+1));
+        else {
+            static WORD patternBits[8] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
+            HBITMAP patternBitmap = ::CreateBitmap(8, 8, 1, 1, patternBits);
+            HBRUSH brush = ::CreatePatternBrush(patternBitmap);
+            SaveDC(hdc);
+            ::SetTextColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
+            ::SetBkColor(hdc, ::GetSysColor(COLOR_3DFACE));
+            ::SetBrushOrgEx(hdc, rect.x(), rect.y(), NULL);
+            ::SelectObject(hdc, brush);
+            ::FillRect(hdc, &themeRect, brush);
+            ::RestoreDC(hdc, -1);
+            ::DeleteObject(brush);  
+            ::DeleteObject(patternBitmap);
+        }
+    }
+    context->releaseWindowsContext(hdc, rect, alphaBlend);
+}
+
+void ScrollbarThemeWin::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarControlPartMask mask)
+{
+    checkAndInitScrollbarTheme();
+
+    bool start = mask & BackButtonPart;
+    int xpState = 0;
+    int classicState = 0;
+    if (scrollbar->orientation() == HorizontalScrollbar)
+        xpState = start ? TS_LEFT_BUTTON : TS_RIGHT_BUTTON;
+    else
+        xpState = start ? TS_UP_BUTTON : TS_DOWN_BUTTON;
+    classicState = xpState / 4;
+
+    if (!scrollbar->isEnabled()) {
+        xpState += TS_DISABLED;
+        classicState |= DFCS_INACTIVE;
+    } else if ((scrollbar->hoveredPart() == BackButtonPart && start) ||
+               (scrollbar->hoveredPart() == ForwardButtonPart && !start)) {
+        if (scrollbar->pressedPart() == scrollbar->hoveredPart()) {
+            xpState += TS_ACTIVE;
+            classicState |= DFCS_PUSHED | DFCS_FLAT;
+        } else
+            xpState += TS_HOVER;
+    } else {
+        if (scrollbar->hoveredPart() == NoPart || !runningVista)
+            xpState += TS_NORMAL;
+        else {
+            if (scrollbar->orientation() == HorizontalScrollbar)
+                xpState = start ? TS_LEFT_BUTTON_HOVER : TS_RIGHT_BUTTON_HOVER;
+            else
+                xpState = start ? TS_UP_BUTTON_HOVER : TS_DOWN_BUTTON_HOVER;
+        }
+    }
+
+    bool alphaBlend = false;
+    if (scrollbarTheme)
+        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, SP_BUTTON, xpState);
+    HDC hdc = context->getWindowsContext(rect, alphaBlend);
+
+    RECT themeRect(rect);
+    if (scrollbarTheme)
+        DrawThemeBackground(scrollbarTheme, hdc, SP_BUTTON, xpState, &themeRect, 0);
+    else
+        ::DrawFrameControl(hdc, &themeRect, DFC_SCROLL, classicState);
+    context->releaseWindowsContext(hdc, rect, alphaBlend);
+}
+
+static IntRect gripperRect(int thickness, const IntRect& thumbRect)
+{
+    // Center in the thumb.
+    int gripperThickness = thickness / 2;
+    return IntRect(thumbRect.x() + (thumbRect.width() - gripperThickness) / 2,
+                   thumbRect.y() + (thumbRect.height() - gripperThickness) / 2,
+                   gripperThickness, gripperThickness);
+}
+
+static void paintGripper(Scrollbar* scrollbar, HDC hdc, const IntRect& rect)
+{
+    if (!scrollbarTheme)
+        return;  // Classic look has no gripper.
+   
+    int state;
+    if (!scrollbar->isEnabled())
+        state = TS_DISABLED;
+    else if (scrollbar->pressedPart() == ThumbPart)
+        state = TS_ACTIVE; // Thumb always stays active once pressed.
+    else if (scrollbar->hoveredPart() == ThumbPart)
+        state = TS_HOVER;
+    else
+        state = TS_NORMAL;
+
+    RECT themeRect(rect);
+    DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_GRIPPERHOR : SP_GRIPPERVERT, state, &themeRect, 0);
+}
+
+void ScrollbarThemeWin::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
+{
+    checkAndInitScrollbarTheme();
+
+    int state;
+    if (!scrollbar->isEnabled())
+        state = TS_DISABLED;
+    else if (scrollbar->pressedPart() == ThumbPart)
+        state = TS_ACTIVE; // Thumb always stays active once pressed.
+    else if (scrollbar->hoveredPart() == ThumbPart)
+        state = TS_HOVER;
+    else
+        state = TS_NORMAL;
+
+    bool alphaBlend = false;
+    if (scrollbarTheme)
+        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state);
+    HDC hdc = context->getWindowsContext(rect, alphaBlend);
+    RECT themeRect(rect);
+    if (scrollbarTheme) {
+        DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state, &themeRect, 0);
+        paintGripper(scrollbar, hdc, gripperRect(scrollbarThickness(), rect));
+    } else
+        ::DrawEdge(hdc, &themeRect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
+    context->releaseWindowsContext(hdc, rect, alphaBlend);
+}
+
+int ScrollbarThemeWin::thumbPosition(Scrollbar* scrollbar)
+{
+    if (scrollbar->isEnabled())
+        return scrollbar->currentPos() * (trackLength(scrollbar) - thumbLength(scrollbar)) / scrollbar->maximum();
+    return 0;
+}
+
+int ScrollbarThemeWin::thumbLength(Scrollbar* scrollbar)
+{
+    if (!scrollbar->isEnabled())
+        return 0;
+    float proportion = (float)(scrollbar->visibleSize()) / scrollbar->totalSize();
+    int trackLen = trackLength(scrollbar);
+    int length = proportion * trackLen;
+    int minLength = (scrollbar->orientation() == HorizontalScrollbar) ? scrollbarThickness() : scrollbarThickness();
+    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 ScrollbarThemeWin::trackLength(Scrollbar* scrollbar)
+{
+    return (scrollbar->orientation() == HorizontalScrollbar) ? trackRect(scrollbar).width() : trackRect(scrollbar).height();
 }
 
 }
diff --git a/WebCore/platform/win/ScrollbarThemeWin.h b/WebCore/platform/win/ScrollbarThemeWin.h
index 372235c..d99c2d4 100755
--- a/WebCore/platform/win/ScrollbarThemeWin.h
+++ b/WebCore/platform/win/ScrollbarThemeWin.h
@@ -32,11 +32,34 @@
 
 class ScrollbarThemeWin : public ScrollbarThemeComposite {
 public:
+    ScrollbarThemeWin();
     virtual ~ScrollbarThemeWin();
 
     virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar);
 
     virtual void themeChanged();
+
+protected:
+    virtual bool hasButtons(Scrollbar*) { return true; }
+    virtual bool hasThumb(Scrollbar*);
+
+    virtual IntRect backButtonRect(Scrollbar*, bool painting = false);
+    virtual IntRect forwardButtonRect(Scrollbar*, bool painting = false);
+    virtual IntRect trackRect(Scrollbar*, bool painting = false);
+
+    virtual void splitTrack(Scrollbar*, const IntRect& track, IntRect& startTrack, IntRect& thumb, IntRect& endTrack);
+    
+    virtual bool trackIsSinglePiece() { return false; }
+
+    virtual void paintTrack(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarControlPartMask);
+    virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarControlPartMask);
+    virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&);
+
+private:
+    int thumbPosition(Scrollbar*);
+    int thumbLength(Scrollbar*);
+    int trackLength(Scrollbar*);
+
 };
 
 }