|
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<int>(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<int>(m_scrollbar->visibleSize() * Scrollbar::minFractionToStepWhenPaging(), m_scrollbar->visibleSize() - Scrollbar::maxOverlapBetweenPages()), 1); |
|
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 |