OLD | NEW |
| (Empty) |
1 // Copyright 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "WebCompositorInputHandlerImpl.h" | |
8 | |
9 #include "CCActiveGestureAnimation.h" | |
10 #include "CCProxy.h" | |
11 #include "PlatformGestureCurveTarget.h" | |
12 #include "TouchpadFlingPlatformGestureCurve.h" | |
13 #include "TraceEvent.h" | |
14 #include "WebCompositorImpl.h" | |
15 #include "WebCompositorInputHandlerClient.h" | |
16 #include "WebInputEvent.h" | |
17 #include <wtf/ThreadingPrimitives.h> | |
18 | |
19 using namespace WebCore; | |
20 | |
21 namespace WebCore { | |
22 | |
23 PassOwnPtr<CCInputHandler> CCInputHandler::create(CCInputHandlerClient* inputHan
dlerClient) | |
24 { | |
25 return WebKit::WebCompositorInputHandlerImpl::create(inputHandlerClient); | |
26 } | |
27 | |
28 class PlatformGestureToCCGestureAdapter : public CCGestureCurve, public Platform
GestureCurveTarget { | |
29 public: | |
30 static PassOwnPtr<CCGestureCurve> create(PassOwnPtr<PlatformGestureCurve> pl
atformCurve) | |
31 { | |
32 return adoptPtr(new PlatformGestureToCCGestureAdapter(platformCurve)); | |
33 } | |
34 | |
35 virtual const char* debugName() const | |
36 { | |
37 return m_curve->debugName(); | |
38 } | |
39 | |
40 virtual bool apply(double time, CCGestureCurveTarget* target) | |
41 { | |
42 ASSERT(target); | |
43 m_target = target; | |
44 return m_curve->apply(time, this); | |
45 } | |
46 | |
47 virtual void scrollBy(const IntPoint& scrollDelta) | |
48 { | |
49 ASSERT(m_target); | |
50 m_target->scrollBy(scrollDelta); | |
51 } | |
52 | |
53 private: | |
54 PlatformGestureToCCGestureAdapter(PassOwnPtr<PlatformGestureCurve> curve) | |
55 : m_curve(curve) | |
56 , m_target(0) | |
57 { | |
58 } | |
59 | |
60 OwnPtr<PlatformGestureCurve> m_curve; | |
61 CCGestureCurveTarget* m_target; | |
62 }; | |
63 | |
64 } | |
65 | |
66 namespace WebKit { | |
67 | |
68 // These statics may only be accessed from the compositor thread. | |
69 int WebCompositorInputHandlerImpl::s_nextAvailableIdentifier = 1; | |
70 HashSet<WebCompositorInputHandlerImpl*>* WebCompositorInputHandlerImpl::s_compos
itors = 0; | |
71 | |
72 WebCompositorInputHandler* WebCompositorInputHandler::fromIdentifier(int identif
ier) | |
73 { | |
74 return WebCompositorInputHandlerImpl::fromIdentifier(identifier); | |
75 } | |
76 | |
77 PassOwnPtr<WebCompositorInputHandlerImpl> WebCompositorInputHandlerImpl::create(
WebCore::CCInputHandlerClient* inputHandlerClient) | |
78 { | |
79 return adoptPtr(new WebCompositorInputHandlerImpl(inputHandlerClient)); | |
80 } | |
81 | |
82 WebCompositorInputHandler* WebCompositorInputHandlerImpl::fromIdentifier(int ide
ntifier) | |
83 { | |
84 ASSERT(WebCompositorImpl::initialized()); | |
85 ASSERT(CCProxy::isImplThread()); | |
86 | |
87 if (!s_compositors) | |
88 return 0; | |
89 | |
90 for (HashSet<WebCompositorInputHandlerImpl*>::iterator it = s_compositors->b
egin(); it != s_compositors->end(); ++it) { | |
91 if ((*it)->identifier() == identifier) | |
92 return *it; | |
93 } | |
94 return 0; | |
95 } | |
96 | |
97 WebCompositorInputHandlerImpl::WebCompositorInputHandlerImpl(CCInputHandlerClien
t* inputHandlerClient) | |
98 : m_client(0) | |
99 , m_identifier(s_nextAvailableIdentifier++) | |
100 , m_inputHandlerClient(inputHandlerClient) | |
101 #ifndef NDEBUG | |
102 , m_expectScrollUpdateEnd(false) | |
103 , m_expectPinchUpdateEnd(false) | |
104 #endif | |
105 , m_gestureScrollStarted(false) | |
106 { | |
107 ASSERT(CCProxy::isImplThread()); | |
108 | |
109 if (!s_compositors) | |
110 s_compositors = new HashSet<WebCompositorInputHandlerImpl*>; | |
111 s_compositors->add(this); | |
112 } | |
113 | |
114 WebCompositorInputHandlerImpl::~WebCompositorInputHandlerImpl() | |
115 { | |
116 ASSERT(CCProxy::isImplThread()); | |
117 if (m_client) | |
118 m_client->willShutdown(); | |
119 | |
120 ASSERT(s_compositors); | |
121 s_compositors->remove(this); | |
122 if (!s_compositors->size()) { | |
123 delete s_compositors; | |
124 s_compositors = 0; | |
125 } | |
126 } | |
127 | |
128 void WebCompositorInputHandlerImpl::setClient(WebCompositorInputHandlerClient* c
lient) | |
129 { | |
130 ASSERT(CCProxy::isImplThread()); | |
131 // It's valid to set a new client if we've never had one or to clear the cli
ent, but it's not valid to change from having one client to a different one. | |
132 ASSERT(!m_client || !client); | |
133 m_client = client; | |
134 } | |
135 | |
136 void WebCompositorInputHandlerImpl::handleInputEvent(const WebInputEvent& event) | |
137 { | |
138 ASSERT(CCProxy::isImplThread()); | |
139 ASSERT(m_client); | |
140 | |
141 WebCompositorInputHandlerImpl::EventDisposition disposition = handleInputEve
ntInternal(event); | |
142 switch (disposition) { | |
143 case DidHandle: | |
144 m_client->didHandleInputEvent(); | |
145 break; | |
146 case DidNotHandle: | |
147 m_client->didNotHandleInputEvent(true /* sendToWidget */); | |
148 break; | |
149 case DropEvent: | |
150 m_client->didNotHandleInputEvent(false /* sendToWidget */); | |
151 break; | |
152 } | |
153 } | |
154 | |
155 WebCompositorInputHandlerImpl::EventDisposition WebCompositorInputHandlerImpl::h
andleInputEventInternal(const WebInputEvent& event) | |
156 { | |
157 if (event.type == WebInputEvent::MouseWheel) { | |
158 const WebMouseWheelEvent& wheelEvent = *static_cast<const WebMouseWheelE
vent*>(&event); | |
159 CCInputHandlerClient::ScrollStatus scrollStatus = m_inputHandlerClient->
scrollBegin(IntPoint(wheelEvent.x, wheelEvent.y), CCInputHandlerClient::Wheel); | |
160 switch (scrollStatus) { | |
161 case CCInputHandlerClient::ScrollStarted: { | |
162 TRACE_EVENT_INSTANT2("cc", "WebCompositorInputHandlerImpl::handleInp
ut wheel scroll", "deltaX", -wheelEvent.deltaX, "deltaY", -wheelEvent.deltaY); | |
163 m_inputHandlerClient->scrollBy(IntPoint(wheelEvent.x, wheelEvent.y),
IntSize(-wheelEvent.deltaX, -wheelEvent.deltaY)); | |
164 m_inputHandlerClient->scrollEnd(); | |
165 return DidHandle; | |
166 } | |
167 case CCInputHandlerClient::ScrollIgnored: | |
168 // FIXME: This should be DropEvent, but in cases where we fail to pr
operly sync scrollability it's safer to send the | |
169 // event to the main thread. Change back to DropEvent once we have s
ynchronization bugs sorted out. | |
170 return DidNotHandle; | |
171 case CCInputHandlerClient::ScrollOnMainThread: | |
172 return DidNotHandle; | |
173 } | |
174 } else if (event.type == WebInputEvent::GestureScrollBegin) { | |
175 ASSERT(!m_gestureScrollStarted); | |
176 ASSERT(!m_expectScrollUpdateEnd); | |
177 #ifndef NDEBUG | |
178 m_expectScrollUpdateEnd = true; | |
179 #endif | |
180 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
181 CCInputHandlerClient::ScrollStatus scrollStatus = m_inputHandlerClient->
scrollBegin(IntPoint(gestureEvent.x, gestureEvent.y), CCInputHandlerClient::Gest
ure); | |
182 switch (scrollStatus) { | |
183 case CCInputHandlerClient::ScrollStarted: | |
184 m_gestureScrollStarted = true; | |
185 return DidHandle; | |
186 case CCInputHandlerClient::ScrollOnMainThread: | |
187 return DidNotHandle; | |
188 case CCInputHandlerClient::ScrollIgnored: | |
189 return DropEvent; | |
190 } | |
191 } else if (event.type == WebInputEvent::GestureScrollUpdate) { | |
192 ASSERT(m_expectScrollUpdateEnd); | |
193 | |
194 if (!m_gestureScrollStarted) | |
195 return DidNotHandle; | |
196 | |
197 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
198 m_inputHandlerClient->scrollBy(IntPoint(gestureEvent.x, gestureEvent.y),
IntSize(-gestureEvent.deltaX, -gestureEvent.deltaY)); | |
199 return DidHandle; | |
200 } else if (event.type == WebInputEvent::GestureScrollEnd) { | |
201 ASSERT(m_expectScrollUpdateEnd); | |
202 #ifndef NDEBUG | |
203 m_expectScrollUpdateEnd = false; | |
204 #endif | |
205 if (!m_gestureScrollStarted) | |
206 return DidNotHandle; | |
207 | |
208 m_inputHandlerClient->scrollEnd(); | |
209 m_gestureScrollStarted = false; | |
210 return DidHandle; | |
211 } else if (event.type == WebInputEvent::GesturePinchBegin) { | |
212 ASSERT(!m_expectPinchUpdateEnd); | |
213 #ifndef NDEBUG | |
214 m_expectPinchUpdateEnd = true; | |
215 #endif | |
216 m_inputHandlerClient->pinchGestureBegin(); | |
217 return DidHandle; | |
218 } else if (event.type == WebInputEvent::GesturePinchEnd) { | |
219 ASSERT(m_expectPinchUpdateEnd); | |
220 #ifndef NDEBUG | |
221 m_expectPinchUpdateEnd = false; | |
222 #endif | |
223 m_inputHandlerClient->pinchGestureEnd(); | |
224 return DidHandle; | |
225 } else if (event.type == WebInputEvent::GesturePinchUpdate) { | |
226 ASSERT(m_expectPinchUpdateEnd); | |
227 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
228 m_inputHandlerClient->pinchGestureUpdate(gestureEvent.deltaX, IntPoint(g
estureEvent.x, gestureEvent.y)); | |
229 return DidHandle; | |
230 } else if (event.type == WebInputEvent::GestureFlingStart) { | |
231 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
232 return handleGestureFling(gestureEvent); | |
233 } else if (event.type == WebInputEvent::GestureFlingCancel) { | |
234 if (cancelCurrentFling()) | |
235 return DidHandle; | |
236 } else if (WebInputEvent::isKeyboardEventType(event.type)) { | |
237 cancelCurrentFling(); | |
238 } | |
239 | |
240 return DidNotHandle; | |
241 } | |
242 | |
243 WebCompositorInputHandlerImpl::EventDisposition WebCompositorInputHandlerImpl::h
andleGestureFling(const WebGestureEvent& gestureEvent) | |
244 { | |
245 CCInputHandlerClient::ScrollStatus scrollStatus = m_inputHandlerClient->scro
llBegin(IntPoint(gestureEvent.x, gestureEvent.y), CCInputHandlerClient::Gesture)
; | |
246 switch (scrollStatus) { | |
247 case CCInputHandlerClient::ScrollStarted: { | |
248 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::handleGesture
Fling::started"); | |
249 OwnPtr<PlatformGestureCurve> flingCurve = TouchpadFlingPlatformGestureCu
rve::create(FloatPoint(gestureEvent.deltaX, gestureEvent.deltaY)); | |
250 m_wheelFlingAnimation = CCActiveGestureAnimation::create(PlatformGesture
ToCCGestureAdapter::create(flingCurve.release()), this); | |
251 m_wheelFlingParameters.delta = WebFloatPoint(gestureEvent.deltaX, gestur
eEvent.deltaY); | |
252 m_wheelFlingParameters.point = WebPoint(gestureEvent.x, gestureEvent.y); | |
253 m_wheelFlingParameters.globalPoint = WebPoint(gestureEvent.globalX, gest
ureEvent.globalY); | |
254 m_wheelFlingParameters.modifiers = gestureEvent.modifiers; | |
255 m_inputHandlerClient->scheduleAnimation(); | |
256 return DidHandle; | |
257 } | |
258 case CCInputHandlerClient::ScrollOnMainThread: { | |
259 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::handleGesture
Fling::scrollOnMainThread"); | |
260 return DidNotHandle; | |
261 } | |
262 case CCInputHandlerClient::ScrollIgnored: { | |
263 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::handleGesture
Fling::ignored"); | |
264 // We still pass the curve to the main thread if there's nothing scrolla
ble, in case something | |
265 // registers a handler before the curve is over. | |
266 return DidNotHandle; | |
267 } | |
268 } | |
269 return DidNotHandle; | |
270 } | |
271 | |
272 int WebCompositorInputHandlerImpl::identifier() const | |
273 { | |
274 ASSERT(CCProxy::isImplThread()); | |
275 return m_identifier; | |
276 } | |
277 | |
278 void WebCompositorInputHandlerImpl::animate(double monotonicTime) | |
279 { | |
280 if (!m_wheelFlingAnimation) | |
281 return; | |
282 | |
283 if (!m_wheelFlingParameters.startTime) | |
284 m_wheelFlingParameters.startTime = monotonicTime; | |
285 | |
286 if (m_wheelFlingAnimation->animate(monotonicTime)) | |
287 m_inputHandlerClient->scheduleAnimation(); | |
288 else { | |
289 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::animate::flin
gOver"); | |
290 cancelCurrentFling(); | |
291 } | |
292 } | |
293 | |
294 bool WebCompositorInputHandlerImpl::cancelCurrentFling() | |
295 { | |
296 bool hadFlingAnimation = m_wheelFlingAnimation; | |
297 TRACE_EVENT_INSTANT1("cc", "WebCompositorInputHandlerImpl::cancelCurrentFlin
g", "hadFlingAnimation", hadFlingAnimation); | |
298 m_wheelFlingAnimation.clear(); | |
299 m_wheelFlingParameters = WebActiveWheelFlingParameters(); | |
300 return hadFlingAnimation; | |
301 } | |
302 | |
303 void WebCompositorInputHandlerImpl::scrollBy(const IntPoint& increment) | |
304 { | |
305 if (increment == IntPoint::zero()) | |
306 return; | |
307 | |
308 TRACE_EVENT2("cc", "WebCompositorInputHandlerImpl::scrollBy", "x", increment
.x(), "y", increment.y()); | |
309 WebMouseWheelEvent syntheticWheel; | |
310 syntheticWheel.type = WebInputEvent::MouseWheel; | |
311 syntheticWheel.deltaX = increment.x(); | |
312 syntheticWheel.deltaY = increment.y(); | |
313 syntheticWheel.hasPreciseScrollingDeltas = true; | |
314 syntheticWheel.x = m_wheelFlingParameters.point.x; | |
315 syntheticWheel.y = m_wheelFlingParameters.point.y; | |
316 syntheticWheel.globalX = m_wheelFlingParameters.globalPoint.x; | |
317 syntheticWheel.globalY = m_wheelFlingParameters.globalPoint.y; | |
318 syntheticWheel.modifiers = m_wheelFlingParameters.modifiers; | |
319 | |
320 WebCompositorInputHandlerImpl::EventDisposition disposition = handleInputEve
ntInternal(syntheticWheel); | |
321 switch (disposition) { | |
322 case DidHandle: | |
323 m_wheelFlingParameters.cumulativeScroll.width += increment.x(); | |
324 m_wheelFlingParameters.cumulativeScroll.height += increment.y(); | |
325 case DropEvent: | |
326 break; | |
327 case DidNotHandle: | |
328 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::scrollBy::Abo
rtFling"); | |
329 // If we got a DidNotHandle, that means we need to deliver wheels on the
main thread. | |
330 // In this case we need to schedule a commit and transfer the fling curv
e over to the main | |
331 // thread and run the rest of the wheels from there. | |
332 // This can happen when flinging a page that contains a scrollable subar
ea that we can't | |
333 // scroll on the thread if the fling starts outside the subarea but then
is flung "under" the | |
334 // pointer. | |
335 m_client->transferActiveWheelFlingAnimation(m_wheelFlingParameters); | |
336 cancelCurrentFling(); | |
337 break; | |
338 } | |
339 } | |
340 | |
341 } | |
OLD | NEW |