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#include "WebKitDLL.h"
28#include "WebKit.h"
29#include "WebScrollBar.h"
30
31#include <WebCore/GraphicsContext.h>
32#include <WebCore/PlatformMouseEvent.h>
33#include <WebCore/Scrollbar.h>
34#include <WebCore/ScrollbarTheme.h>
35
36using namespace WebCore;
37
38// WebScrollBar ---------------------------------------------------------------------
39
40WebScrollBar::WebScrollBar()
41    : m_refCount(0)
42    , m_containingWindow(0)
43    , m_currentPosition(0)
44{
45    gClassCount++;
46    gClassNameCount.add("WebScrollBar");
47}
48
49WebScrollBar::~WebScrollBar()
50{
51    gClassCount--;
52    gClassNameCount.remove("WebScrollBar");
53}
54
55WebScrollBar* WebScrollBar::createInstance()
56{
57    WebScrollBar* instance = new WebScrollBar();
58    instance->AddRef();
59    return instance;
60}
61
62// IUnknown -------------------------------------------------------------------
63
64HRESULT STDMETHODCALLTYPE WebScrollBar::QueryInterface(REFIID riid, void** ppvObject)
65{
66    *ppvObject = 0;
67    if (IsEqualGUID(riid, IID_IUnknown))
68        *ppvObject = static_cast<IUnknown*>(this);
69    else if (IsEqualGUID(riid, IID_IWebScrollBarPrivate))
70        *ppvObject = static_cast<IWebScrollBarPrivate*>(this);
71    else
72        return E_NOINTERFACE;
73
74    AddRef();
75    return S_OK;
76}
77
78ULONG STDMETHODCALLTYPE WebScrollBar::AddRef(void)
79{
80    return ++m_refCount;
81}
82
83ULONG STDMETHODCALLTYPE WebScrollBar::Release(void)
84{
85    ULONG newRef = --m_refCount;
86    if (!newRef)
87        delete(this);
88
89    return newRef;
90}
91
92// IWebScrollBarPrivate ------------------------------------------------------------------
93HRESULT STDMETHODCALLTYPE WebScrollBar::init(
94    /* [in] */ IWebScrollBarDelegatePrivate* delegate,
95    /* [in] */ OLE_HANDLE containingWindow,
96    /* [in] */ WebScrollBarOrientation orientation,
97    /* [in] */ WebScrollBarControlSize controlSize)
98{
99    if (!delegate || !containingWindow)
100        return E_FAIL;
101    ScrollbarOrientation webCoreOrientation = (ScrollbarOrientation) orientation;
102    ScrollbarControlSize webCoreControlSize = (ScrollbarControlSize) controlSize;
103    m_delegate = delegate;
104    m_scrollBar = Scrollbar::createNativeScrollbar(this, webCoreOrientation, webCoreControlSize);
105    if (!m_scrollBar)
106        return E_FAIL;
107    m_containingWindow = (HWND)(ULONG64)containingWindow;
108    return S_OK;
109}
110
111HRESULT STDMETHODCALLTYPE WebScrollBar::setEnabled(
112    /* [in] */ BOOL enabled)
113{
114    m_scrollBar->setEnabled(!!enabled);
115    return S_OK;
116}
117
118HRESULT STDMETHODCALLTYPE WebScrollBar::setSteps(
119    /* [in] */ int lineStep,
120    /* [in] */ int pageStep)
121{
122    m_scrollBar->setSteps(lineStep, pageStep);
123    return S_OK;
124}
125
126HRESULT STDMETHODCALLTYPE WebScrollBar::setProportion(
127    /* [in] */ int visibleSize,
128    /* [in] */ int totalSize)
129{
130    m_scrollBar->setProportion(visibleSize, totalSize);
131    return S_OK;
132}
133
134HRESULT STDMETHODCALLTYPE WebScrollBar::setRect(
135    /* [in] */ RECT bounds)
136{
137    IntRect rect(bounds.left, bounds.top, bounds.right-bounds.left, bounds.bottom-bounds.top);
138    m_scrollBar->setFrameRect(rect);
139    return S_OK;
140}
141
142HRESULT STDMETHODCALLTYPE WebScrollBar::setValue(
143    /* [in] */ int value)
144{
145    m_currentPosition = value;
146    ScrollableArea::scrollToOffsetWithoutAnimation(m_scrollBar->orientation(), m_currentPosition);
147    return S_OK;
148}
149
150HRESULT STDMETHODCALLTYPE WebScrollBar::value(
151    /* [retval][out] */ int* value)
152{
153    if (!value)
154        return E_POINTER;
155    *value = m_currentPosition;
156    return S_OK;
157}
158
159HRESULT STDMETHODCALLTYPE WebScrollBar::paint(
160    /* [in] */ HDC dc,
161    /* [in] */ RECT damageRect)
162{
163    GraphicsContext context(dc);
164    IntRect rect(damageRect.left, damageRect.top, damageRect.right-damageRect.left, damageRect.bottom-damageRect.top);
165    m_scrollBar->paint(&context, rect);
166    return S_OK;
167}
168
169HRESULT STDMETHODCALLTYPE WebScrollBar::frameRect(
170    /* [retval][out] */ RECT* bounds)
171{
172    if (!bounds)
173        return E_POINTER;
174    IntRect rect = m_scrollBar->frameRect();
175    bounds->left = rect.x();
176    bounds->right = rect.maxX();
177    bounds->top = rect.y();
178    bounds->bottom = rect.maxY();
179    return S_OK;
180}
181
182HRESULT STDMETHODCALLTYPE WebScrollBar::width(
183    /* [retval][out] */ int* w)
184{
185    if (!w)
186        return E_POINTER;
187    *w = m_scrollBar->width();
188    return S_OK;
189}
190
191HRESULT STDMETHODCALLTYPE WebScrollBar::height(
192    /* [retval][out] */ int* h)
193{
194    if (!h)
195        return E_POINTER;
196    *h = m_scrollBar->height();
197    return S_OK;
198}
199
200HRESULT STDMETHODCALLTYPE WebScrollBar::requestedWidth(
201    /* [retval][out] */ int* w)
202{
203    if (!w)
204        return E_POINTER;
205
206    *w = m_scrollBar->orientation() == VerticalScrollbar ? ScrollbarTheme::theme()->scrollbarThickness(m_scrollBar->controlSize()) : -1;
207    return S_OK;
208}
209
210HRESULT STDMETHODCALLTYPE WebScrollBar::requestedHeight(
211    /* [retval][out] */ int* h)
212{
213    if (!h)
214        return E_POINTER;
215
216    *h = m_scrollBar->orientation() == HorizontalScrollbar ? ScrollbarTheme::theme()->scrollbarThickness(m_scrollBar->controlSize()) : -1;
217    return S_OK;
218}
219
220
221HRESULT STDMETHODCALLTYPE WebScrollBar::handleMouseEvent(
222    OLE_HANDLE window,
223    UINT msg,
224    WPARAM wParam,
225    LPARAM lParam)
226{
227    PlatformMouseEvent mouseEvent((HWND)(ULONG64)window, msg, wParam, lParam);
228    switch (msg) {
229        case WM_LBUTTONDOWN:
230            m_scrollBar->mouseDown(mouseEvent);
231            break;
232        case WM_LBUTTONUP:
233            m_scrollBar->mouseUp(mouseEvent);
234            break;
235        case WM_MOUSEMOVE:
236            m_scrollBar->mouseMoved(mouseEvent);
237            break;
238    }
239
240    return S_OK;
241}
242
243HRESULT STDMETHODCALLTYPE WebScrollBar::scroll(
244    WebScrollDirection direction,
245    WebScrollGranularity granularity,
246    float multiplier)
247{
248    ScrollDirection webCoreScrollDirection = (ScrollDirection) direction;
249    ScrollGranularity webCoreGranularity = (ScrollGranularity) granularity;
250    ScrollableArea::scroll(webCoreScrollDirection, webCoreGranularity, multiplier);
251    return S_OK;
252}
253
254// ScrollableArea -------------------------------------------------------
255
256int WebScrollBar::scrollSize(ScrollbarOrientation orientation) const
257{
258    return (orientation == m_scrollBar->orientation()) ? (m_scrollBar->totalSize() - m_scrollBar->visibleSize()) : 0;
259}
260
261int WebScrollBar::scrollPosition(Scrollbar*) const
262{
263    return m_currentPosition;
264}
265
266void WebScrollBar::setScrollOffset(const IntPoint& offset)
267{
268    m_currentPosition = (m_scrollBar->orientation() == HorizontalScrollbar) ? offset.x() : offset.y();
269    m_delegate->valueChanged(this);
270}
271
272void WebScrollBar::invalidateScrollbarRect(Scrollbar*, const IntRect& rect)
273{
274    RECT r = rect;
275    ::InvalidateRect(m_containingWindow, &r, false);
276}
277
278Scrollbar* WebScrollBar::horizontalScrollbar() const
279{
280    return m_scrollBar->orientation() == HorizontalScrollbar ? m_scrollBar.get() : 0;
281}
282
283Scrollbar* WebScrollBar::verticalScrollbar() const
284{
285    return m_scrollBar->orientation() == VerticalScrollbar ? m_scrollBar.get() : 0;
286}
287
288int WebScrollBar::visibleHeight() const
289{
290    return m_scrollBar->height();
291}
292
293int WebScrollBar::visibleWidth() const
294{
295    return m_scrollBar->width();
296}
297
298WebCore::IntSize WebScrollBar::contentsSize() const
299{
300    return m_scrollBar->frameRect().size();
301}
302
303bool WebScrollBar::scrollbarsCanBeActive() const
304{
305    return true;
306}
307
308WebCore::IntRect WebScrollBar::scrollableAreaBoundingBox() const
309{
310    return m_scrollBar->frameRect();
311}
312