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