OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 "core/input/ScrollManager.h" | |
6 | |
7 #include "core/dom/DOMNodeIds.h" | |
8 #include "core/events/GestureEvent.h" | |
9 #include "core/frame/FrameHost.h" | |
10 #include "core/frame/FrameView.h" | |
11 #include "core/frame/TopControls.h" | |
12 #include "core/html/HTMLFrameOwnerElement.h" | |
13 #include "core/input/EventHandler.h" | |
14 #include "core/layout/LayoutPart.h" | |
15 #include "core/loader/DocumentLoader.h" | |
16 #include "core/page/AutoscrollController.h" | |
17 #include "core/page/Page.h" | |
18 #include "core/page/scrolling/OverscrollController.h" | |
19 #include "core/page/scrolling/RootScroller.h" | |
20 #include "core/page/scrolling/ScrollState.h" | |
21 #include "core/paint/PaintLayer.h" | |
22 #include "platform/PlatformGestureEvent.h" | |
23 | |
24 | |
25 namespace blink { | |
26 | |
27 namespace { | |
28 | |
29 // TODO(bokan): This method can go away once all scrolls happen through the | |
30 // scroll customization path. | |
31 void computeScrollChainForSingleNode(Node& node, std::deque<int>& scrollChain) | |
32 { | |
33 scrollChain.clear(); | |
34 | |
35 DCHECK(node.layoutObject()); | |
36 Element* element = toElement(&node); | |
37 | |
38 scrollChain.push_front(DOMNodeIds::idForNode(element)); | |
39 } | |
40 | |
41 void recomputeScrollChain(const LocalFrame& frame, const Node& startNode, | |
42 std::deque<int>& scrollChain) | |
43 { | |
44 scrollChain.clear(); | |
45 | |
46 DCHECK(startNode.layoutObject()); | |
47 LayoutBox* curBox = startNode.layoutObject()->enclosingBox(); | |
48 | |
49 // Scrolling propagates along the containing block chain. | |
50 while (curBox && !curBox->isLayoutView()) { | |
51 Node* curNode = curBox->node(); | |
52 // FIXME: this should reject more elements, as part of crbug.com/410974. | |
53 if (curNode && curNode->isElementNode()) { | |
54 Element* curElement = toElement(curNode); | |
55 if (curElement == frame.document()->scrollingElement()) | |
56 break; | |
57 scrollChain.push_front(DOMNodeIds::idForNode(curElement)); | |
58 } | |
59 curBox = curBox->containingBlock(); | |
60 } | |
61 // TODO(tdresser): this should sometimes be excluded, as part of crbug.com/4 10974. | |
62 // We need to ensure that the scrollingElement is always part of | |
63 // the scroll chain. In quirks mode, when the scrollingElement is | |
64 // the body, some elements may use the documentElement as their | |
65 // containingBlock, so we ensure the scrollingElement is added | |
66 // here. | |
67 scrollChain.push_front(DOMNodeIds::idForNode(frame.document()->scrollingElem ent())); | |
68 } | |
69 | |
70 } // namespace | |
71 | |
72 ScrollManager::ScrollManager(LocalFrame* frame) | |
73 : m_frame(frame) | |
74 { | |
75 clear(); | |
76 } | |
77 | |
78 ScrollManager::~ScrollManager() | |
79 { | |
80 } | |
81 | |
82 void ScrollManager::clear() | |
83 { | |
84 m_lastGestureScrollOverWidget = false; | |
85 m_scrollbarHandlingScrollGesture = nullptr; | |
86 m_resizeScrollableArea = nullptr; | |
87 m_offsetFromResizeCorner = LayoutSize(); | |
88 clearGestureScrollState(); | |
89 } | |
90 | |
91 void ScrollManager::clearGestureScrollState() | |
92 { | |
93 m_scrollGestureHandlingNode = nullptr; | |
94 m_previousGestureScrolledNode = nullptr; | |
95 m_deltaConsumedForScrollSequence = false; | |
96 m_currentScrollChain.clear(); | |
97 | |
98 if (FrameHost* host = frameHost()) { | |
99 bool resetX = true; | |
100 bool resetY = true; | |
101 host->overscrollController().resetAccumulated(resetX, resetY); | |
102 } | |
103 } | |
104 | |
105 void ScrollManager::stopAutoscroll() | |
106 { | |
107 if (AutoscrollController* controller = autoscrollController()) | |
108 controller->stopAutoscroll(); | |
109 } | |
110 | |
111 bool ScrollManager::panScrollInProgress() const | |
112 { | |
113 return autoscrollController() && autoscrollController()->panScrollInProgress (); | |
114 } | |
115 | |
116 AutoscrollController* ScrollManager::autoscrollController() const | |
117 { | |
118 if (Page* page = m_frame->page()) | |
119 return &page->autoscrollController(); | |
120 return nullptr; | |
121 } | |
122 | |
123 ScrollResult ScrollManager::physicalScroll(ScrollGranularity granularity, | |
124 const FloatSize& delta, const FloatPoint& position, | |
125 const FloatSize& velocity, Node* startNode, Node** stopNode, bool* consumed) | |
126 { | |
127 if (consumed) | |
128 *consumed = false; | |
129 if (delta.isZero()) | |
130 return ScrollResult(); | |
131 | |
132 Node* node = startNode; | |
133 DCHECK(node && node->layoutObject()); | |
134 | |
135 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | |
136 | |
137 ScrollResult result; | |
138 | |
139 LayoutBox* curBox = node->layoutObject()->enclosingBox(); | |
140 while (curBox) { | |
141 // If we're at the stopNode, we should try to scroll it but we shouldn't | |
142 // chain past it. | |
143 bool shouldStopChaining = | |
144 stopNode && *stopNode && curBox->node() == *stopNode; | |
145 bool wasRootScroller = false; | |
146 | |
147 result = scrollBox( | |
148 curBox, | |
149 granularity, | |
150 delta, | |
151 position, | |
152 velocity, | |
153 &wasRootScroller); | |
154 | |
155 if (result.didScroll() && stopNode) | |
156 *stopNode = curBox->node(); | |
157 | |
158 if (result.didScroll() || shouldStopChaining) { | |
159 setFrameWasScrolledByUser(); | |
160 if (consumed) | |
161 *consumed = true; | |
162 return result; | |
163 } | |
164 if (wasRootScroller) { | |
165 // Don't try to chain past the root scroller, even if there's | |
166 // eligible ancestors. | |
167 break; | |
168 } | |
169 | |
170 curBox = curBox->containingBlock(); | |
171 } | |
172 | |
173 return result; | |
174 } | |
175 | |
176 bool ScrollManager::logicalScroll(ScrollDirection direction, ScrollGranularity g ranularity, Node* startNode, Node* mousePressNode) | |
177 { | |
178 Node* node = startNode; | |
179 | |
180 if (!node) | |
181 node = m_frame->document()->focusedElement(); | |
182 | |
183 if (!node) | |
184 node = mousePressNode; | |
185 | |
186 if ((!node || !node->layoutObject()) && m_frame->view() && !m_frame->view()- >layoutViewItem().isNull()) | |
187 node = m_frame->view()->layoutViewItem().node(); | |
188 | |
189 if (!node) | |
190 return false; | |
191 | |
192 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | |
193 | |
194 LayoutBox* curBox = node->layoutObject()->enclosingBox(); | |
195 while (curBox) { | |
196 ScrollDirectionPhysical physicalDirection = toPhysicalDirection( | |
197 direction, curBox->isHorizontalWritingMode(), curBox->style()->isFli ppedBlocksWritingMode()); | |
198 | |
199 ScrollResult result = curBox->scroll(granularity, toScrollDelta(physical Direction, 1)); | |
200 | |
201 if (result.didScroll()) { | |
202 setFrameWasScrolledByUser(); | |
203 return true; | |
204 } | |
205 | |
206 curBox = curBox->containingBlock(); | |
207 } | |
208 | |
209 return false; | |
210 } | |
211 | |
212 // TODO(bokan): This should be merged with logicalScroll assuming | |
213 // defaultSpaceEventHandler's chaining scroll can be done crossing frames. | |
214 bool ScrollManager::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode, Node* mousePressNode) | |
215 { | |
216 // The layout needs to be up to date to determine if we can scroll. We may b e | |
217 // here because of an onLoad event, in which case the final layout hasn't be en performed yet. | |
218 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | |
219 // FIXME: enable scroll customization in this case. See crbug.com/410974. | |
220 if (logicalScroll(direction, granularity, startingNode, mousePressNode)) | |
221 return true; | |
222 | |
223 Frame* parentFrame = m_frame->tree().parent(); | |
224 if (!parentFrame || !parentFrame->isLocalFrame()) | |
225 return false; | |
226 // FIXME: Broken for OOPI. | |
227 return toLocalFrame(parentFrame)->eventHandler().bubblingScroll(direction, g ranularity, m_frame->deprecatedLocalOwner()); | |
228 } | |
229 | |
230 ScrollResult ScrollManager::scrollBox(LayoutBox* box, | |
231 ScrollGranularity granularity, const FloatSize& delta, | |
232 const FloatPoint& position, const FloatSize& velocity, | |
233 bool* wasRootScroller) | |
234 { | |
235 DCHECK(box); | |
236 Node* node = box->node(); | |
237 | |
238 // If there's no ApplyScroll callback on the element, scroll as usuall in | |
239 // the non-scroll-customization case. | |
240 if (!node || !node->isElementNode() || !toElement(node)->getApplyScroll()) { | |
241 *wasRootScroller = false; | |
242 return box->scroll(granularity, delta); | |
243 } | |
244 | |
245 // Viewport actions should only happen when scrolling an element in the | |
246 // main frame. | |
247 DCHECK(m_frame->isMainFrame()); | |
248 | |
249 // If there is an ApplyScroll callback, its because we placed one on the | |
250 // root scroller to control top controls and overscroll. Invoke a scroll | |
251 // using parts of the scroll customization framework on just this element. | |
252 computeScrollChainForSingleNode(*node, m_currentScrollChain); | |
253 | |
254 OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateData()); | |
255 scrollStateData->delta_x = delta.width(); | |
256 scrollStateData->delta_y = delta.height(); | |
257 scrollStateData->position_x = position.x(); | |
258 scrollStateData->position_y = position.y(); | |
259 // TODO(bokan): delta_granularity is meant to be the number of pixels per | |
260 // unit of delta but we can't determine that until we get to the area we'll | |
261 // scroll. This is a hack, we stuff the enum into the double value for | |
262 // now. | |
263 scrollStateData->delta_granularity = static_cast<double>(granularity); | |
264 scrollStateData->velocity_x = velocity.width(); | |
265 scrollStateData->velocity_y = velocity.height(); | |
266 scrollStateData->should_propagate = false; | |
267 scrollStateData->is_in_inertial_phase = false; | |
268 scrollStateData->from_user_input = true; | |
269 scrollStateData->delta_consumed_for_scroll_sequence = false; | |
270 ScrollState* scrollState = | |
271 ScrollState::create(std::move(scrollStateData)); | |
272 | |
273 customizedScroll(*node, *scrollState); | |
274 | |
275 ScrollResult result( | |
276 scrollState->deltaX() != delta.width(), | |
277 scrollState->deltaY() != delta.height(), | |
278 scrollState->deltaX(), | |
279 scrollState->deltaY()); | |
280 | |
281 *wasRootScroller = true; | |
282 m_currentScrollChain.clear(); | |
283 | |
284 return result; | |
285 } | |
286 | |
287 void ScrollManager::setFrameWasScrolledByUser() | |
288 { | |
289 if (DocumentLoader* documentLoader = m_frame->loader().documentLoader()) | |
290 documentLoader->initialScrollState().wasScrolledByUser = true; | |
291 } | |
292 | |
293 void ScrollManager::customizedScroll(const Node& startNode, ScrollState& scrollS tate) | |
294 { | |
295 if (scrollState.fullyConsumed()) | |
296 return; | |
297 | |
298 if (scrollState.deltaX() || scrollState.deltaY()) | |
299 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | |
300 | |
301 if (m_currentScrollChain.empty()) | |
302 recomputeScrollChain(*m_frame, startNode, m_currentScrollChain); | |
303 scrollState.setScrollChain(m_currentScrollChain); | |
304 | |
305 scrollState.distributeToScrollChainDescendant(); | |
306 } | |
307 | |
308 WebInputEventResult ScrollManager::handleGestureScrollBegin(const PlatformGestur eEvent& gestureEvent) | |
bokan
2016/05/31 19:39:13
To me, this and (related methods) seems like it be
mustaq
2016/05/31 20:20:10
Again, may be a TODO in the class-level comment in
Navid Zolghadr
2016/06/01 17:36:43
I was on the fence on whether to put the scroll ge
| |
309 { | |
310 Document* document = m_frame->document(); | |
311 if (document->layoutViewItem().isNull()) | |
312 return WebInputEventResult::NotHandled; | |
313 | |
314 FrameView* view = m_frame->view(); | |
315 if (!view) | |
316 return WebInputEventResult::NotHandled; | |
317 | |
318 // If there's no layoutObject on the node, send the event to the nearest anc estor with a layoutObject. | |
319 // Needed for <option> and <optgroup> elements so we can touch scroll <selec t>s | |
320 while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->layoutOb ject()) | |
321 m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShado wHostNode(); | |
322 | |
323 if (!m_scrollGestureHandlingNode) { | |
324 if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) | |
325 m_scrollGestureHandlingNode = m_frame->document()->documentElement() ; | |
326 else | |
327 return WebInputEventResult::NotHandled; | |
328 } | |
329 DCHECK(m_scrollGestureHandlingNode); | |
330 | |
331 passScrollGestureEventToWidget(gestureEvent, m_scrollGestureHandlingNode->la youtObject()); | |
332 if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) { | |
333 m_currentScrollChain.clear(); | |
334 OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateData() ); | |
335 scrollStateData->position_x = gestureEvent.position().x(); | |
336 scrollStateData->position_y = gestureEvent.position().y(); | |
337 scrollStateData->is_beginning = true; | |
338 scrollStateData->from_user_input = true; | |
339 scrollStateData->delta_consumed_for_scroll_sequence = m_deltaConsumedFor ScrollSequence; | |
340 ScrollState* scrollState = ScrollState::create(std::move(scrollStateData )); | |
341 customizedScroll(*m_scrollGestureHandlingNode.get(), *scrollState); | |
342 } else { | |
343 if (m_frame->isMainFrame()) | |
344 m_frame->host()->topControls().scrollBegin(); | |
345 } | |
346 return WebInputEventResult::HandledSystem; | |
347 } | |
348 | |
349 WebInputEventResult ScrollManager::handleGestureScrollUpdate(const PlatformGestu reEvent& gestureEvent) | |
350 { | |
351 DCHECK_EQ(gestureEvent.type(), PlatformEvent::GestureScrollUpdate); | |
352 | |
353 // Negate the deltas since the gesture event stores finger movement and | |
354 // scrolling occurs in the direction opposite the finger's movement | |
355 // direction. e.g. Finger moving up has negative event delta but causes the | |
356 // page to scroll down causing positive scroll delta. | |
357 FloatSize delta(-gestureEvent.deltaX(), -gestureEvent.deltaY()); | |
358 FloatSize velocity(-gestureEvent.velocityX(), -gestureEvent.velocityY()); | |
359 if (delta.isZero()) | |
360 return WebInputEventResult::NotHandled; | |
361 | |
362 ScrollGranularity granularity = gestureEvent.deltaUnits(); | |
363 Node* node = m_scrollGestureHandlingNode.get(); | |
364 | |
365 // Scroll customization is only available for touch. | |
366 bool handleScrollCustomization = RuntimeEnabledFeatures::scrollCustomization Enabled() && gestureEvent.source() == PlatformGestureSourceTouchscreen; | |
367 if (node) { | |
368 LayoutObject* layoutObject = node->layoutObject(); | |
369 if (!layoutObject) | |
370 return WebInputEventResult::NotHandled; | |
371 | |
372 // Try to send the event to the correct view. | |
373 WebInputEventResult result = passScrollGestureEventToWidget(gestureEvent , layoutObject); | |
374 if (result != WebInputEventResult::NotHandled) { | |
375 if (gestureEvent.preventPropagation() | |
376 && !RuntimeEnabledFeatures::scrollCustomizationEnabled()) { | |
377 // This is an optimization which doesn't apply with | |
378 // scroll customization enabled. | |
379 m_previousGestureScrolledNode = m_scrollGestureHandlingNode; | |
380 } | |
381 // FIXME: we should allow simultaneous scrolling of nested | |
382 // iframes along perpendicular axes. See crbug.com/466991. | |
383 m_deltaConsumedForScrollSequence = true; | |
384 return result; | |
385 } | |
386 | |
387 if (handleScrollCustomization) { | |
388 OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateDa ta()); | |
389 scrollStateData->delta_x = delta.width(); | |
390 scrollStateData->delta_y = delta.height(); | |
391 scrollStateData->delta_granularity = ScrollByPrecisePixel; | |
392 scrollStateData->velocity_x = velocity.width(); | |
393 scrollStateData->velocity_y = velocity.height(); | |
394 scrollStateData->should_propagate = !gestureEvent.preventPropagation (); | |
395 scrollStateData->is_in_inertial_phase = gestureEvent.inertialPhase() == ScrollInertialPhaseMomentum; | |
396 scrollStateData->from_user_input = true; | |
397 scrollStateData->delta_consumed_for_scroll_sequence = m_deltaConsume dForScrollSequence; | |
398 ScrollState* scrollState = ScrollState::create(std::move(scrollState Data)); | |
399 if (m_previousGestureScrolledNode) { | |
400 // The ScrollState needs to know what the current | |
401 // native scrolling element is, so that for an | |
402 // inertial scroll that shouldn't propagate, only the | |
403 // currently scrolling element responds. | |
404 DCHECK(m_previousGestureScrolledNode->isElementNode()); | |
405 scrollState->setCurrentNativeScrollingElement(toElement(m_previo usGestureScrolledNode.get())); | |
406 } | |
407 customizedScroll(*node, *scrollState); | |
408 m_previousGestureScrolledNode = scrollState->currentNativeScrollingE lement(); | |
409 m_deltaConsumedForScrollSequence = scrollState->deltaConsumedForScro llSequence(); | |
410 if (scrollState->deltaX() != delta.width() | |
411 || scrollState->deltaY() != delta.height()) { | |
412 setFrameWasScrolledByUser(); | |
413 return WebInputEventResult::HandledSystem; | |
414 } | |
415 } else { | |
416 Node* stopNode = nullptr; | |
417 if (gestureEvent.preventPropagation()) | |
418 stopNode = m_previousGestureScrolledNode.get(); | |
419 | |
420 bool consumed = false; | |
421 ScrollResult result = physicalScroll( | |
422 granularity, | |
423 delta, | |
424 FloatPoint(gestureEvent.position()), | |
425 velocity, | |
426 node, | |
427 &stopNode, | |
428 &consumed); | |
429 | |
430 if (gestureEvent.preventPropagation()) | |
431 m_previousGestureScrolledNode = stopNode; | |
432 | |
433 if ((!stopNode || !isRootScroller(*stopNode)) && frameHost()) { | |
434 frameHost()->overscrollController().resetAccumulated( | |
435 result.didScrollX, result.didScrollY); | |
436 } | |
437 | |
438 if (consumed) | |
439 return WebInputEventResult::HandledSystem; | |
440 } | |
441 } | |
442 | |
443 return WebInputEventResult::NotHandled; | |
444 } | |
445 | |
446 WebInputEventResult ScrollManager::handleGestureScrollEnd(const PlatformGestureE vent& gestureEvent) | |
447 { | |
448 Node* node = m_scrollGestureHandlingNode; | |
449 | |
450 if (node) { | |
451 passScrollGestureEventToWidget(gestureEvent, node->layoutObject()); | |
452 if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) { | |
453 OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateDa ta()); | |
454 scrollStateData->is_ending = true; | |
455 scrollStateData->is_in_inertial_phase = gestureEvent.inertialPhase() == ScrollInertialPhaseMomentum; | |
456 scrollStateData->from_user_input = true; | |
457 scrollStateData->is_direct_manipulation = true; | |
458 scrollStateData->delta_consumed_for_scroll_sequence = m_deltaConsume dForScrollSequence; | |
459 ScrollState* scrollState = ScrollState::create(std::move(scrollState Data)); | |
460 customizedScroll(*node, *scrollState); | |
461 } | |
462 } | |
463 | |
464 clearGestureScrollState(); | |
465 return WebInputEventResult::NotHandled; | |
466 } | |
467 | |
468 FrameHost* ScrollManager::frameHost() const | |
469 { | |
470 if (!m_frame->page()) | |
471 return nullptr; | |
472 | |
473 return &m_frame->page()->frameHost(); | |
474 } | |
475 | |
476 WebInputEventResult ScrollManager::passScrollGestureEventToWidget(const Platform GestureEvent& gestureEvent, LayoutObject* layoutObject) | |
477 { | |
478 DCHECK(gestureEvent.isScrollEvent()); | |
479 | |
480 if (!m_lastGestureScrollOverWidget || !layoutObject || !layoutObject->isLayo utPart()) | |
481 return WebInputEventResult::NotHandled; | |
482 | |
483 Widget* widget = toLayoutPart(layoutObject)->widget(); | |
484 | |
485 if (!widget || !widget->isFrameView()) | |
486 return WebInputEventResult::NotHandled; | |
487 | |
488 return toFrameView(widget)->frame().eventHandler().handleGestureScrollEvent( gestureEvent); | |
489 } | |
490 | |
491 bool ScrollManager::isRootScroller(const Node& node) const | |
492 { | |
493 // The root scroller is the one Element on the page designated to perform | |
494 // "viewport actions" like top controls movement and overscroll glow. | |
495 if (!frameHost() || !frameHost()->rootScroller()) | |
496 return false; | |
497 | |
498 return frameHost()->rootScroller()->get() == &node; | |
499 } | |
500 | |
501 | |
502 WebInputEventResult ScrollManager::handleGestureScrollEvent(const PlatformGestur eEvent& gestureEvent) | |
503 { | |
504 Node* eventTarget = nullptr; | |
505 Scrollbar* scrollbar = nullptr; | |
506 if (gestureEvent.type() != PlatformEvent::GestureScrollBegin) { | |
507 scrollbar = m_scrollbarHandlingScrollGesture.get(); | |
508 eventTarget = m_scrollGestureHandlingNode.get(); | |
509 } | |
510 | |
511 if (!eventTarget) { | |
512 Document* document = m_frame->document(); | |
513 if (document->layoutViewItem().isNull()) | |
514 return WebInputEventResult::NotHandled; | |
515 | |
516 FrameView* view = m_frame->view(); | |
517 LayoutPoint viewPoint = view->rootFrameToContents(gestureEvent.position( )); | |
518 HitTestRequest request(HitTestRequest::ReadOnly); | |
519 HitTestResult result(request, viewPoint); | |
520 document->layoutViewItem().hitTest(result); | |
521 | |
522 eventTarget = result.innerNode(); | |
523 | |
524 m_lastGestureScrollOverWidget = result.isOverWidget(); | |
525 m_scrollGestureHandlingNode = eventTarget; | |
526 m_previousGestureScrolledNode = nullptr; | |
527 | |
528 if (!scrollbar) | |
529 scrollbar = result.scrollbar(); | |
530 } | |
531 | |
532 if (scrollbar) { | |
533 bool shouldUpdateCapture = false; | |
534 if (scrollbar->gestureEvent(gestureEvent, &shouldUpdateCapture)) { | |
535 if (shouldUpdateCapture) | |
536 m_scrollbarHandlingScrollGesture = scrollbar; | |
537 return WebInputEventResult::HandledSuppressed; | |
538 } | |
539 m_scrollbarHandlingScrollGesture = nullptr; | |
540 } | |
541 | |
542 if (eventTarget) { | |
543 if (handleScrollGestureOnResizer(eventTarget, gestureEvent)) | |
544 return WebInputEventResult::HandledSuppressed; | |
545 | |
546 GestureEvent* gestureDomEvent = GestureEvent::create(eventTarget->docume nt().domWindow(), gestureEvent); | |
547 if (gestureDomEvent) { | |
548 DispatchEventResult gestureDomEventResult = eventTarget->dispatchEve nt(gestureDomEvent); | |
549 if (gestureDomEventResult != DispatchEventResult::NotCanceled) { | |
550 DCHECK(gestureDomEventResult != DispatchEventResult::CanceledByE ventHandler); | |
551 return EventHandler::toWebInputEventResult(gestureDomEventResult ); | |
552 } | |
553 } | |
554 } | |
555 | |
556 switch (gestureEvent.type()) { | |
557 case PlatformEvent::GestureScrollBegin: | |
558 return handleGestureScrollBegin(gestureEvent); | |
559 case PlatformEvent::GestureScrollUpdate: | |
560 return handleGestureScrollUpdate(gestureEvent); | |
561 case PlatformEvent::GestureScrollEnd: | |
562 return handleGestureScrollEnd(gestureEvent); | |
563 case PlatformEvent::GestureFlingStart: | |
564 case PlatformEvent::GesturePinchBegin: | |
565 case PlatformEvent::GesturePinchEnd: | |
566 case PlatformEvent::GesturePinchUpdate: | |
567 return WebInputEventResult::NotHandled; | |
568 default: | |
569 NOTREACHED(); | |
570 return WebInputEventResult::NotHandled; | |
571 } | |
572 } | |
573 | |
574 bool ScrollManager::isScrollbarHandlingGestures() const | |
575 { | |
576 return m_scrollbarHandlingScrollGesture.get(); | |
577 } | |
578 | |
579 bool ScrollManager::handleScrollGestureOnResizer(Node* eventTarget, const Platfo rmGestureEvent& gestureEvent) | |
580 { | |
581 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) { | |
582 PaintLayer* layer = eventTarget->layoutObject() ? eventTarget->layoutObj ect()->enclosingLayer() : nullptr; | |
583 IntPoint p = m_frame->view()->rootFrameToContents(gestureEvent.position( )); | |
584 if (layer && layer->getScrollableArea() && layer->getScrollableArea()->i sPointInResizeControl(p, ResizerForTouch)) { | |
585 m_resizeScrollableArea = layer->getScrollableArea(); | |
586 m_resizeScrollableArea->setInResizeMode(true); | |
587 m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offset FromResizeCorner(p)); | |
588 return true; | |
589 } | |
590 } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate) { | |
591 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) { | |
592 m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorne r); | |
593 return true; | |
594 } | |
595 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) { | |
596 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) { | |
597 m_resizeScrollableArea->setInResizeMode(false); | |
598 m_resizeScrollableArea = nullptr; | |
599 return false; | |
600 } | |
601 } | |
602 | |
603 return false; | |
604 } | |
605 | |
606 bool ScrollManager::inResizeMode() const | |
607 { | |
608 return m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode(); | |
609 } | |
610 | |
611 void ScrollManager::resize(const PlatformEvent& evt) | |
612 { | |
613 m_resizeScrollableArea->resize(evt, m_offsetFromResizeCorner); | |
614 } | |
615 | |
616 void ScrollManager::clearResizeScrollableArea(bool shouldNotBeNull) | |
617 { | |
618 if (shouldNotBeNull) | |
619 DCHECK(m_resizeScrollableArea); | |
620 | |
621 if (m_resizeScrollableArea) | |
622 m_resizeScrollableArea->setInResizeMode(false); | |
623 m_resizeScrollableArea = nullptr; | |
624 } | |
625 | |
626 void ScrollManager::setResizeScrollableArea(PaintLayer* layer, IntPoint p) | |
627 { | |
628 m_resizeScrollableArea = layer->getScrollableArea(); | |
629 m_resizeScrollableArea->setInResizeMode(true); | |
630 m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offsetFromResi zeCorner(p)); | |
631 } | |
632 | |
633 bool ScrollManager::canHandleGestureEvent(const GestureEventWithHitTestResults& targetedEvent) | |
634 { | |
635 Scrollbar* scrollbar = targetedEvent.hitTestResult().scrollbar(); | |
636 | |
637 if (scrollbar) { | |
638 bool shouldUpdateCapture = false; | |
639 if (scrollbar->gestureEvent(targetedEvent.event(), &shouldUpdateCapture) ) { | |
640 if (shouldUpdateCapture) | |
641 m_scrollbarHandlingScrollGesture = scrollbar; | |
642 return true; | |
643 } | |
644 } | |
645 return false; | |
646 } | |
647 | |
648 DEFINE_TRACE(ScrollManager) | |
649 { | |
650 visitor->trace(m_frame); | |
651 visitor->trace(m_scrollGestureHandlingNode); | |
652 visitor->trace(m_previousGestureScrolledNode); | |
653 visitor->trace(m_scrollbarHandlingScrollGesture); | |
654 visitor->trace(m_resizeScrollableArea); | |
655 } | |
656 | |
657 } // namespace blink | |
OLD | NEW |