c0131cb09664206d707629fe6f7c438220fb8ee5
[WebKit-https.git] / WebKit / chromium / src / WebScrollbarImpl.cpp
1 /*
2  * Copyright (C) 2010 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "WebScrollbarImpl.h"
33
34 #include "GraphicsContext.h"
35 #include "KeyboardCodes.h"
36 #include "PlatformContextSkia.h"
37 #include "Scrollbar.h"
38 #include "ScrollbarTheme.h"
39 #include "ScrollTypes.h"
40 #include "WebCanvas.h"
41 #include "WebInputEvent.h"
42 #include "WebInputEventConversion.h"
43 #include "WebRect.h"
44 #include "WebScrollbarClient.h"
45 #include "WebVector.h"
46 #include "WebViewImpl.h"
47
48 using namespace std;
49 using namespace WebCore;
50
51 namespace WebKit {
52
53 WebScrollbar* WebScrollbar::create(WebScrollbarClient* client, Orientation orientation)
54 {
55     return new WebScrollbarImpl(client, orientation);
56 }
57
58 int WebScrollbar::defaultThickness()
59 {
60     return ScrollbarTheme::nativeTheme()->scrollbarThickness();
61 }
62
63 WebScrollbarImpl::WebScrollbarImpl(WebScrollbarClient* client, Orientation orientation)
64     : m_client(client)
65 {
66     m_scrollbar = Scrollbar::createNativeScrollbar(
67         static_cast<ScrollbarClient*>(this),
68         static_cast<ScrollbarOrientation>(orientation),
69         RegularScrollbar);
70 }
71
72 WebScrollbarImpl::~WebScrollbarImpl()
73 {
74 }
75
76 void WebScrollbarImpl::setLocation(const WebRect& rect)
77 {
78     WebCore::IntRect oldRect = m_scrollbar->frameRect();
79     m_scrollbar->setFrameRect(rect);
80     if (WebRect(oldRect) != rect)
81       m_scrollbar->invalidate();
82
83     int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
84     int pageStep = max(max(static_cast<int>(static_cast<float>(length) * Scrollbar::minFractionToStepWhenPaging()), length - Scrollbar::maxOverlapBetweenPages()), 1);
85     m_scrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
86     m_scrollbar->setEnabled(m_scrollbar->totalSize() > length);
87     m_scrollbar->setProportion(length, m_scrollbar->totalSize());
88 }
89
90 int WebScrollbarImpl::value() const
91 {
92     return m_scrollbar->value();
93 }
94
95 void WebScrollbarImpl::setValue(int position)
96 {
97     m_scrollbar->setValue(position);
98 }
99
100 void WebScrollbarImpl::setDocumentSize(int size)
101 {
102     int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
103     m_scrollbar->setEnabled(size > length);
104     m_scrollbar->setProportion(length, size);
105 }
106
107 void WebScrollbarImpl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
108 {
109     WebCore::ScrollDirection dir;
110     bool horizontal = m_scrollbar->orientation() == HorizontalScrollbar;
111     if (direction == ScrollForward)
112         dir = horizontal ? ScrollRight : ScrollDown;
113     else
114         dir = horizontal ? ScrollLeft : ScrollUp;
115     m_scrollbar->scroll(dir, static_cast<WebCore::ScrollGranularity>(granularity), multiplier);
116 }
117
118 void WebScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect)
119 {
120 #if WEBKIT_USING_CG
121     GraphicsContext gc(canvas);
122 #elif WEBKIT_USING_SKIA
123     PlatformContextSkia context(canvas);
124
125     // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
126     GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
127 #else
128     notImplemented();
129 #endif
130
131     m_scrollbar->paint(&gc, rect);
132 }
133
134 bool WebScrollbarImpl::handleInputEvent(const WebInputEvent& event)
135 {
136     switch (event.type) {
137     case WebInputEvent::MouseDown:
138         return onMouseDown(event);
139     case WebInputEvent::MouseUp:
140         return onMouseUp(event);
141     case WebInputEvent::MouseMove:
142         return onMouseMove(event);
143     case WebInputEvent::MouseLeave:
144         return onMouseLeave(event);
145     case WebInputEvent::MouseWheel:
146         return onMouseWheel(event);
147     case WebInputEvent::KeyDown:
148         return onKeyDown(event);
149     case WebInputEvent::Undefined:
150     case WebInputEvent::MouseEnter:
151     case WebInputEvent::RawKeyDown:
152     case WebInputEvent::KeyUp:
153     case WebInputEvent::Char:
154     case WebInputEvent::TouchStart:
155     case WebInputEvent::TouchMove:
156     case WebInputEvent::TouchEnd:
157     case WebInputEvent::TouchCancel:
158     default:
159          break;
160     }
161     return false;
162 }
163
164 bool WebScrollbarImpl::onMouseDown(const WebInputEvent& event)
165 {
166     WebMouseEvent mousedown = *static_cast<const WebMouseEvent*>(&event);
167     if (!m_scrollbar->frameRect().contains(mousedown.x, mousedown.y))
168         return false;
169
170             mousedown.x -= m_scrollbar->x();
171             mousedown.y -= m_scrollbar->y();
172             m_scrollbar->mouseDown(PlatformMouseEventBuilder(m_scrollbar.get(), mousedown));
173             return true;
174         }
175
176 bool WebScrollbarImpl::onMouseUp(const WebInputEvent& event)
177 {
178     if (m_scrollbar->pressedPart() == NoPart)
179         return false;
180
181     return m_scrollbar->mouseUp();
182 }
183
184 bool WebScrollbarImpl::onMouseMove(const WebInputEvent& event)
185 {
186         WebMouseEvent mousemove = *static_cast<const WebMouseEvent*>(&event);
187         if (m_scrollbar->frameRect().contains(mousemove.x, mousemove.y)
188             || m_scrollbar->pressedPart() != NoPart) {
189             mousemove.x -= m_scrollbar->x();
190             mousemove.y -= m_scrollbar->y();
191             return m_scrollbar->mouseMoved(PlatformMouseEventBuilder(m_scrollbar.get(), mousemove));
192         }
193
194         if (m_scrollbar->hoveredPart() != NoPart)
195             m_scrollbar->mouseExited();
196     return false;
197 }
198
199 bool WebScrollbarImpl::onMouseLeave(const WebInputEvent& event)
200 {
201     if (m_scrollbar->hoveredPart() == NoPart)
202         return false;
203
204     return m_scrollbar->mouseExited();
205 }
206
207 bool WebScrollbarImpl::onMouseWheel(const WebInputEvent& event)
208 {
209         // Same logic as in Scrollview.cpp.  If we can move at all, we'll accept the event.
210         WebMouseWheelEvent mousewheel = *static_cast<const WebMouseWheelEvent*>(&event);
211         int maxScrollDelta = m_scrollbar->maximum() - m_scrollbar->value();
212         float delta = m_scrollbar->orientation() == HorizontalScrollbar ? mousewheel.deltaX : mousewheel.deltaY;
213         if ((delta < 0 && maxScrollDelta > 0) || (delta > 0 && m_scrollbar->value() > 0)) {
214             if (mousewheel.scrollByPage) {
215                 ASSERT(m_scrollbar->orientation() == VerticalScrollbar);
216                 bool negative = delta < 0;
217                 delta = max(max(static_cast<float>(m_scrollbar->visibleSize()) * Scrollbar::minFractionToStepWhenPaging(), static_cast<float>(m_scrollbar->visibleSize() - Scrollbar::maxOverlapBetweenPages())), 1.0f);
218                 if (negative)
219                     delta *= -1;
220             }
221             m_scrollbar->setValue(m_scrollbar->value() - delta);
222             return true;
223         }
224
225     return false;
226     }
227
228 bool WebScrollbarImpl::onKeyDown(const WebInputEvent& event)
229 {
230         WebKeyboardEvent keyboard = *static_cast<const WebKeyboardEvent*>(&event);
231         int keyCode;
232         // We have to duplicate this logic from WebViewImpl because there it uses
233         // Char and RawKeyDown events, which don't exist at this point.
234         if (keyboard.windowsKeyCode == VKEY_SPACE)
235             keyCode = ((keyboard.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
236         else {
237             if (keyboard.modifiers == WebInputEvent::ControlKey) {
238                 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
239                 // key combinations which affect scrolling. Safari is buggy in the
240                 // sense that it scrolls the page for all Ctrl+scrolling key
241                 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
242                 switch (keyboard.windowsKeyCode) {
243                 case VKEY_HOME:
244                 case VKEY_END:
245                     break;
246                 default:
247                     return false;
248                 }
249             }
250
251             if (keyboard.isSystemKey || (keyboard.modifiers & WebInputEvent::ShiftKey))
252                 return false;
253
254             keyCode = keyboard.windowsKeyCode;
255         }
256         WebCore::ScrollDirection scrollDirection;
257         WebCore::ScrollGranularity scrollGranularity;
258         if (WebViewImpl::mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) {
259             // Will return false if scroll direction wasn't compatible with this scrollbar.
260             return m_scrollbar->scroll(scrollDirection, scrollGranularity);
261         }
262     return false;
263 }
264
265 void WebScrollbarImpl::valueChanged(WebCore::Scrollbar*)
266 {
267     m_client->valueChanged(this);
268 }
269
270 void WebScrollbarImpl::invalidateScrollbarRect(WebCore::Scrollbar*, const WebCore::IntRect& rect)
271 {
272     WebRect webrect(rect);
273     webrect.x += m_scrollbar->x();
274     webrect.y += m_scrollbar->y();
275     m_client->invalidateScrollbarRect(this, webrect);
276 }
277
278 bool WebScrollbarImpl::isActive() const
279 {
280     return true;
281 }
282
283 bool WebScrollbarImpl::scrollbarCornerPresent() const
284 {
285     return false;
286 }
287
288 void WebScrollbarImpl::getTickmarks(Vector<WebCore::IntRect>& tickmarks) const
289 {
290     WebVector<WebRect> ticks;
291     m_client->getTickmarks(const_cast<WebScrollbarImpl*>(this), &ticks);
292     tickmarks.resize(ticks.size());
293     for (size_t i = 0; i < ticks.size(); ++i)
294         tickmarks[i] = ticks[i];
295 }
296
297 } // namespace WebKit