Changeset 122970 in webkit


Ignore:
Timestamp:
Jul 18, 2012 7:47:40 AM (12 years ago)
Author:
commit-queue@webkit.org
Message:

TOUCH_ADJUSTMENT is too aggressive when snapping to large elements.
https://bugs.webkit.org/show_bug.cgi?id=91262

Patch by Kevin Ellis <kevers@chromium.org> on 2012-07-18
Reviewed by Antonio Gomes.

Source/WebCore:

Constrains the extent to which the touch point can be adjusted when
generating synthetic mouse events when TOUCH_ADJUSTEMNT is enabled.
Previously, the target position snapped to the center of the target
element, which can be far removed from the touch position when tapping
on or near a large element. The refined strategy is to leave the
adjusted position unchanged if tapping within the element or to snap
to the center of the overlap region if the touch point lies outside the
bounds of the element, but the touch area and element bounds overlap.
For non-rectilineary bounds, a point lying outside the element boundary
is pulled towards the center of the element, by an amount limited by
the radius of the touch area.

Tests: touchadjustment/big-div.html

touchadjustment/rotated-node.html

  • page/TouchAdjustment.cpp:

(WebCore::TouchAdjustment::contentsToWindow):
(TouchAdjustment):
(WebCore::TouchAdjustment::snapTo):
(WebCore::TouchAdjustment::findNodeWithLowestDistanceMetric):

LayoutTests:

Adding a test case to ensure that the adjusted touch position is
within the bounds of the target element and the touch area.
Previously, the target position snapped to the center of the target
element, which can be far removed from the touch area.

The second test is for non-rectilinear elements, and verifies that
the touch area must overlap the true bounds of the element for an
adjustment to occur.

  • touchadjustment/big-div-expected.txt: Added.
  • touchadjustment/big-div.html: Added.
  • touchadjustment/rotated-node-expected.txt: Added.
  • touchadjustment/rotated-node.html: Added.
Location:
trunk
Files:
4 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r122968 r122970  
     12012-07-18  Kevin Ellis  <kevers@chromium.org>
     2
     3        TOUCH_ADJUSTMENT is too aggressive when snapping to large elements.
     4        https://bugs.webkit.org/show_bug.cgi?id=91262
     5
     6        Reviewed by Antonio Gomes.
     7
     8        Adding a test case to ensure that the adjusted touch position is
     9        within the bounds of the target element and the touch area.
     10        Previously, the target position snapped to the center of the target
     11        element, which can be far removed from the touch area.
     12
     13        The second test is for non-rectilinear elements, and verifies that
     14        the touch area must overlap the true bounds of the element for an
     15        adjustment to occur.
     16
     17        * touchadjustment/big-div-expected.txt: Added.
     18        * touchadjustment/big-div.html: Added.
     19        * touchadjustment/rotated-node-expected.txt: Added.
     20        * touchadjustment/rotated-node.html: Added.
     21
    1222012-07-18  Vsevolod Vlasov  <vsevik@chromium.org>
    223
  • trunk/Source/WebCore/ChangeLog

    r122966 r122970  
     12012-07-18  Kevin Ellis  <kevers@chromium.org>
     2
     3        TOUCH_ADJUSTMENT is too aggressive when snapping to large elements.
     4        https://bugs.webkit.org/show_bug.cgi?id=91262
     5
     6        Reviewed by Antonio Gomes.
     7
     8        Constrains the extent to which the touch point can be adjusted when
     9        generating synthetic mouse events when TOUCH_ADJUSTEMNT is enabled.
     10        Previously, the target position snapped to the center of the target
     11        element, which can be far removed from the touch position when tapping
     12        on or near a large element.  The refined strategy is to leave the
     13        adjusted position unchanged if tapping within the element or to snap
     14        to the center of the overlap region if the touch point lies outside the
     15        bounds of the element, but the touch area and element bounds overlap.
     16        For non-rectilineary bounds, a point lying outside the element boundary
     17        is pulled towards the center of the element, by an amount limited by
     18        the radius of the touch area.
     19
     20        Tests: touchadjustment/big-div.html
     21               touchadjustment/rotated-node.html
     22
     23        * page/TouchAdjustment.cpp:
     24        (WebCore::TouchAdjustment::contentsToWindow):
     25        (TouchAdjustment):
     26        (WebCore::TouchAdjustment::snapTo):
     27        (WebCore::TouchAdjustment::findNodeWithLowestDistanceMetric):
     28
    1292012-07-18  Sergey Rogulenko  <rogulenko@google.com>
    230
  • trunk/Source/WebCore/page/TouchAdjustment.cpp

    r117128 r122970  
    240240}
    241241
     242FloatPoint contentsToWindow(FrameView *view, FloatPoint pt)
     243{
     244    int x = static_cast<int>(pt.x() + 0.5f);
     245    int y = static_cast<int>(pt.y() + 0.5f);
     246    IntPoint adjusted = view->contentsToWindow(IntPoint(x, y));
     247    return FloatPoint(adjusted.x(), adjusted.y());
     248}
     249
     250bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const IntRect& touchArea, IntPoint& adjustedPoint)
     251{
     252    FrameView* view = geom.node()->document()->view();
     253    FloatQuad quad = geom.quad();
     254
     255    if (quad.isRectilinear()) {
     256        IntRect contentBounds = geom.boundingBox();
     257        // Convert from frame coordinates to window coordinates.
     258        IntRect bounds = view->contentsToWindow(contentBounds);
     259        if (bounds.contains(touchPoint)) {
     260            adjustedPoint = touchPoint;
     261            return true;
     262        }
     263        if (bounds.intersects(touchArea)) {
     264            bounds.intersect(touchArea);
     265            adjustedPoint = bounds.center();
     266            return true;
     267        }
     268        return false;
     269    }
     270
     271    // Non-rectilinear element.
     272    // Convert quad from content to window coordinates.
     273    FloatPoint p1 = contentsToWindow(view, quad.p1());
     274    FloatPoint p2 = contentsToWindow(view, quad.p2());
     275    FloatPoint p3 = contentsToWindow(view, quad.p3());
     276    FloatPoint p4 = contentsToWindow(view, quad.p4());
     277    quad = FloatQuad(p1, p2, p3, p4);
     278
     279    if (quad.containsPoint(touchPoint)) {
     280        adjustedPoint = touchPoint;
     281        return true;
     282    }
     283
     284    // Pull point towards the center of the element.
     285    float cx = 0.25 * (p1.x() + p2.x() + p3.x() + p4.x());
     286    float cy = 0.25 * (p1.y() + p2.y() + p3.y() + p4.y());
     287    FloatPoint center = FloatPoint(cx, cy);
     288
     289    FloatSize pullDirection = center - touchPoint;
     290    float distanceToCenter = pullDirection.diagonalLength();
     291
     292    // Use distance from center to corner of touch area to limit adjustment distance.
     293    float dx = 0.5f * touchArea.width();
     294    float dy = 0.5f * touchArea.height();
     295    float touchRadius = sqrt(dx * dx + dy * dy);
     296
     297    float scaleFactor = touchRadius / distanceToCenter;
     298    if (scaleFactor > 1)
     299        scaleFactor = 1;
     300    pullDirection.scale(scaleFactor);
     301
     302    int x = static_cast<int>(touchPoint.x() + pullDirection.width());
     303    int y = static_cast<int>(touchPoint.y() + pullDirection.height());
     304    IntPoint point(x, y);
     305
     306    if (quad.containsPoint(point)) {
     307        adjustedPoint = point;
     308        return true;
     309    }
     310    return false;
     311}
    242312
    243313// A generic function for finding the target node with the lowest distance metric. A distance metric here is the result
     
    250320    SubtargetGeometryList::const_iterator it = subtargets.begin();
    251321    const SubtargetGeometryList::const_iterator end = subtargets.end();
     322    IntPoint adjustedPoint;
    252323    for (; it != end; ++it) {
    253324        Node* node = it->node();
    254325        float distanceMetric = distanceFunction(touchHotspot, touchArea, *it);
    255326        if (distanceMetric < bestDistanceMetric) {
    256             targetPoint = roundedIntPoint(it->quad().center());
    257             targetArea = it->boundingBox();
    258             targetNode = node;
    259             bestDistanceMetric = distanceMetric;
     327            if (snapTo(*it, touchHotspot, touchArea, adjustedPoint)) {
     328                targetPoint = adjustedPoint;
     329                targetArea = it->boundingBox();
     330                targetNode = node;
     331                bestDistanceMetric = distanceMetric;
     332            }
    260333        } else if (distanceMetric == bestDistanceMetric) {
    261334            // Try to always return the inner-most element.
    262             if (node->isDescendantOf(targetNode)) {
     335            if (node->isDescendantOf(targetNode) && snapTo(*it, touchHotspot, touchArea, adjustedPoint)) {
     336                targetPoint = adjustedPoint;
    263337                targetNode = node;
    264338                targetArea = it->boundingBox();
     
    268342    if (targetNode) {
    269343        targetArea = targetNode->document()->view()->contentsToWindow(targetArea);
    270         targetPoint = targetNode->document()->view()->contentsToWindow(targetPoint);
    271     }
    272 
     344    }
    273345    return (targetNode);
    274346}
Note: See TracChangeset for help on using the changeset viewer.