Changeset 143727 in webkit


Ignore:
Timestamp:
Feb 22, 2013 6:46:35 AM (11 years ago)
Author:
allan.jensen@digia.com
Message:

Allow child-frame content in hit-tests.
https://bugs.webkit.org/show_bug.cgi?id=95204

Reviewed by Julien Chaffraix.

Source/WebCore:

Refactors how EventHandler::hitTestResultAtPoint handles child-frame content,
it is now handled by the hit test itself controlled by the AllowChildFrameContent
flag in HitTestRequest.

This means that area-based hit-tests can now return elements from all the child frames
they intersect instead of just the one frame containing the center point. The improved
results from area-based hit-tests will among other things also improve touch adjustment
near frame boundaries.

Tests: fast/dom/nodesFromRect/nodesFromRect-child-frame-content.html

  • page/EventHandler.cpp:

(WebCore::EventHandler::hitTestResultAtPoint):

Recursion into child-frames have been moved to RenderFrameBase::nodeAtPoint, so
now hitTestResultAtPoint just needs to set AllowChildFrameContent.

  • page/TouchAdjustment.cpp:

(WebCore::TouchAdjustment::parentShadowHostOrOwner):

New function to iterate up across frame boundaries.

(WebCore::TouchAdjustment::compileSubtargetList):

We need to iterate up across frame boundaries to avoid iframes competing with their
own content for touch adjustment.

  • rendering/HitTestRequest.h:

(WebCore::HitTestRequest::allowsChildFrameContent):
(WebCore::HitTestRequest::isChildFrameHitTest):

  • rendering/HitTestResult.cpp:

(WebCore::HitTestResult::HitTestResult):
(WebCore::HitTestResult::operator=):
(WebCore::HitTestResult::append):
(WebCore::HitTestResult::dictationAlternatives):

  • rendering/HitTestResult.h:

(WebCore::HitTestResult::pointInMainFrame):
(WebCore::HitTestResult::pointInInnerNodeFrame):
(HitTestResult):

m_hitTestLocation is now in main frame coordinates, which make m_pointInMainFrame
unnecessary, but requires the introduction of m_pointInInnerFrame, to remember
the coordinates of inner-node in its own frame.

  • rendering/RenderFrameBase.cpp:

(WebCore::RenderFrameBase::nodeAtPoint):

The recursion into child-frames is now handled here instead of in hitTestResultAtPoint, this
allows us to recurse into multiple frames, instead of just one.

  • rendering/RenderFrameBase.h:

(RenderFrameBase):

  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::hitTest):

RenderLayer should not lie about being hit if the request is child-frame request.

  • testing/Internals.cpp:

(WebCore::Internals::nodesFromRect):

  • testing/Internals.h:

(Internals):

  • testing/Internals.idl:

Extended so nodesFromRect with child-frame content can be tested.

LayoutTests:

A new tests for nodesFromRect that returns result from child frames.

  • fast/dom/nodesFromRect/nodesFromRect-child-frame-content-expected.txt: Added.
  • fast/dom/nodesFromRect/nodesFromRect-child-frame-content.html: Added.
  • fast/dom/nodesFromRect/nodesFromRect-continuation-crash.html:
  • fast/dom/nodesFromRect/resources/child-frame.html: Added.
  • fast/dom/nodesFromRect/resources/nodesFromRect.js:

(check):
(checkShadowContent):
(nodesFromRectAsString):

Location:
trunk
Files:
3 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r143718 r143727  
     12013-02-22  Allan Sandfeld Jensen  <allan.jensen@digia.com>
     2
     3        Allow child-frame content in hit-tests.
     4        https://bugs.webkit.org/show_bug.cgi?id=95204
     5
     6        Reviewed by Julien Chaffraix.
     7
     8        A new tests for nodesFromRect that returns result from child frames.
     9
     10        * fast/dom/nodesFromRect/nodesFromRect-child-frame-content-expected.txt: Added.
     11        * fast/dom/nodesFromRect/nodesFromRect-child-frame-content.html: Added.
     12        * fast/dom/nodesFromRect/nodesFromRect-continuation-crash.html:
     13        * fast/dom/nodesFromRect/resources/child-frame.html: Added.
     14        * fast/dom/nodesFromRect/resources/nodesFromRect.js:
     15        (check):
     16        (checkShadowContent):
     17        (nodesFromRectAsString):
     18
    1192013-02-22  Zan Dobersek  <zdobersek@igalia.com>
    220
  • trunk/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-continuation-crash.html

    r133330 r143727  
    88    if (!window.internals)
    99        alert("This test requires window.internals");
    10     var nodes = internals.nodesFromRect(document, 100, 100, 20, 20, 20, 20, false, false);
     10    var nodes = internals.nodesFromRect(document, 100, 100, 20, 20, 20, 20, false, false, false);
    1111    alert("PASS: This test did not trigger an ASSERT");
    1212};
  • trunk/LayoutTests/fast/dom/nodesFromRect/resources/nodesFromRect.js

    r135841 r143727  
    22 * Contributors:
    33 *     * Antonio Gomes <tonikitoo@webkit.org>
    4  **/
     4 *     * Allan Sandfeld Jensen <allan.jensen@digia.com>
     5**/
    56
    67function check(x, y, topPadding, rightPadding, bottomPadding, leftPadding, list, doc)
     
    1213    doc = document;
    1314
    14   var nodes = internals.nodesFromRect(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding, true /* ignoreClipping */, false /* allow shadow content */);
     15  var nodes = internals.nodesFromRect(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding, true /* ignoreClipping */, false /* allow shadow content */, false /* allow child-frame content */);
    1516  if (!nodes)
    1617    return;
     
    4647    doc = document;
    4748
    48   var nodes = internals.nodesFromRect(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding, true /* ignoreClipping */, true /* allowShadowContent */);
     49  var nodes = internals.nodesFromRect(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding, true /* ignoreClipping */, true /* allowShadowContent */, false /* allow child-frame content */);
    4950  if (!nodes)
    5051    return;
     
    9798{
    9899    var nodeString = "";
    99     var nodes = internals.nodesFromRect(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding, true /* ignoreClipping */, false /* allow shadow content */);
     100    var nodes = internals.nodesFromRect(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding, true /* ignoreClipping */, false /* allow shadow content */, true /* allow child-frame content */);
    100101    if (!nodes)
    101102        return nodeString;
     
    111112        } else if (nodes[i].nodeType == 3) {
    112113            nodeString += "'" + nodes[i].data + "'";
     114        } else if (nodes[i].nodeType == 9) {
     115            nodeString += "#document";
    113116        } else {
    114117            continue;
     
    120123    return nodeString;
    121124}
    122 
    123125
    124126function getCenterFor(element)
  • trunk/Source/WebCore/ChangeLog

    r143726 r143727  
     12013-02-22  Allan Sandfeld Jensen  <allan.jensen@digia.com>
     2
     3        Allow child-frame content in hit-tests.
     4        https://bugs.webkit.org/show_bug.cgi?id=95204
     5
     6        Reviewed by Julien Chaffraix.
     7
     8        Refactors how EventHandler::hitTestResultAtPoint handles child-frame content,
     9        it is now handled by the hit test itself controlled by the AllowChildFrameContent
     10        flag in HitTestRequest.
     11
     12        This means that area-based hit-tests can now return elements from all the child frames
     13        they intersect instead of just the one frame containing the center point. The improved
     14        results from area-based hit-tests will among other things also improve touch adjustment
     15        near frame boundaries.
     16
     17        Tests: fast/dom/nodesFromRect/nodesFromRect-child-frame-content.html
     18
     19        * page/EventHandler.cpp:
     20        (WebCore::EventHandler::hitTestResultAtPoint):
     21            Recursion into child-frames have been moved to RenderFrameBase::nodeAtPoint, so
     22            now hitTestResultAtPoint just needs to set AllowChildFrameContent.
     23        * page/TouchAdjustment.cpp:
     24        (WebCore::TouchAdjustment::parentShadowHostOrOwner):
     25            New function to iterate up across frame boundaries.
     26        (WebCore::TouchAdjustment::compileSubtargetList):
     27            We need to iterate up across frame boundaries to avoid iframes competing with their
     28            own content for touch adjustment.
     29        * rendering/HitTestRequest.h:
     30        (WebCore::HitTestRequest::allowsChildFrameContent):
     31        (WebCore::HitTestRequest::isChildFrameHitTest):
     32        * rendering/HitTestResult.cpp:
     33        (WebCore::HitTestResult::HitTestResult):
     34        (WebCore::HitTestResult::operator=):
     35        (WebCore::HitTestResult::append):
     36        (WebCore::HitTestResult::dictationAlternatives):
     37        * rendering/HitTestResult.h:
     38        (WebCore::HitTestResult::pointInMainFrame):
     39        (WebCore::HitTestResult::pointInInnerNodeFrame):
     40        (HitTestResult):
     41            m_hitTestLocation is now in main frame coordinates, which make m_pointInMainFrame
     42            unnecessary, but requires the introduction of m_pointInInnerFrame, to remember
     43            the coordinates of inner-node in its own frame.
     44        * rendering/RenderFrameBase.cpp:
     45        (WebCore::RenderFrameBase::nodeAtPoint):
     46            The recursion into child-frames is now handled here instead of in hitTestResultAtPoint, this
     47            allows us to recurse into multiple frames, instead of just one.
     48        * rendering/RenderFrameBase.h:
     49        (RenderFrameBase):
     50        * rendering/RenderLayer.cpp:
     51        (WebCore::RenderLayer::hitTest):
     52            RenderLayer should not lie about being hit if the request is child-frame request.
     53        * testing/Internals.cpp:
     54        (WebCore::Internals::nodesFromRect):
     55        * testing/Internals.h:
     56        (Internals):
     57        * testing/Internals.idl:
     58            Extended so nodesFromRect with child-frame content can be tested.
     59
    1602013-02-22  Andreas Kling  <akling@apple.com>
    261
  • trunk/Source/WebCore/page/EventHandler.cpp

    r143560 r143727  
    10271027        return result;
    10281028
    1029     HitTestRequest request(hitType);
     1029    // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
     1030    HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
    10301031    m_frame->contentRenderer()->hitTest(request, result);
    1031 
    1032     while (true) {
    1033         Node* n = result.innerNode();
    1034         if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
    1035             break;
    1036         RenderWidget* renderWidget = toRenderWidget(n->renderer());
    1037         Widget* widget = renderWidget->widget();
    1038         if (!widget || !widget->isFrameView())
    1039             break;
    1040         Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
    1041         if (!frame || !frame->contentRenderer())
    1042             break;
    1043         FrameView* view = static_cast<FrameView*>(widget);
    1044         LayoutPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
    1045             result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
    1046         HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width());
    1047         widgetHitTestResult.setPointInMainFrame(result.pointInMainFrame());
    1048         frame->contentRenderer()->hitTest(request, widgetHitTestResult);
    1049         result = widgetHitTestResult;
    1050 
    1051         if (request.allowsFrameScrollbars()) {
    1052             Scrollbar* eventScrollbar = view->scrollbarAtPoint(roundedIntPoint(point));
    1053             if (eventScrollbar)
    1054                 result.setScrollbar(eventScrollbar);
    1055         }
    1056     }
    10571032
    10581033    if (!request.allowsShadowContent())
  • trunk/Source/WebCore/page/TouchAdjustment.cpp

    r141524 r143727  
    2626#include "FloatQuad.h"
    2727#include "FrameView.h"
     28#include "HTMLFrameOwnerElement.h"
    2829#include "HTMLInputElement.h"
    2930#include "HTMLLabelElement.h"
     
    222223}
    223224
     225static inline Node* parentShadowHostOrOwner(const Node* node)
     226{
     227    if (Node* ancestor = node->parentOrShadowHostNode())
     228        return ancestor;
     229    if (node->isDocumentNode())
     230        return static_cast<const Document*>(node)->ownerElement();
     231    return 0;
     232}
     233
    224234// Compiles a list of subtargets of all the relevant target nodes.
    225235void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter, AppendSubtargetsForNode appendSubtargetsForNode)
     
    249259                respondingNode = visitedNode;
    250260                // Continue the iteration to collect the ancestors of the responder, which we will need later.
    251                 for (visitedNode = visitedNode->parentOrShadowHostNode(); visitedNode; visitedNode = visitedNode->parentOrShadowHostNode()) {
     261                for (visitedNode = parentShadowHostOrOwner(visitedNode); visitedNode; visitedNode = parentShadowHostOrOwner(visitedNode)) {
    252262                    HashSet<Node*>::AddResult addResult = ancestorsToRespondersSet.add(visitedNode);
    253263                    if (!addResult.isNewEntry)
  • trunk/Source/WebCore/rendering/HitTestRequest.h

    r142977 r143727  
    3737        TouchEvent = 1 << 7,
    3838        AllowShadowContent = 1 << 8,
    39         AllowFrameScrollbars = 1 << 9
     39        AllowFrameScrollbars = 1 << 9,
     40        AllowChildFrameContent = 1 << 10,
     41        ChildFrameHitTest = 1 << 11
    4042    };
    4143
     
    5759    bool allowsShadowContent() const { return m_requestType & AllowShadowContent; }
    5860    bool allowsFrameScrollbars() const { return m_requestType & AllowFrameScrollbars; }
     61    bool allowsChildFrameContent() const { return m_requestType & AllowChildFrameContent; }
     62    bool isChildFrameHitTest() const { return m_requestType & ChildFrameHitTest; }
    5963
    6064    // Convenience functions
  • trunk/Source/WebCore/rendering/HitTestResult.cpp

    r141524 r143727  
    200200HitTestResult::HitTestResult(const LayoutPoint& point)
    201201    : m_hitTestLocation(point)
    202     , m_pointInMainFrame(point)
     202    , m_pointInInnerNodeFrame(point)
    203203    , m_isOverWidget(false)
    204204{
     
    207207HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
    208208    : m_hitTestLocation(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding)
    209     , m_pointInMainFrame(centerPoint)
     209    , m_pointInInnerNodeFrame(centerPoint)
    210210    , m_isOverWidget(false)
    211211{
     
    214214HitTestResult::HitTestResult(const HitTestLocation& other)
    215215    : m_hitTestLocation(other)
    216     , m_pointInMainFrame(m_hitTestLocation.point())
     216    , m_pointInInnerNodeFrame(m_hitTestLocation.point())
    217217    , m_isOverWidget(false)
    218218{
     
    223223    , m_innerNode(other.innerNode())
    224224    , m_innerNonSharedNode(other.innerNonSharedNode())
    225     , m_pointInMainFrame(other.m_pointInMainFrame)
     225    , m_pointInInnerNodeFrame(other.m_pointInInnerNodeFrame)
    226226    , m_localPoint(other.localPoint())
    227227    , m_innerURLElement(other.URLElement())
     
    242242    m_innerNode = other.innerNode();
    243243    m_innerNonSharedNode = other.innerNonSharedNode();
    244     m_pointInMainFrame = other.m_pointInMainFrame;
     244    m_pointInInnerNodeFrame = other.m_pointInInnerNodeFrame;
    245245    m_localPoint = other.localPoint();
    246246    m_innerURLElement = other.URLElement();
     
    736736        m_innerNonSharedNode = other.innerNonSharedNode();
    737737        m_localPoint = other.localPoint();
    738         m_pointInMainFrame = other.m_pointInMainFrame;
     738        m_pointInInnerNodeFrame = other.m_pointInInnerNodeFrame;
    739739        m_innerURLElement = other.URLElement();
    740740        m_scrollbar = other.scrollbar();
     
    769769        return Vector<String>();
    770770
    771     DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(hitTestLocation().point(), DocumentMarker::DictationAlternatives);
     771    DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(pointInInnerNodeFrame(), DocumentMarker::DictationAlternatives);
    772772    if (!marker)
    773773        return Vector<String>();
  • trunk/Source/WebCore/rendering/HitTestResult.h

    r139199 r143727  
    126126
    127127    // The hit-tested point in the coordinates of the main frame.
    128     const LayoutPoint& pointInMainFrame() const { return m_pointInMainFrame; }
     128    const LayoutPoint& pointInMainFrame() const { return m_hitTestLocation.point(); }
    129129    IntPoint roundedPointInMainFrame() const { return roundedIntPoint(pointInMainFrame()); }
    130     void setPointInMainFrame(const LayoutPoint& p) { m_pointInMainFrame = p; }
    131130
    132131    // The hit-tested point in the coordinates of the innerNode frame, the frame containing innerNode.
    133     const LayoutPoint& pointInInnerNodeFrame() const { return m_hitTestLocation.point(); }
     132    const LayoutPoint& pointInInnerNodeFrame() const { return m_pointInInnerNodeFrame; }
    134133    IntPoint roundedPointInInnerNodeFrame() const { return roundedIntPoint(pointInInnerNodeFrame()); }
    135134    Frame* innerNodeFrame() const;
     
    204203    RefPtr<Node> m_innerNode;
    205204    RefPtr<Node> m_innerNonSharedNode;
    206     LayoutPoint m_pointInMainFrame; // The hit-tested point in main-frame coordinates.
     205    LayoutPoint m_pointInInnerNodeFrame; // The hit-tested point in innerNode frame coordinates.
    207206    LayoutPoint m_localPoint; // A point in the local coordinate space of m_innerNonSharedNode's renderer. Allows us to efficiently
    208207                              // determine where inside the renderer we hit on subsequent operations.
  • trunk/Source/WebCore/rendering/RenderFrameBase.cpp

    r139749 r143727  
    3030#include "FrameView.h"
    3131#include "HTMLFrameElementBase.h"
     32#include "HitTestResult.h"
     33#include "RenderLayer.h"
    3234#include "RenderView.h"
    3335
     
    103105}
    104106
     107bool RenderFrameBase::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
     108{
     109    if (!request.allowsChildFrameContent())
     110        return RenderPart::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
     111
     112    ASSERT_WITH_SECURITY_IMPLICATION(!widget() || widget()->isFrameView());
     113    FrameView* childFrameView = static_cast<FrameView*>(widget());
     114    RenderView* childRoot = childFrameView ? childFrameView->renderView() : 0;
     115
     116    if (childRoot) {
     117        LayoutPoint adjustedLocation = accumulatedOffset + location();
     118        LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - childFrameView->scrollOffset();
     119        HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset);
     120        HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildFrameHitTest);
     121        HitTestResult childFrameResult(newHitTestLocation);
     122
     123        bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTestLocation, childFrameResult);
     124        result.append(childFrameResult);
     125        if (isInsideChildFrame)
     126            return true;
     127
     128        if (request.allowsFrameScrollbars()) {
     129            // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls,
     130            // so we need to test ScrollView scrollbars separately here.
     131            // FIXME: Consider if this test could be done unconditionally.
     132            Scrollbar* frameScrollbar = childFrameView->scrollbarAtPoint(newHitTestLocation.roundedPoint());
     133            if (frameScrollbar)
     134                result.setScrollbar(frameScrollbar);
     135        }
     136    }
     137
     138    return RenderPart::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
    105139}
     140
     141}
  • trunk/Source/WebCore/rendering/RenderFrameBase.h

    r128677 r143727  
    3737
    3838public:
     39    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
    3940    void layoutWithFlattening(bool fixedWidth, bool fixedHeight);
    4041};
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r143655 r143727  
    40144014        // return ourselves. We do this so mouse events continue getting delivered after a drag has
    40154015        // exited the WebView, and so hit testing over a scrollbar hits the content document.
    4016         if ((request.active() || request.release()) && isRootLayer()) {
     4016        if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRootLayer()) {
    40174017            renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point()));
    40184018            insideLayer = this;
  • trunk/Source/WebCore/testing/Internals.cpp

    r143136 r143727  
    13991399
    14001400PassRefPtr<NodeList> Internals::nodesFromRect(Document* document, int x, int y, unsigned topPadding, unsigned rightPadding,
    1401     unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, ExceptionCode& ec) const
     1401    unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent, ExceptionCode& ec) const
    14021402{
    14031403    if (!document || !document->frame() || !document->frame()->view()) {
     
    14111411    if (allowShadowContent)
    14121412        hitType |= HitTestRequest::AllowShadowContent;
     1413    if (allowChildFrameContent)
     1414        hitType |= HitTestRequest::AllowChildFrameContent;
    14131415
    14141416    return document->nodesFromRect(x, y, topPadding, rightPadding, bottomPadding, leftPadding, hitType);
  • trunk/Source/WebCore/testing/Internals.h

    r143136 r143727  
    191191
    192192    PassRefPtr<NodeList> nodesFromRect(Document*, int x, int y, unsigned topPadding, unsigned rightPadding,
    193         unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, ExceptionCode&) const;
     193        unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent, ExceptionCode&) const;
    194194
    195195    void emitInspectorDidBeginFrame();
  • trunk/Source/WebCore/testing/Internals.idl

    r143136 r143727  
    159159    NodeList nodesFromRect(in Document document, in long x, in long y,
    160160        in unsigned long topPadding, in unsigned long rightPadding, in unsigned long bottomPadding, in unsigned long leftPadding,
    161         in boolean ignoreClipping, in boolean allowShadowContent) raises (DOMException);
     161        in boolean ignoreClipping, in boolean allowShadowContent, in boolean allowChildFrameContent) raises (DOMException);
    162162
    163163    void emitInspectorDidBeginFrame();
Note: See TracChangeset for help on using the changeset viewer.