Autoscrolling from a drag selection does not work in full screen, or when the
authorbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Mar 2016 22:01:30 +0000 (22:01 +0000)
committerbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Mar 2016 22:01:30 +0000 (22:01 +0000)
window is against the screen edge
https://bugs.webkit.org/show_bug.cgi?id=155858
-and corresponding-
rdar://problem/9338465

Reviewed by Simon Fraser.

WebKit2 has always had this bug. Since WebKit1 scrolling in handled largely
by AppKit, we did not have this bug because AppKit adjusts the autoscroll
amount whenever the window is at the edge of the screen and the user is
trying to autoscroll in that direction. This patch employs the same technique
in WebCore.

Instead of using EventHandler::lastKnownMousePosition() as the autoscroll
amount, use EventHandler::effectiveMousePositionForSelectionAutoscroll()
which will adjust the lastKnownMousePosition if the window is at the edge of
the screen.
* page/AutoscrollController.cpp:
(WebCore::AutoscrollController::autoscrollTimerFired):

For most ports, effectiveMousePositionForSelectionAutoscroll() will just
return m_lastKnownMousePosition. We override it in EventHandlerMac to return
an adjusted amount.
* page/EventHandler.cpp:
(WebCore::EventHandler::effectiveMousePositionForSelectionAutoscroll):
* page/EventHandler.h:
* page/mac/EventHandlerMac.mm:
(WebCore::autoscrollAdjustmentFactorForScreenBoundaries):
(WebCore::EventHandler::effectiveMousePositionForSelectionAutoscroll):

Make screenForDisplayID available as on PlatformScreen.h instead of just
being a static function in the implementation file.
* platform/PlatformScreen.h:
* platform/mac/PlatformScreenMac.mm:
(WebCore::screenForDisplayID):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198692 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/page/AutoscrollController.cpp
Source/WebCore/page/EventHandler.cpp
Source/WebCore/page/EventHandler.h
Source/WebCore/page/mac/EventHandlerMac.mm
Source/WebCore/platform/PlatformScreen.h
Source/WebCore/platform/mac/PlatformScreenMac.mm

index 6c0963d..747452e 100644 (file)
@@ -1,3 +1,42 @@
+2016-03-25  Beth Dakin  <bdakin@apple.com>
+
+        Autoscrolling from a drag selection does not work in full screen, or when the 
+        window is against the screen edge
+        https://bugs.webkit.org/show_bug.cgi?id=155858
+        -and corresponding-
+        rdar://problem/9338465
+
+        Reviewed by Simon Fraser.
+
+        WebKit2 has always had this bug. Since WebKit1 scrolling in handled largely 
+        by AppKit, we did not have this bug because AppKit adjusts the autoscroll 
+        amount whenever the window is at the edge of the screen and the user is 
+        trying to autoscroll in that direction. This patch employs the same technique 
+        in WebCore.
+
+        Instead of using EventHandler::lastKnownMousePosition() as the autoscroll 
+        amount, use EventHandler::effectiveMousePositionForSelectionAutoscroll() 
+        which will adjust the lastKnownMousePosition if the window is at the edge of 
+        the screen.
+        * page/AutoscrollController.cpp:
+        (WebCore::AutoscrollController::autoscrollTimerFired):
+
+        For most ports, effectiveMousePositionForSelectionAutoscroll() will just 
+        return m_lastKnownMousePosition. We override it in EventHandlerMac to return 
+        an adjusted amount.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::effectiveMousePositionForSelectionAutoscroll):
+        * page/EventHandler.h:
+        * page/mac/EventHandlerMac.mm:
+        (WebCore::autoscrollAdjustmentFactorForScreenBoundaries):
+        (WebCore::EventHandler::effectiveMousePositionForSelectionAutoscroll):
+
+        Make screenForDisplayID available as on PlatformScreen.h instead of just 
+        being a static function in the implementation file.
+        * platform/PlatformScreen.h:
+        * platform/mac/PlatformScreenMac.mm:
+        (WebCore::screenForDisplayID):
+
 2016-03-25  Brady Eidson  <beidson@apple.com>
 
         Soften push/replaceState frequency restrictions.
index b589670..a7c7a58 100644 (file)
@@ -252,7 +252,7 @@ void AutoscrollController::autoscrollTimerFired()
 #if ENABLE(DRAG_SUPPORT)
         frame.eventHandler().updateSelectionForMouseDrag();
 #endif
-        m_autoscrollRenderer->autoscroll(frame.eventHandler().lastKnownMousePosition());
+        m_autoscrollRenderer->autoscroll(frame.eventHandler().effectiveMousePositionForSelectionAutoscroll());
         break;
     }
     case NoAutoscroll:
index 802bb43..1ce12a3 100644 (file)
@@ -2586,6 +2586,11 @@ void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent&, Scrolla
 {
 }
 
+IntPoint EventHandler::effectiveMousePositionForSelectionAutoscroll() const
+{
+    return m_lastKnownMousePosition;
+}
+
 #endif
 
 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
index 2435da0..dca51f8 100644 (file)
@@ -179,6 +179,8 @@ public:
     IntPoint lastKnownMouseGlobalPosition() const { return m_lastKnownMouseGlobalPosition; }
     Cursor currentMouseCursor() const { return m_currentMouseCursor; }
 
+    IntPoint effectiveMousePositionForSelectionAutoscroll() const;
+
     static Frame* subframeForTargetNode(Node*);
     static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
 
index 5419195..50895da 100644 (file)
@@ -1106,4 +1106,61 @@ VisibleSelection EventHandler::selectClosestWordFromHitTestResultBasedOnLookup(c
     return VisibleSelection();
 }
 
+static IntSize autoscrollAdjustmentFactorForScreenBoundaries(const IntPoint& screenPoint, const FloatRect& screenRect)
+{
+    // If the window is at the edge of the screen, and the mouse position is also at that edge of the screen,
+    // we need to adjust the autoscroll amount in order for the user to be able to autoscroll in that direction.
+    // We can pretend that the mouse position is slightly beyond the edge of the screen, and then autoscrolling
+    // will occur as excpected. This function figures out just how much to adjust the autoscroll amount by
+    // in order to get autoscrolling to feel natural in this situation.
+
+    IntSize adjustmentFactor;
+    
+#define EDGE_DISTANCE_THRESHOLD 50
+#define PIXELS_MULTIPLIER 20
+
+    float screenLeftEdge = screenRect.x();
+    float insetScreenLeftEdge = screenLeftEdge + EDGE_DISTANCE_THRESHOLD;
+    float screenRightEdge = screenRect.maxX();
+    float insetScreenRightEdge = screenRightEdge - EDGE_DISTANCE_THRESHOLD;
+    if (screenPoint.x() >= screenLeftEdge && screenPoint.x() < insetScreenLeftEdge) {
+        float distanceFromEdge = screenPoint.x() - screenLeftEdge - EDGE_DISTANCE_THRESHOLD;
+        if (distanceFromEdge < 0)
+            adjustmentFactor.setWidth((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
+    } else if (screenPoint.x() >= insetScreenRightEdge && screenPoint.x() < screenRightEdge) {
+        float distanceFromEdge = EDGE_DISTANCE_THRESHOLD - (screenRightEdge - screenPoint.x());
+        if (distanceFromEdge > 0)
+            adjustmentFactor.setWidth((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
+    }
+
+    float screenTopEdge = screenRect.y();
+    float insetScreenTopEdge = screenTopEdge + EDGE_DISTANCE_THRESHOLD;
+    float screenBottomEdge = screenRect.maxY();
+    float insetScreenBottomEdge = screenBottomEdge - EDGE_DISTANCE_THRESHOLD;
+
+    if (screenPoint.y() >= screenTopEdge && screenPoint.y() < insetScreenTopEdge) {
+        float distanceFromEdge = screenPoint.y() - screenTopEdge - EDGE_DISTANCE_THRESHOLD;
+        if (distanceFromEdge < 0)
+            adjustmentFactor.setHeight((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
+    } else if (screenPoint.y() >= insetScreenBottomEdge && screenPoint.y() < screenBottomEdge) {
+        float distanceFromEdge = EDGE_DISTANCE_THRESHOLD - (screenBottomEdge - screenPoint.y());
+        if (distanceFromEdge > 0)
+            adjustmentFactor.setHeight((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
+    }
+
+    return adjustmentFactor;
+}
+
+IntPoint EventHandler::effectiveMousePositionForSelectionAutoscroll() const
+{
+    Page* page = m_frame.page();
+    if (!page)
+        return m_lastKnownMousePosition;
+
+    NSScreen *screen = screenForDisplayID(page->chrome().displayID());
+    IntSize autoscrollAdjustmentFactor = autoscrollAdjustmentFactorForScreenBoundaries(m_lastKnownMouseGlobalPosition, toUserSpace(screen.frame, nil));
+
+    return m_lastKnownMousePosition + autoscrollAdjustmentFactor;
+}
+
 }
index f1f5dd8..42b0f6b 100644 (file)
@@ -65,6 +65,7 @@ namespace WebCore {
 
 #if PLATFORM(MAC)
     NSScreen *screenForWindow(NSWindow *);
+    NSScreen *screenForDisplayID(PlatformDisplayID);
 
     WEBCORE_EXPORT FloatRect toUserSpace(const NSRect&, NSWindow *destination);
     WEBCORE_EXPORT NSRect toDeviceSpace(const FloatRect&, NSWindow *source);
index d87bec2..f72f700 100644 (file)
@@ -42,15 +42,6 @@ static PlatformDisplayID displayIDFromScreen(NSScreen *screen)
     return (PlatformDisplayID)[[[screen deviceDescription] objectForKey:@"NSScreenNumber"] intValue];
 }
 
-static NSScreen *screenForDisplayID(PlatformDisplayID displayID)
-{
-    for (NSScreen *screen in [NSScreen screens]) {
-        if (displayIDFromScreen(screen) == displayID)
-            return screen;
-    }
-    return nil;
-}
-
 // These functions scale between screen and page coordinates because JavaScript/DOM operations
 // assume that the screen and the page share the same coordinate system.
 
@@ -135,6 +126,15 @@ NSScreen *screenForWindow(NSWindow *window)
     return nil;
 }
 
+NSScreen *screenForDisplayID(PlatformDisplayID displayID)
+{
+    for (NSScreen *screen in [NSScreen screens]) {
+        if (displayIDFromScreen(screen) == displayID)
+            return screen;
+    }
+    return nil;
+}
+
 FloatRect toUserSpace(const NSRect& rect, NSWindow *destination)
 {
     FloatRect userRect = rect;