Changeset 163975 in webkit
- Timestamp:
- Feb 12, 2014 12:40:17 PM (10 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r163974 r163975 1 2014-02-12 Brent Fulgham <bfulgham@apple.com> 2 3 Wheel events don't latch to inner scrollable elements 4 https://bugs.webkit.org/show_bug.cgi?id=128225 5 <rdar://problem/12183688> 6 7 Reviewed by Simon Fraser 8 9 * WebCore.exp.in: Add declarations for new scrolledToTop, scrolledToBottom, scrolledToLeft, and scrolledToRight. 10 * page/EventHandler.cpp: 11 (WebCore::EventHandler::EventHandler): 12 (WebCore::EventHandler::clear): 13 (WebCore::findScrollableContainer): New helper function to locate first node 14 in enclosing region of document that is capable of handling mouse wheel events. 15 (WebCore::isAtMaxDominantScrollPosition): Predicate to check if the scrollable 16 area is at the limit we will hit based on scroll direction. 17 (WebCore::EventHandler::handleWheelEvent): Identify the case where we have hit 18 the end of a scroll, and treat that as a valid 'handled' case. If the scroll event 19 is just starting, treat end-of-scroll as unhandled so the parent element can 20 handle things. 21 * page/EventHandler.h: 22 * page/scrolling/ScrollingTree.cpp: 23 (WebCore::ScrollingTree::shouldHandleWheelEventSynchronously): Use new methods 24 on the PlatformWheelEvent class. 25 (WebCore::ScrollingTree::setOrClearLatchedNode): Ditto 26 * platform/PlatformWheelEvent.h: 27 (WebCore::PlatformWheelEvent::shouldConsiderLatching): Moved implementation from ScrollingTree. 28 (WebCore::PlatformWheelEvent::shouldClearLatchedNode): Ditto 29 * platform/ScrollableArea.cpp: 30 (WebCore::ScrollableArea::scrolledToTop): Added 31 (WebCore::ScrollableArea::scrolledToBottom):Added 32 (WebCore::ScrollableArea::scrolledToLeft): Added 33 (WebCore::ScrollableArea::scrolledToRight): Added 34 * platform/ScrollableArea.h: 35 * rendering/RenderListBox.cpp: 36 (WebCore::RenderListBox::scrolledToTop): Added 37 (WebCore::RenderListBox::scrolledToBottom): Added 38 (WebCore::RenderListBox::scrolledToLeft): Added 39 (WebCore::RenderListBox::scrolledToRight): Added 40 * rendering/RenderListBox.h: Changed to public inheritance of ScrollableArea to 41 allow generic use of this type in scroll wheel logic. 42 1 43 2014-02-12 Brendan Long <b.long@cablelabs.com> 2 44 -
trunk/Source/WebCore/WebCore.exp.in
r163920 r163975 397 397 __ZN7WebCore14ScrollableArea15didAddScrollbarEPNS_9ScrollbarENS_20ScrollbarOrientationE 398 398 __ZN7WebCore14ScrollableArea16handleWheelEventERKNS_18PlatformWheelEventE 399 __ZNK7WebCore14ScrollableArea16scrolledToBottomEv 400 __ZNK7WebCore14ScrollableArea14scrolledToLeftEv 401 __ZNK7WebCore14ScrollableArea13scrolledToTopEv 402 __ZNK7WebCore14ScrollableArea15scrolledToRightEv 399 403 __ZN7WebCore14ScrollableArea17willEndLiveResizeEv 400 404 __ZN7WebCore14ScrollableArea19invalidateScrollbarEPNS_9ScrollbarERKNS_7IntRectE -
trunk/Source/WebCore/page/EventHandler.cpp
r163725 r163975 1 1 /* 2 * Copyright (C) 2006 , 2007, 2008, 2009, 2010, 2011, 2013Apple Inc. All rights reserved.2 * Copyright (C) 2006-2014 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 4 4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) … … 73 73 #include "RenderFrameSet.h" 74 74 #include "RenderLayer.h" 75 #include "RenderListBox.h" 75 76 #include "RenderTextControlSingleLine.h" 76 77 #include "RenderView.h" … … 354 355 , m_mouseDownView(nil) 355 356 , m_sendingEventToSubview(false) 357 , m_startedGestureAtScrollLimit(false) 356 358 #if !PLATFORM(IOS) 357 359 , m_activationEventNumber(-1) … … 433 435 m_capturingMouseEventsElement = nullptr; 434 436 m_latchedWheelEventElement = nullptr; 437 #if PLATFORM(COCOA) 438 m_latchedScrollableContainer = nullptr; 439 #endif 435 440 m_previousWheelScrolledElement = nullptr; 436 441 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) … … 2443 2448 #endif 2444 2449 2450 #if !PLATFORM(MAC) 2451 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, Element*&, ContainerNode*&, ScrollableArea*&, bool&) 2452 { 2453 } 2454 2455 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& event) 2456 { 2457 m_recentWheelEventDeltaTracker->recordWheelEventDelta(event); 2458 } 2459 2460 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, ContainerNode*, ScrollableArea*) 2461 { 2462 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed. 2463 FrameView* view = m_frame.view(); 2464 2465 bool didHandleEvent = view ? view->wheelEvent(event) : false; 2466 m_isHandlingWheelEvent = false; 2467 return didHandleEvent; 2468 } 2469 #endif 2470 2445 2471 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e) 2446 2472 { … … 2464 2490 document->renderView()->hitTest(request, result); 2465 2491 2466 bool useLatchedWheelEventElement = e.useLatchedEventElement();2467 2468 2492 Element* element = result.innerElement(); 2469 2493 2470 bool isOverWidget; 2471 if (useLatchedWheelEventElement) { 2472 if (!m_latchedWheelEventElement) { 2473 m_latchedWheelEventElement = element; 2474 m_widgetIsLatched = result.isOverWidget(); 2475 } else 2476 element = m_latchedWheelEventElement.get(); 2477 2478 isOverWidget = m_widgetIsLatched; 2479 } else { 2480 if (m_latchedWheelEventElement) 2481 m_latchedWheelEventElement = nullptr; 2482 if (m_previousWheelScrolledElement) 2483 m_previousWheelScrolledElement = nullptr; 2484 2485 isOverWidget = result.isOverWidget(); 2486 } 2494 bool isOverWidget = result.isOverWidget(); 2495 2496 ContainerNode* scrollableContainer = nullptr; 2497 ScrollableArea* scrollableArea = nullptr; 2498 platformPrepareForWheelEvents(e, result, element, scrollableContainer, scrollableArea, isOverWidget); 2487 2499 2488 2500 // FIXME: It should not be necessary to do this mutation here. … … 2493 2505 event = event.copyTurningVerticalTicksIntoHorizontalTicks(); 2494 2506 2495 #if PLATFORM(COCOA) 2496 switch (event.phase()) { 2497 case PlatformWheelEventPhaseBegan: 2498 m_recentWheelEventDeltaTracker->beginTrackingDeltas(); 2499 break; 2500 case PlatformWheelEventPhaseEnded: 2501 m_recentWheelEventDeltaTracker->endTrackingDeltas(); 2502 break; 2503 default: 2504 break; 2505 } 2506 #endif 2507 2508 m_recentWheelEventDeltaTracker->recordWheelEventDelta(event); 2507 platformRecordWheelEvent(event); 2509 2508 2510 2509 if (element) { … … 2526 2525 } 2527 2526 2528 2529 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed. 2530 view = m_frame.view(); 2531 bool didHandleEvent = view ? view->wheelEvent(event) : false; 2532 m_isHandlingWheelEvent = false; 2533 return didHandleEvent; 2527 return platformCompleteWheelEvent(e, scrollableContainer, scrollableArea); 2534 2528 } 2535 2529 -
trunk/Source/WebCore/page/EventHandler.h
r163725 r163975 1 1 /* 2 * Copyright (C) 2006 , 2007, 2009, 2010, 2011, 2013Apple Inc. All rights reserved.2 * Copyright (C) 2006-2014 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 70 70 class AutoscrollController; 71 71 class Clipboard; 72 class ContainerNode; 72 73 class Document; 73 74 class Element; … … 91 92 class RenderLayer; 92 93 class RenderWidget; 94 class ScrollableArea; 93 95 class SVGElementInstance; 94 96 class Scrollbar; … … 197 199 void defaultWheelEventHandler(Node*, WheelEvent*); 198 200 bool handlePasteGlobalSelection(const PlatformMouseEvent&); 201 202 void platformPrepareForWheelEvents(const PlatformWheelEvent& wheelEvent, const HitTestResult& result, Element*& wheelEventTarget, ContainerNode*& scrollableContainer, ScrollableArea*& scrollableArea, bool& isOverWidget); 203 void platformRecordWheelEvent(const PlatformWheelEvent&); 204 bool platformCompleteWheelEvent(const PlatformWheelEvent&, ContainerNode* scrollableContainer, ScrollableArea* scrollableArea); 199 205 200 206 #if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS) … … 521 527 #if PLATFORM(COCOA) 522 528 NSView *m_mouseDownView; 529 RefPtr<ContainerNode> m_latchedScrollableContainer; 523 530 bool m_sendingEventToSubview; 531 bool m_startedGestureAtScrollLimit; 524 532 #if !PLATFORM(IOS) 525 533 int m_activationEventNumber; -
trunk/Source/WebCore/page/mac/EventHandlerMac.mm
r163406 r163975 1 1 /* 2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.2 * Copyright (C) 2006, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 39 39 #include "FrameView.h" 40 40 #include "KeyboardEvent.h" 41 #include "MainFrame.h" 41 42 #include "MouseEventWithHitTestResults.h" 42 43 #include "NotImplemented.h" … … 44 45 #include "Pasteboard.h" 45 46 #include "PlatformEventFactoryMac.h" 47 #include "RenderLayer.h" 48 #include "RenderListBox.h" 46 49 #include "RenderWidget.h" 47 50 #include "RuntimeApplicationChecks.h" 51 #include "ScrollableArea.h" 48 52 #include "Scrollbar.h" 49 53 #include "Settings.h" 54 #include "ShadowRoot.h" 50 55 #include "WebCoreSystemInterface.h" 51 56 #include <wtf/MainThread.h> … … 735 740 } 736 741 737 } 742 static ContainerNode* findEnclosingScrollableContainer(ContainerNode& node) 743 { 744 // Find the first node with a valid scrollable area starting with the current 745 // node and traversing its parents (or shadow hosts). 746 for (ContainerNode* candidate = &node; candidate; candidate = candidate->parentOrShadowHostNode()) { 747 RenderBox* box = candidate->renderBox(); 748 if (box && box->canBeScrolledAndHasScrollableArea()) 749 return candidate; 750 } 751 752 return nullptr; 753 } 754 755 static bool scrolledToEdgeInDominantDirection(const ScrollableArea& area, DominantScrollGestureDirection direction, float deltaX, float deltaY) 756 { 757 if (DominantScrollGestureDirection::Horizontal == direction && deltaX) { 758 if (deltaX < 0) 759 return area.scrolledToRight(); 760 761 return area.scrolledToLeft(); 762 } 763 764 if (deltaY < 0) 765 return area.scrolledToBottom(); 766 767 return area.scrolledToTop(); 768 } 769 770 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent& wheelEvent, const HitTestResult& result, Element*& wheelEventTarget, ContainerNode*& scrollableContainer, ScrollableArea*& scrollableArea, bool& isOverWidget) 771 { 772 FrameView* view = m_frame.view(); 773 774 scrollableContainer = nullptr; 775 scrollableArea = nullptr; 776 if (!view || !view->frame().isMainFrame()) { 777 scrollableContainer = wheelEventTarget; 778 scrollableArea = view; 779 } else { 780 scrollableContainer = findEnclosingScrollableContainer(*wheelEventTarget); 781 if (scrollableContainer) { 782 if (RenderBox* box = scrollableContainer->renderBox()) { 783 if (box->isListBox()) 784 scrollableArea = toRenderListBox(box); 785 else 786 scrollableArea = box->layer(); 787 } 788 } 789 } 790 791 if (wheelEvent.shouldConsiderLatching()) { 792 if (scrollableArea) 793 m_startedGestureAtScrollLimit = scrolledToEdgeInDominantDirection(*scrollableArea, m_recentWheelEventDeltaTracker->dominantScrollGestureDirection(), wheelEvent.deltaX(), wheelEvent.deltaY()); 794 else 795 m_startedGestureAtScrollLimit = false; 796 m_latchedWheelEventElement = wheelEventTarget; 797 m_latchedScrollableContainer = scrollableContainer; 798 m_widgetIsLatched = result.isOverWidget(); 799 isOverWidget = m_widgetIsLatched; 800 m_recentWheelEventDeltaTracker->beginTrackingDeltas(); 801 } else if (wheelEvent.shouldResetLatching()) { 802 m_latchedWheelEventElement = nullptr; 803 m_latchedScrollableContainer = nullptr; 804 m_widgetIsLatched = false; 805 m_previousWheelScrolledElement = nullptr; 806 m_recentWheelEventDeltaTracker->endTrackingDeltas(); 807 } 808 809 if (!wheelEvent.shouldResetLatching() && m_latchedWheelEventElement) { 810 wheelEventTarget = m_latchedWheelEventElement.get(); 811 isOverWidget = m_widgetIsLatched; 812 } 813 } 814 815 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& wheelEvent) 816 { 817 switch (wheelEvent.phase()) { 818 case PlatformWheelEventPhaseBegan: 819 m_recentWheelEventDeltaTracker->beginTrackingDeltas(); 820 break; 821 case PlatformWheelEventPhaseEnded: 822 m_recentWheelEventDeltaTracker->endTrackingDeltas(); 823 break; 824 default: 825 break; 826 } 827 828 m_recentWheelEventDeltaTracker->recordWheelEventDelta(wheelEvent); 829 } 830 831 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& wheelEvent, ContainerNode* scrollableContainer, ScrollableArea* scrollableArea) 832 { 833 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed. 834 FrameView* view = m_frame.view(); 835 836 if (wheelEvent.useLatchedEventElement() && m_latchedScrollableContainer) { 837 if (!view || !view->frame().isMainFrame()) { 838 bool didHandleWheelEvent = view && view->wheelEvent(wheelEvent); 839 if (!didHandleWheelEvent && scrollableContainer == m_latchedScrollableContainer) { 840 // If we are just starting a scroll event, and have nowhere left to scroll, allow 841 // the enclosing frame to handle the scroll. 842 didHandleWheelEvent = !m_startedGestureAtScrollLimit; 843 } 844 m_isHandlingWheelEvent = false; 845 return didHandleWheelEvent; 846 } 847 848 if (scrollableArea && !m_startedGestureAtScrollLimit && scrollableContainer == m_latchedScrollableContainer) { 849 m_isHandlingWheelEvent = false; 850 return true; 851 } 852 } 853 854 bool didHandleEvent = view ? view->wheelEvent(wheelEvent) : false; 855 m_isHandlingWheelEvent = false; 856 return didHandleEvent; 857 } 858 859 } -
trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp
r163516 r163975 59 59 } 60 60 61 static bool shouldConsiderLatching(const PlatformWheelEvent& wheelEvent)62 {63 return wheelEvent.phase() == PlatformWheelEventPhaseBegan64 || wheelEvent.phase() == PlatformWheelEventPhaseMayBegin;65 }66 67 static bool eventShouldClearLatchedNode(const PlatformWheelEvent& wheelEvent)68 {69 if (wheelEvent.phase() == PlatformWheelEventPhaseCancelled)70 return true;71 72 if (wheelEvent.phase() == PlatformWheelEventPhaseNone && wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded)73 return true;74 75 return false;76 }77 78 61 bool ScrollingTree::shouldHandleWheelEventSynchronously(const PlatformWheelEvent& wheelEvent) 79 62 { … … 84 67 return true; 85 68 86 bool shouldSetLatch = shouldConsiderLatching(wheelEvent);69 bool shouldSetLatch = wheelEvent.shouldConsiderLatching(); 87 70 88 71 if (hasLatchedNode() && !shouldSetLatch) … … 104 87 void ScrollingTree::setOrClearLatchedNode(const PlatformWheelEvent& wheelEvent, ScrollingNodeID nodeID) 105 88 { 106 if ( shouldConsiderLatching(wheelEvent))89 if (wheelEvent.shouldConsiderLatching()) 107 90 setLatchedNode(nodeID); 108 else if ( eventShouldClearLatchedNode(wheelEvent))91 else if (wheelEvent.shouldResetLatching()) 109 92 clearLatchedNode(); 110 93 } -
trunk/Source/WebCore/platform/PlatformWheelEvent.h
r163657 r163975 168 168 || m_momentumPhase == PlatformWheelEventPhaseBegan || m_momentumPhase == PlatformWheelEventPhaseChanged; 169 169 } 170 bool shouldConsiderLatching() const 171 { 172 return m_phase == PlatformWheelEventPhaseBegan || m_phase == PlatformWheelEventPhaseMayBegin; 173 } 174 bool shouldResetLatching() const 175 { 176 if (m_phase == PlatformWheelEventPhaseCancelled || m_phase == PlatformWheelEventPhaseMayBegin) 177 return true; 178 179 if (m_phase == PlatformWheelEventPhaseNone && m_momentumPhase == PlatformWheelEventPhaseEnded) 180 return true; 181 182 return false; 183 } 170 184 #else 171 185 bool useLatchedEventElement() const { return false; } -
trunk/Source/WebCore/platform/ScrollableArea.cpp
r163079 r163975 1 1 /* 2 2 * Copyright (c) 2010, Google Inc. All rights reserved. 3 * Copyright (C) 2008, 2011 Apple Inc. All Rights Reserved.3 * Copyright (C) 2008, 2011, 2014 Apple Inc. All Rights Reserved. 4 4 * 5 5 * Redistribution and use in source and binary forms, with or without … … 423 423 } 424 424 425 bool ScrollableArea::scrolledToTop() const 426 { 427 return scrollPosition().y() <= minimumScrollPosition().y(); 428 } 429 430 bool ScrollableArea::scrolledToBottom() const 431 { 432 return scrollPosition().y() >= maximumScrollPosition().y(); 433 } 434 435 bool ScrollableArea::scrolledToLeft() const 436 { 437 return scrollPosition().x() <= minimumScrollPosition().x(); 438 } 439 440 bool ScrollableArea::scrolledToRight() const 441 { 442 return scrollPosition().x() >= maximumScrollPosition().x(); 443 } 444 425 445 IntSize ScrollableArea::totalContentsSize() const 426 446 { -
trunk/Source/WebCore/platform/ScrollableArea.h
r163079 r163975 1 1 /* 2 * Copyright (C) 2008, 2011 Apple Inc. All Rights Reserved.2 * Copyright (C) 2008, 2011, 2014 Apple Inc. All Rights Reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 150 150 virtual IntPoint minimumScrollPosition() const; 151 151 virtual IntPoint maximumScrollPosition() const; 152 virtual bool scrolledToTop() const; 153 virtual bool scrolledToBottom() const; 154 virtual bool scrolledToLeft() const; 155 virtual bool scrolledToRight() const; 152 156 153 157 enum VisibleContentRectIncludesScrollbars { ExcludeScrollbars, IncludeScrollbars }; -
trunk/Source/WebCore/rendering/RenderListBox.cpp
r163560 r163975 1 1 /* 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.2 * Copyright (C) 2006, 2007, 2008, 2011, 2014 Apple Inc. All rights reserved. 3 3 * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 4 4 * … … 832 832 } 833 833 834 bool RenderListBox::scrolledToTop() const 835 { 836 Scrollbar* vbar = verticalScrollbar(); 837 if (!vbar) 838 return true; 839 840 return vbar->value() <= 0; 841 } 842 843 bool RenderListBox::scrolledToBottom() const 844 { 845 Scrollbar* vbar = verticalScrollbar(); 846 if (!vbar) 847 return true; 848 849 return vbar->value() >= vbar->maximum(); 850 } 851 852 bool RenderListBox::scrolledToLeft() const 853 { 854 // We do not scroll horizontally in a select element, so always report 855 // that we are at the full extent of the scroll. 856 return true; 857 } 858 859 bool RenderListBox::scrolledToRight() const 860 { 861 // We do not scroll horizontally in a select element, so always report 862 // that we are at the full extent of the scroll. 863 return true; 864 } 865 834 866 } // namespace WebCore -
trunk/Source/WebCore/rendering/RenderListBox.h
r163560 r163975 2 2 * This file is part of the select element renderer in WebCore. 3 3 * 4 * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.4 * Copyright (C) 2006, 2007, 2009, 2014 Apple Inc. All rights reserved. 5 5 * 6 6 * Redistribution and use in source and binary forms, with or without … … 39 39 class HTMLSelectElement; 40 40 41 class RenderListBox final : public RenderBlockFlow, p rivateScrollableArea {41 class RenderListBox final : public RenderBlockFlow, public ScrollableArea { 42 42 public: 43 43 RenderListBox(HTMLSelectElement&, PassRef<RenderStyle>); … … 59 59 60 60 int size() const; 61 62 virtual bool scrolledToTop() const override; 63 virtual bool scrolledToBottom() const override; 64 virtual bool scrolledToLeft() const override; 65 virtual bool scrolledToRight() const override; 61 66 62 67 private:
Note: See TracChangeset
for help on using the changeset viewer.