⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 126945 in webkit


Ignore:
Timestamp:
Aug 28, 2012, 6:05:41 PM (14 years ago)
Author:
leandrogracia@chromium.org
Message:

Content detection should not disrupt the page behaviour
https://bugs.webkit.org/show_bug.cgi?id=94727

Reviewed by Adam Barth.

Source/WebCore:

Tested by WebViewTest::DetectContentAroundPosition.

  • dom/Node.cpp:

(WebCore::Node::willRespondToTouchEvents): checks if a node listens to touch events. Very similar to willRespondToMouseClickEvents.
(WebCore):

  • dom/Node.h:

(Node):

Source/WebKit/chromium:

Triggers content detection in the embedder on tap gestures and
add checks for the appropriate event listeners in order to prevent
triggering content detection when it would disrupt the page's behaviour.

  • src/WebViewImpl.cpp:

(WebKit::WebViewImpl::handleGestureEvent):
(WebKit::WebViewImpl::detectContentOnTouch):

  • tests/WebViewTest.cpp:
  • tests/data/content_listeners.html: Added.
Location:
trunk/Source
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r126943 r126945  
     12012-08-28  Leandro Gracia Gil  <leandrogracia@chromium.org>
     2
     3        Content detection should not disrupt the page behaviour
     4        https://bugs.webkit.org/show_bug.cgi?id=94727
     5
     6        Reviewed by Adam Barth.
     7
     8        Tested by WebViewTest::DetectContentAroundPosition.
     9
     10        * dom/Node.cpp:
     11        (WebCore::Node::willRespondToTouchEvents): checks if a node listens to touch events. Very similar to willRespondToMouseClickEvents.
     12        (WebCore):
     13        * dom/Node.h:
     14        (Node):
     15
    1162012-08-28  Simon Fraser  <simon.fraser@apple.com>
    217
  • trunk/Source/WebCore/dom/Node.cpp

    r126926 r126945  
    27662766}
    27672767
     2768bool Node::willRespondToTouchEvents()
     2769{
     2770#if ENABLE(TOUCH_EVENTS)
     2771    if (disabled())
     2772        return false;
     2773    return hasEventListeners(eventNames().touchstartEvent) || hasEventListeners(eventNames().touchmoveEvent) || hasEventListeners(eventNames().touchcancelEvent) || hasEventListeners(eventNames().touchendEvent);
     2774#else
     2775    return false;
     2776#endif
     2777}
     2778
    27682779#if ENABLE(MICRODATA)
    27692780DOMSettableTokenList* Node::itemProp()
  • trunk/Source/WebCore/dom/Node.h

    r126816 r126945  
    585585    virtual bool willRespondToMouseMoveEvents();
    586586    virtual bool willRespondToMouseClickEvents();
     587    virtual bool willRespondToTouchEvents();
    587588
    588589    PassRefPtr<Element> querySelector(const AtomicString& selectors, ExceptionCode&);
  • trunk/Source/WebKit/chromium/ChangeLog

    r126940 r126945  
     12012-08-28  Leandro Gracia Gil  <leandrogracia@chromium.org>
     2
     3        Content detection should not disrupt the page behaviour
     4        https://bugs.webkit.org/show_bug.cgi?id=94727
     5
     6        Reviewed by Adam Barth.
     7
     8        Triggers content detection in the embedder on tap gestures and
     9        add checks for the appropriate event listeners in order to prevent
     10        triggering content detection when it would disrupt the page's behaviour.
     11
     12        * src/WebViewImpl.cpp:
     13        (WebKit::WebViewImpl::handleGestureEvent):
     14        (WebKit::WebViewImpl::detectContentOnTouch):
     15        * tests/WebViewTest.cpp:
     16        * tests/data/content_listeners.html: Added.
     17
    1182012-08-28  Sheriff Bot  <webkit.review.bot@gmail.com>
    219
  • trunk/Source/WebKit/chromium/src/WebViewImpl.cpp

    r126940 r126945  
    688688    switch (event.type) {
    689689    case WebInputEvent::GestureFlingStart: {
     690        m_client->cancelScheduledContentIntents();
    690691        m_lastWheelPosition = WebPoint(event.x, event.y);
    691692        m_lastWheelGlobalPosition = WebPoint(event.globalX, event.globalY);
     
    703704        return false;
    704705    case WebInputEvent::GestureTap: {
     706        m_client->cancelScheduledContentIntents();
     707        if (detectContentOnTouch(WebPoint(event.x, event.y), event.type))
     708            return true;
     709
    705710        PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
    706711        RefPtr<WebCore::PopupContainer> selectPopup;
     
    723728            return false;
    724729
     730        m_client->cancelScheduledContentIntents();
     731        if (detectContentOnTouch(WebPoint(event.x, event.y), event.type))
     732            return true;
     733
    725734        m_page->contextMenuController()->clearContextMenu();
    726735        m_contextMenuAllowed = true;
     
    731740    }
    732741    case WebInputEvent::GestureTapDown: {
     742        m_client->cancelScheduledContentIntents();
    733743        // Queue a highlight animation, then hand off to regular handler.
    734744#if OS(LINUX)
     
    738748        return mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
    739749    }
     750    case WebInputEvent::GestureDoubleTap:
    740751    case WebInputEvent::GestureScrollBegin:
     752    case WebInputEvent::GesturePinchBegin:
     753        m_client->cancelScheduledContentIntents();
    741754    case WebInputEvent::GestureScrollEnd:
    742755    case WebInputEvent::GestureScrollUpdate:
    743     case WebInputEvent::GestureDoubleTap:
    744     case WebInputEvent::GesturePinchBegin:
    745756    case WebInputEvent::GesturePinchEnd:
    746757    case WebInputEvent::GesturePinchUpdate: {
     
    39914002        return false;
    39924003
    3993     // FIXME: Should we not detect content intents in nodes that have event listeners?
     4004    // Ignore when tapping on links or nodes listening to click events, unless the click event is on the
     4005    // body element, in which case it's unlikely that the original node itself was intended to be clickable.
     4006    for (; node && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) {
     4007        if (node->isLink() || (touchType != WebInputEvent::GestureLongPress
     4008                && (node->willRespondToTouchEvents() || node->willRespondToMouseClickEvents()))) {
     4009            return false;
     4010        }
     4011    }
    39944012
    39954013    WebContentDetectionResult content = m_client->detectContentAround(touchHit);
  • trunk/Source/WebKit/chromium/tests/WebViewTest.cpp

    r126200 r126945  
    3333
    3434#include "Document.h"
     35#include "Element.h"
    3536#include "FrameTestHelpers.h"
    3637#include "FrameView.h"
    3738#include "HTMLDocument.h"
    3839#include "URLTestHelpers.h"
     40#include "WebContentDetectionResult.h"
    3941#include "WebDocument.h"
     42#include "WebElement.h"
    4043#include "WebFrame.h"
    4144#include "WebFrameClient.h"
    4245#include "WebFrameImpl.h"
     46#include "WebInputEvent.h"
    4347#include "platform/WebSize.h"
    4448#include "WebViewClient.h"
     
    419423}
    420424
    421 }
     425class ContentDetectorClient : public WebViewClient {
     426public:
     427    ContentDetectorClient() { reset(); }
     428
     429    virtual WebContentDetectionResult detectContentAround(const WebHitTestResult& hitTest) OVERRIDE
     430    {
     431        m_contentDetectionRequested = true;
     432        return m_contentDetectionResult;
     433    }
     434
     435    virtual void scheduleContentIntent(const WebURL& url) OVERRIDE
     436    {
     437        m_scheduledIntentURL = url;
     438    }
     439
     440    virtual void cancelScheduledContentIntents() OVERRIDE
     441    {
     442        m_pendingIntentsCancelled = true;
     443    }
     444
     445    void reset()
     446    {
     447        m_contentDetectionRequested = false;
     448        m_pendingIntentsCancelled = false;
     449        m_scheduledIntentURL = WebURL();
     450        m_contentDetectionResult = WebContentDetectionResult();
     451    }
     452
     453    bool contentDetectionRequested() const { return m_contentDetectionRequested; }
     454    bool pendingIntentsCancelled() const { return m_pendingIntentsCancelled; }
     455    const WebURL& scheduledIntentURL() const { return m_scheduledIntentURL; }
     456    void setContentDetectionResult(const WebContentDetectionResult& result) { m_contentDetectionResult = result; }
     457
     458private:
     459    bool m_contentDetectionRequested;
     460    bool m_pendingIntentsCancelled;
     461    WebURL m_scheduledIntentURL;
     462    WebContentDetectionResult m_contentDetectionResult;
     463};
     464
     465static bool tapElementById(WebView* webView, WebInputEvent::Type type, const WebString& id)
     466{
     467    ASSERT(webView);
     468    RefPtr<WebCore::Element> element = static_cast<PassRefPtr<WebCore::Element> >(webView->mainFrame()->document().getElementById(id));
     469    if (!element)
     470        return false;
     471
     472    element->scrollIntoViewIfNeeded();
     473    WebCore::IntPoint center = element->screenRect().center();
     474
     475    WebGestureEvent event;
     476    event.type = type;
     477    event.x = center.x();
     478    event.y = center.y();
     479
     480    webView->handleInputEvent(event);
     481    webkit_support::RunAllPendingMessages();
     482    return true;
     483}
     484
     485TEST_F(WebViewTest, DetectContentAroundPosition)
     486{
     487    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("content_listeners.html"));
     488
     489    ContentDetectorClient client;
     490    WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "content_listeners.html", true, 0, &client);
     491    webView->resize(WebSize(500, 300));
     492    webView->layout();
     493    webkit_support::RunAllPendingMessages();
     494
     495    WebString clickListener = WebString::fromUTF8("clickListener");
     496    WebString touchstartListener = WebString::fromUTF8("touchstartListener");
     497    WebString mousedownListener = WebString::fromUTF8("mousedownListener");
     498    WebString noListener = WebString::fromUTF8("noListener");
     499    WebString link = WebString::fromUTF8("link");
     500
     501    // Ensure content detection is not requested for nodes listening to click,
     502    // mouse or touch events when we do simple taps.
     503    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, clickListener));
     504    EXPECT_FALSE(client.contentDetectionRequested());
     505    client.reset();
     506
     507    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, touchstartListener));
     508    EXPECT_FALSE(client.contentDetectionRequested());
     509    client.reset();
     510
     511    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, mousedownListener));
     512    EXPECT_FALSE(client.contentDetectionRequested());
     513    client.reset();
     514
     515    // Content detection should still work on click, mouse and touch event listeners for long taps
     516    // as long as we're not tapping on links.
     517    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, clickListener));
     518    EXPECT_TRUE(client.contentDetectionRequested());
     519    client.reset();
     520
     521    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, touchstartListener));
     522    EXPECT_TRUE(client.contentDetectionRequested());
     523    client.reset();
     524
     525    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, mousedownListener));
     526    EXPECT_TRUE(client.contentDetectionRequested());
     527    client.reset();
     528
     529    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, link));
     530    EXPECT_FALSE(client.contentDetectionRequested());
     531    client.reset();
     532
     533    // Content detection should work normally without these event listeners.
     534    // The click listener in the body should be ignored as a special case.
     535    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, noListener));
     536    EXPECT_TRUE(client.contentDetectionRequested());
     537    EXPECT_FALSE(client.scheduledIntentURL().isValid());
     538
     539    WebURL intentURL = toKURL(m_baseURL);
     540    client.setContentDetectionResult(WebContentDetectionResult(WebRange(), WebString(), intentURL));
     541    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, noListener));
     542    EXPECT_TRUE(client.scheduledIntentURL() == intentURL);
     543
     544    // Tapping elsewhere should cancel the scheduled intent.
     545    WebGestureEvent event;
     546    event.type = WebInputEvent::GestureTap;
     547    webView->handleInputEvent(event);
     548    webkit_support::RunAllPendingMessages();
     549    EXPECT_TRUE(client.pendingIntentsCancelled());
     550    webView->close();
     551}
     552
     553}
Note: See TracChangeset for help on using the changeset viewer.