Skip to content
Permalink
Browse files
Dragging over an element with scrollbars should scroll the element wh…
…en dragging near edges

https://bugs.webkit.org/show_bug.cgi?id=39725

Reviewed by Hajime Morita.

Source/WebCore:

This patch introduces auto scrolling functionality during drag-and-drop
when drop source is near edge of scrollable element.

When drop source is inside 20px of scrollable element more than 200ms,
scrollable element is automatically scrolled every 50ms toward drop
source position, e.g. vertically scroll up when drop source is in top
edge.

Test: fast/events/drag-and-drop-autoscroll.html

* page/AutoscrollController.cpp:
(WebCore::AutoscrollController::AutoscrollController): Changed to initialize m_dragAndDropAutoscrollStartTime.
(WebCore::AutoscrollController::updateDragAndDrop): Added for start/stop autoscroll during drag-and-drop.
(WebCore::AutoscrollController::autoscrollTimerFired): Changed to add autoscroll for drag-and-drop, and to pass last know position to RenderBox::autoscroll().
* page/AutoscrollController.h:
(AutoscrollController): Changed to add updateDragAndDrop() and m_dragAndDropAutoscrollReferencePosition and m_dragAndDropAutoscrollStartTime.
* page/EventHandler.cpp:
(WebCore::EventHandler::updateDragAndDrop): Changed to call AutoscrollController::updateDragAndDrop().
* rendering/RenderBox.cpp:
(WebCore::RenderBox::autoscroll): Changed for new parameter position.
(WebCore::RenderBox::calculateAutoscrollDirection): Added for autoscroll.
* rendering/RenderBox.h:
(RenderBox):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::autoscroll):  Changed for new parameter position and move updateSelectionForMouseDrag() to AutoscrollController.
* rendering/RenderLayer.h:
(RenderLayer):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::autoscroll):  Changed for new parameter position.
* rendering/RenderListBox.h:
(RenderListBox):
* rendering/RenderTextControlSingleLine.cpp:
(WebCore::RenderTextControlSingleLine::autoscroll):  Changed for new parameter position.
* rendering/RenderTextControlSingleLine.h:
(RenderTextControlSingleLine):

Source/WebKit/chromium:

This patch removes DragScrollTimer used for automatic scrolling of main
frame drag-and-drop which is now implemented in EventHandler.

Another patch will remove DragScrollTimer.{cpp,h} and update GYP files to
make patch size small.

No tests. Existing test covers this change.

* src/WebViewImpl.cpp:
(WebKit::WebViewImpl::WebViewImpl): Changed to remove m_dragScrollTimer.
(WebKit::WebViewImpl::dragSourceEndedAt): ditto
(WebKit::WebViewImpl::dragSourceMovedTo): ditto
(WebKit::WebViewImpl::dragTargetDrop): ditto
(WebKit::WebViewImpl::dragTargetDragEnterOrOver): ditto
* src/WebViewImpl.h:
(WebKit): Chagned to remove DragScrollTimer.

LayoutTests:

This patch adds new test for autoscroll during drag-and-drop.

* fast/events/drag-and-drop-autoscroll-expected.txt: Added.
* fast/events/drag-and-drop-autoscroll.html: Added.


Canonical link: https://commits.webkit.org/124503@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@139044 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
yosinch committed Jan 8, 2013
1 parent bf1ba18 commit 08595286e44e9e866eb52d0a3e3ed0bed33c467c
Showing 18 changed files with 286 additions and 31 deletions.
@@ -1,3 +1,15 @@
2013-01-08 Yoshifumi Inoue <yosin@chromium.org>

Dragging over an element with scrollbars should scroll the element when dragging near edges
https://bugs.webkit.org/show_bug.cgi?id=39725

Reviewed by Hajime Morita.

This patch adds new test for autoscroll during drag-and-drop.

* fast/events/drag-and-drop-autoscroll-expected.txt: Added.
* fast/events/drag-and-drop-autoscroll.html: Added.

2013-01-08 Yuki Sekiguchi <yuki.sekiguchi@access-company.com>

Float block's logical top margin is illegal in vertical writing mode.
@@ -0,0 +1,8 @@
Check autoscroll by drag-and-drop

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


PASS scrollable.scrollTop > 0
For manual testing, drag and drop "Drop Me" to "Scrollable" area.

@@ -0,0 +1,101 @@
<html>
<head>
<style type="text/css">
#draggable {
padding: 5pt;
border: 3px solid #00cc00;
background: #00cccc;
width: 80px;
cursor: hand;
}

#scrollable {
height: 200px;
overflow: auto;
border: solid 3px #cc0000;
}
</style>
<script>
function $(id) { return document.getElementById(id); }

function finishTest() {
eventSender.mouseUp();
$('container').innerHTML = '';
window.testRunner.notifyDone();
}

function testIt() {
var draggable = $('draggable');
var scrollable = $('scrollable');

if (!window.eventSender)
return;

eventSender.dragMode = false;

// Grab draggable
eventSender.mouseMoveTo(draggable.offsetLeft + 5, draggable.offsetTop + 5);
eventSender.mouseDown();

// Move mouse to autoscroll border belt.
eventSender.mouseMoveTo(scrollable.offsetLeft + 5, scrollable.offsetTop + scrollable.offsetHeight - 10);

var retryCount = 0;

function checkScrolled()
{
if (scrollable.scrollTop > 0) {
testPassed('scrollable.scrollTop > 0');
finishTest();
return;
}

++retryCount;
if (retryCount > 10) {
testFailed('No autoscroll');
finishTest();
return;
}

// Autoscroll is occurred evey 0.05 sec.
window.setTimeout(checkScrolled, 50);
}

checkScrolled();
}

function setUpTest()
{
var scrollable = $('scrollable');
for (var i = 0; i < 100; ++i) {
var line = document.createElement('div');
line.innerHTML = "line " + i;
scrollable.appendChild(line);
}

if (!window.eventSender) {
console.log('Please run within DumpRenderTree');
return;
}

window.jsTestIsAsync = true;
window.setTimeout(testIt, 0);
}
</script>
</head>
<body>
For manual testing, drag and drop "Drop Me" to "Scrollable" area.
<div id="container">
<div id="draggable" draggable="true">Drop Me</div>
Scrollable
<div id="scrollable">
</div>
</div>
<script src="../js/resources/js-test-pre.js"></script>
<script>
description('Check autoscroll by drag-and-drop');
setUpTest();
</script>
<script src="../js/resources/js-test-post.js"></script>
</body>
</html>
@@ -1,3 +1,46 @@
2013-01-08 Yoshifumi Inoue <yosin@chromium.org>

Dragging over an element with scrollbars should scroll the element when dragging near edges
https://bugs.webkit.org/show_bug.cgi?id=39725

Reviewed by Hajime Morita.

This patch introduces auto scrolling functionality during drag-and-drop
when drop source is near edge of scrollable element.

When drop source is inside 20px of scrollable element more than 200ms,
scrollable element is automatically scrolled every 50ms toward drop
source position, e.g. vertically scroll up when drop source is in top
edge.

Test: fast/events/drag-and-drop-autoscroll.html

* page/AutoscrollController.cpp:
(WebCore::AutoscrollController::AutoscrollController): Changed to initialize m_dragAndDropAutoscrollStartTime.
(WebCore::AutoscrollController::updateDragAndDrop): Added for start/stop autoscroll during drag-and-drop.
(WebCore::AutoscrollController::autoscrollTimerFired): Changed to add autoscroll for drag-and-drop, and to pass last know position to RenderBox::autoscroll().
* page/AutoscrollController.h:
(AutoscrollController): Changed to add updateDragAndDrop() and m_dragAndDropAutoscrollReferencePosition and m_dragAndDropAutoscrollStartTime.
* page/EventHandler.cpp:
(WebCore::EventHandler::updateDragAndDrop): Changed to call AutoscrollController::updateDragAndDrop().
* rendering/RenderBox.cpp:
(WebCore::RenderBox::autoscroll): Changed for new parameter position.
(WebCore::RenderBox::calculateAutoscrollDirection): Added for autoscroll.
* rendering/RenderBox.h:
(RenderBox):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::autoscroll): Changed for new parameter position and move updateSelectionForMouseDrag() to AutoscrollController.
* rendering/RenderLayer.h:
(RenderLayer):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::autoscroll): Changed for new parameter position.
* rendering/RenderListBox.h:
(RenderListBox):
* rendering/RenderTextControlSingleLine.cpp:
(WebCore::RenderTextControlSingleLine::autoscroll): Changed for new parameter position.
* rendering/RenderTextControlSingleLine.h:
(RenderTextControlSingleLine):

2013-01-08 Jochen Eisinger <jochen@chromium.org>

REGRESSION(r139036): 'WebCore::DateTimeSymbolicFieldElement::isInRange' hides overloaded virtual function
@@ -35,9 +35,13 @@
#include "Page.h"
#include "RenderBox.h"
#include "ScrollView.h"
#include <wtf/CurrentTime.h>

namespace WebCore {

// Delay time in second for start autoscroll if pointer is in border edge of scrollable element.
static double autoscrollDelay = 0.2;

// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
static const double autoscrollInterval = 0.05;

@@ -53,6 +57,7 @@ AutoscrollController::AutoscrollController()
: m_autoscrollTimer(this, &AutoscrollController::autoscrollTimerFired)
, m_autoscrollRenderer(0)
, m_autoscrollType(NoAutoscroll)
, m_dragAndDropAutoscrollStartTime(0)
#if ENABLE(PAN_SCROLLING)
, m_panScrollButtonPressed(false)
, m_springLoadedPanScrollInProgress(false)
@@ -144,6 +149,38 @@ void AutoscrollController::updateAutoscrollRenderer()
m_autoscrollRenderer = renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
}

void AutoscrollController::updateDragAndDrop(Node* dropTargetNode, const IntPoint& eventPosition, double eventTime)
{
if (!dropTargetNode) {
stopAutoscrollTimer();
return;
}

RenderBox* scrollable = RenderBox::findAutoscrollable(dropTargetNode->renderer());
if (!scrollable) {
stopAutoscrollTimer();
return;
}

IntSize offset = scrollable->calculateAutoscrollDirection(eventPosition);
if (offset.isZero()) {
stopAutoscrollTimer();
return;
}

m_dragAndDropAutoscrollReferencePosition = eventPosition + offset;

if (m_autoscrollType == NoAutoscroll) {
m_autoscrollType = AutoscrollForDragAndDrop;
m_autoscrollRenderer = scrollable;
m_dragAndDropAutoscrollStartTime = eventTime;
startAutoscrollTimer();
} else if (m_autoscrollRenderer != scrollable) {
m_dragAndDropAutoscrollStartTime = eventTime;
m_autoscrollRenderer = scrollable;
}
}

#if ENABLE(PAN_SCROLLING)
void AutoscrollController::didPanScrollStart()
{
@@ -200,13 +237,20 @@ void AutoscrollController::autoscrollTimerFired(Timer<AutoscrollController>*)

Frame* frame = m_autoscrollRenderer->frame();
switch (m_autoscrollType) {
case AutoscrollForSelection:
if (!frame->eventHandler()->mousePressed()) {
case AutoscrollForDragAndDrop:
if (WTF::currentTime() - m_dragAndDropAutoscrollStartTime > autoscrollDelay)
m_autoscrollRenderer->autoscroll(m_dragAndDropAutoscrollReferencePosition);
break;
case AutoscrollForSelection: {
EventHandler* eventHandler = frame->eventHandler();
if (!eventHandler->mousePressed()) {
stopAutoscrollTimer();
return;
}
m_autoscrollRenderer->autoscroll();
eventHandler->updateSelectionForMouseDrag();
m_autoscrollRenderer->autoscroll(eventHandler->lastKnownMousePosition());
break;
}
case NoAutoscroll:
break;
#if ENABLE(PAN_SCROLLING)
@@ -34,12 +34,14 @@ namespace WebCore {
class EventHandler;
class Frame;
class FrameView;
class Node;
class PlatformMouseEvent;
class RenderBox;
class RenderObject;

enum AutoscrollType {
NoAutoscroll,
AutoscrollForDragAndDrop,
AutoscrollForSelection,
#if ENABLE(PAN_SCROLLING)
AutoscrollForPan,
@@ -56,6 +58,7 @@ class AutoscrollController {
void startAutoscrollForSelection(RenderObject*);
void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false);
void updateAutoscrollRenderer();
void updateDragAndDrop(Node* targetNode, const IntPoint& eventPosition, double eventTime);
#if ENABLE(PAN_SCROLLING)
void didPanScrollStart();
void didPanScrollStop();
@@ -74,6 +77,8 @@ class AutoscrollController {
Timer<AutoscrollController> m_autoscrollTimer;
RenderBox* m_autoscrollRenderer;
AutoscrollType m_autoscrollType;
IntPoint m_dragAndDropAutoscrollReferencePosition;
double m_dragAndDropAutoscrollStartTime;
#if ENABLE(PAN_SCROLLING)
IntPoint m_panScrollStartPos;
bool m_panScrollButtonPressed;
@@ -1963,6 +1963,8 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard*
if (newTarget && newTarget->isTextNode())
newTarget = newTarget->parentNode();

m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());

if (m_dragTarget != newTarget) {
// FIXME: this ordering was explicitly chosen to match WinIE. However,
// it is sometimes incorrect when dragging within subframes, as seen with
@@ -81,6 +81,11 @@ static OverrideSizeMap* gOverrideWidthMap = 0;
static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;


// Size of border belt for autoscroll. When mouse pointer in border belt,
// autoscroll is started.
static const int autoscrollBeltSize = 20;

bool RenderBox::s_hadOverflowClip = false;

RenderBox::RenderBox(Node* node)
@@ -680,10 +685,10 @@ bool RenderBox::usesCompositedScrolling() const
return hasOverflowClip() && hasLayer() && layer()->usesCompositedScrolling();
}

void RenderBox::autoscroll()
void RenderBox::autoscroll(const IntPoint& position)
{
if (layer())
layer()->autoscroll();
layer()->autoscroll(position);
}

// There are two kinds of renderer that can autoscroll.
@@ -707,6 +712,33 @@ bool RenderBox::canAutoscroll() const
return page && page->mainFrame() == frame;
}

// If specified point is in border belt, returned offset denotes direction of
// scrolling.
IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
{
if (!frame())
return IntSize();

FrameView* frameView = frame()->view();
if (!frameView)
return IntSize();

IntSize offset;
IntPoint point = frameView->windowToContents(windowPoint);
IntRect box(absoluteBoundingBoxRect());

if (point.x() < box.x() + autoscrollBeltSize)
point.move(-autoscrollBeltSize, 0);
else if (point.x() > box.maxX() - autoscrollBeltSize)
point.move(autoscrollBeltSize, 0);

if (point.y() < box.y() + autoscrollBeltSize)
point.move(0, -autoscrollBeltSize);
else if (point.y() > box.maxY() - autoscrollBeltSize)
point.move(0, autoscrollBeltSize);
return frameView->contentsToWindow(point) - windowPoint;
}

RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
{
while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) {
@@ -443,8 +443,9 @@ class RenderBox : public RenderBoxModelObject {
virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
bool canBeScrolledAndHasScrollableArea() const;
virtual bool canBeProgramaticallyScrolled() const;
virtual void autoscroll();
virtual void autoscroll(const IntPoint&);
bool canAutoscroll() const;
IntSize calculateAutoscrollDirection(const IntPoint& windowPoint) const;
static RenderBox* findAutoscrollable(RenderObject*);
virtual void stopAutoscroll() { }
virtual void panScroll(const IntPoint&);
@@ -2291,7 +2291,7 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const Lay
return LayoutRect(LayoutPoint(x, y), visibleRect.size());
}

void RenderLayer::autoscroll()
void RenderLayer::autoscroll(const IntPoint& position)
{
Frame* frame = renderer()->frame();
if (!frame)
@@ -2301,11 +2301,7 @@ void RenderLayer::autoscroll()
if (!frameView)
return;

#if ENABLE(DRAG_SUPPORT)
frame->eventHandler()->updateSelectionForMouseDrag();
#endif

IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->lastKnownMousePosition());
IntPoint currentDocumentPosition = frameView->windowToContents(position);
scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
}

0 comments on commit 0859528

Please sign in to comment.