Incorrect rect-based hit-test result when hit-test region includes culled inlines
authorallan.jensen@digia.com <allan.jensen@digia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Nov 2012 11:03:23 +0000 (11:03 +0000)
committerallan.jensen@digia.com <allan.jensen@digia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Nov 2012 11:03:23 +0000 (11:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=88376

Patch by Allan Sandfeld Jensen <allan.jensen@nokia.com> on 2012-09-17
Reviewed by Dave Hyatt.

Source/WebCore:

Move the handling of culled inlines from HitTestResult::addNodeToRectBasedTestResult to
InlineFlowBox::nodeAtPoint. This makes it possible to fix a number of bugs with how
culled inlines were handled. They are now checked after all their children, and may
terminate area-based hit-testing if they contain the whole area.

Tests: fast/dom/nodesFromRect/nodesFromRect-culled-inlines.html
       fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak.html

* rendering/HitTestResult.cpp:
(WebCore::HitTestLocation::HitTestLocation):
(WebCore::HitTestResult::addNodeToRectBasedTestResult):
* rendering/HitTestResult.h:
(HitTestLocation):
* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::nodeAtPoint):
* rendering/RenderInline.cpp:
(WebCore::RenderInline::hitTestCulledInline):
* rendering/RenderInline.h:
(RenderInline):

LayoutTests:

Renames the existing nodesFromRect-culled-inlines.html test to nodesFromRect-inline-image.html,
because it did not test any culled inlines anymore, and replace it with two new tests that does
test culled inlines.

* fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak-expected.txt: Copied from LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inlines-expected.txt.
* fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak.html: Added.
* fast/dom/nodesFromRect/nodesFromRect-culled-inlines-expected.txt:
* fast/dom/nodesFromRect/nodesFromRect-culled-inlines.html:
* fast/dom/nodesFromRect/nodesFromRect-inline-image-expected.txt: Added.
* fast/dom/nodesFromRect/nodesFromRect-inline-image.html: Added.
* fast/dom/nodesFromRect/resources/nodesFromRect.js:
(checkRect):
(nodesFromRectAsString):

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak.html [new file with mode: 0644]
LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inlines-expected.txt
LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inlines.html
LayoutTests/fast/dom/nodesFromRect/nodesFromRect-inline-image-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/nodesFromRect/nodesFromRect-inline-image.html [new file with mode: 0644]
LayoutTests/fast/dom/nodesFromRect/resources/nodesFromRect.js
Source/WebCore/ChangeLog
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/HitTestResult.h
Source/WebCore/rendering/InlineFlowBox.cpp
Source/WebCore/rendering/RenderInline.cpp
Source/WebCore/rendering/RenderInline.h

index 483f765..ee15527 100644 (file)
@@ -1,3 +1,24 @@
+2012-09-17  Allan Sandfeld Jensen  <allan.jensen@nokia.com>
+
+        Incorrect rect-based hit-test result when hit-test region includes culled inlines
+        https://bugs.webkit.org/show_bug.cgi?id=88376
+
+        Reviewed by Dave Hyatt.
+
+        Renames the existing nodesFromRect-culled-inlines.html test to nodesFromRect-inline-image.html,
+        because it did not test any culled inlines anymore, and replace it with two new tests that does
+        test culled inlines.
+
+        * fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak-expected.txt: Copied from LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inlines-expected.txt.
+        * fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak.html: Added.
+        * fast/dom/nodesFromRect/nodesFromRect-culled-inlines-expected.txt:
+        * fast/dom/nodesFromRect/nodesFromRect-culled-inlines.html:
+        * fast/dom/nodesFromRect/nodesFromRect-inline-image-expected.txt: Added.
+        * fast/dom/nodesFromRect/nodesFromRect-inline-image.html: Added.
+        * fast/dom/nodesFromRect/resources/nodesFromRect.js:
+        (checkRect):
+        (nodesFromRectAsString):
+
 2012-11-27  Kent Tamura  <tkent@chromium.org>
 
         Reduce the number of pixel tests for date/time input types
diff --git a/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak-expected.txt b/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak-expected.txt
new file mode 100644 (file)
index 0000000..0241aae
--- /dev/null
@@ -0,0 +1,12 @@
+Document::nodesFromRect : culled inline with line-break - bug 88376
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak.html b/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak.html
new file mode 100644 (file)
index 0000000..487860b
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Document::nodesFromRect : culled inline with line-break - bug 88376</title>
+    <script src="../../js/resources/js-test-pre.js"></script>
+    <script src="resources/nodesFromRect.js"></script>
+    <style>
+        #sandbox { 
+            position: absolute;
+            left: 0px;
+            top: 0px;
+            width: 220px;
+            height: 200px;
+        }
+        #sandbox p { font: 20px Ahem; }
+    </style>
+</head>
+<body id="body">
+    <div id=sandbox>
+        <p>Word <span id=culledinline>word1 <span id=wordinline2>word2</span></span> word
+    </div>
+
+    <p id="description"></p>
+    <span id="console"></span>
+    <script type="application/javascript">
+        function runTest()
+        {
+            description(document.title);
+            window.scrollTo(0, 0);
+            /* Rect based test over word1 only. */
+            checkRect(110, 25, 10, 10, "'word1 '");
+            /* Rect based test over the word2 only. */
+            checkRect(20, 45, 10, 10, "'word2'");
+            /* Rect based test not contained by culledinline, but contained by its bounding box. */
+            checkRect(20, 35, 10, 20, "'word2', SPAN#wordinline2, SPAN#culledinline, P, 'Word '");
+            /* Note the order of P and 'Word ' is slightly unusual, but this is due to lines being tested one by one. */
+
+            document.getElementById('sandbox').style.display = 'none';
+        }
+        runTest();
+    </script>
+    <script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
+
index d7454db..ebed247 100644 (file)
@@ -1,4 +1,10 @@
-  PASS All correct nodes found for rect
+Document::nodesFromRect : culled inlines - bug 88376
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
 PASS All correct nodes found for rect
 PASS All correct nodes found for rect
 PASS All correct nodes found for rect
index b0d9058..b2e0652 100644 (file)
@@ -1,48 +1,52 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>Document::nodesFromRect test - bug 85849</title>
-  <script src="../../js/resources/js-test-pre.js"></script>
-  <script src="resources/nodesFromRect.js"></script>
-  <script type="application/javascript">
-    function runTest()
-    {
-      var e = {};
-
-      // Set up shortcut access to elements
-      e['html'] = document.getElementsByTagName("html")[0];
-      ['body', 'span', 'img'].forEach(function(a) {
-        e[a] = document.getElementById(a);
-      });
-
-      window.scrollTo(0, 0);
-
-      /* Point based test over the img only. */
-      check(20, 20, 0, 0, 0, 0, [e.img]);
-      /* Rect based test over the img only. */
-      check(20, 20, 5, 5, 5, 5, [e.img]);
-
-      /* Note that for the tests below, the img bounds are considered to be (99, 99). */
-      /* Point based test over the img and the span. */
-      check(0, 99, 0, 0, 0, 0, [e.img]);
-      /* Rect based test over the img and the span with the img fully covering the hit region. */
-      check(0, 98, 0, 1, 1, 0, [e.img]);
-      /* Rect based test over the img and the span with the img not fully covering the hit region. */
-      /* FIXME: This fails due to: https://bugs.webkit.org/show_bug.cgi?id=88376 */
-      check(0, 98, 0, 1, 2, 0, [e.img, e.span]);
-      /* Rect based test over the entire img. */
-      check(0, 0, 0, 99, 99, 0, [e.img]);
-    }
-  </script>
+    <title>Document::nodesFromRect : culled inlines - bug 88376</title>
+    <script src="../../js/resources/js-test-pre.js"></script>
+    <script src="resources/nodesFromRect.js"></script>
+    <style>
+        #sandbox { 
+            position: absolute;
+            left: 0px;
+            top: 0px;
+            width: 400px;
+            height: 200px;
+        }
+        #sandbox p { font: 16px Ahem; }
+    </style>
 </head>
-<body id="body" style="padding: 0; margin: 0;">
-  <span id="span" style="margin: 0; padding: 0; font-size:36px">
-    <img id="img" width="100" height="100" style="background-color: black; margin: 0; padding: 0;" />
-  </span>
+<body id="body">
+    <div id=sandbox>
+        <p><span id=culledinline><span id=wordinline1>word1</span>   <span id=wordinline2>word2</span></span>   <span id=wordinline3>word3</span></p>
+    </div>
+
+    <p id="description"></p>
+    <span id="console"></span>
+    <script type="application/javascript">
+        function runTest()
+        {
+            description(document.title);
+            window.scrollTo(0, 0);
+            /* Rect based test over word1 only. */
+            checkRect(30, 19, 8, 8, "'word1'");
+            /* Rect based test over the word2 only. */
+            checkRect(126, 19, 8, 8, "'word2'");
+            /* Rect based test over the word3 only. */
+            checkRect(222, 19, 8, 8, "'word3'");
+            /* Rect based test between word1 and word2. */
+            checkRect(84, 19, 8, 8, "'   '");
+            /* Rect based test over and outside word1. */
+            checkRect(70, 19, 20, 8, "'   ', 'word1', SPAN#wordinline1, SPAN#culledinline");
+            /* Rect based test over word1 and word2. */
+            checkRect(70, 19, 40, 8, "'word2', SPAN#wordinline2, '   ', 'word1', SPAN#wordinline1, SPAN#culledinline");
+            /* Rect based test over word2 and word3. */
+            checkRect(170, 19, 40, 8, "'word3', SPAN#wordinline3, '   ', 'word2', SPAN#wordinline2, SPAN#culledinline, P");
 
-  <span id="console" style="position: absolute; top: 150px;"></span>
-  <script> runTest();</script>
-  <script src="../../js/resources/js-test-post.js"></script>
+            document.getElementById('sandbox').style.display = 'none';
+        }
+        runTest();
+    </script>
+    <script src="../../js/resources/js-test-post.js"></script>
 </body>
 </html>
 
diff --git a/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-inline-image-expected.txt b/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-inline-image-expected.txt
new file mode 100644 (file)
index 0000000..64c67df
--- /dev/null
@@ -0,0 +1,21 @@
+Document::nodesFromRect : inline image - bug 85849
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS All correct nodes found for rect
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-inline-image.html b/LayoutTests/fast/dom/nodesFromRect/nodesFromRect-inline-image.html
new file mode 100644 (file)
index 0000000..aacdc9c
--- /dev/null
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Document::nodesFromRect : inline image - bug 85849</title>
+    <script src="../../js/resources/js-test-pre.js"></script>
+    <script src="resources/nodesFromRect.js"></script>
+    <style>
+        #sandbox { 
+            position: absolute;
+            left: 0px;
+            top: 0px;
+            width: 400px;
+            height: 200px;
+        }
+        #sandbox #container { padding: 2px; padding-bottom: 10px; }
+        #sandbox #container span { font-size: 36px; }
+        #sandbox img { background-color: black; }
+    </style>
+</head>
+<body id="body">
+    <div id=sandbox>
+        <div id=container>
+            <span>
+                <img width="100" height="100"></img>
+            </span>
+        </div>
+    </div>
+
+    <p id="description"></p>
+    <span id="console"></span>
+    <script type="application/javascript">
+        function runTest()
+        {
+            description(document.title);
+            window.scrollTo(0, 0);
+            /* Point based test over the img only. */
+            checkRect(20, 20, 1, 1, "IMG");
+            /* Rect based test over the img only. */
+            checkRect(15, 15, 10, 10, "IMG");
+            /* Rect based test over the div only. */
+            checkRect(0, 0, 2, 2, "DIV#container");
+            /* Rect based test over the span only. */
+            checkRect(3, 103, 2, 2, "SPAN");
+
+            /* Note that for the tests below, the img bounds are considered to be (2, 2) x (100, 100). */
+            /* Rect based test over the entire img. */
+            checkRect(2, 2, 100, 100, "IMG");
+            /* Point based test over the img and the span. */
+            checkRect(2, 99, 1, 1, "IMG");
+            /* Rect based test over the img and the span with the img fully covering the hit region. */
+            checkRect(2, 98, 2, 2, "IMG");
+            /* Rect based test over the img and the span with the img not fully covering the hit region. */
+            checkRect(3, 101, 2, 5, "IMG, SPAN");
+            /* Rect based test over the img, span and their container. */
+            checkRect(3, 101, 2, 18, "IMG, SPAN, DIV#container");
+            /* Rect based test over just span and its container. */
+            checkRect(3, 103, 2, 16,  "SPAN, DIV#container");
+            /* Rect based test over the img that is not over span with the img not fully covering the hit region. */
+            checkRect(1, 1, 3, 3, "IMG, DIV#container");
+
+        }
+        runTest();
+    </script>
+    <script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
+
index 2e83a75..d02c1c7 100644 (file)
@@ -67,6 +67,60 @@ function checkShadowContent(x, y, topPadding, rightPadding, bottomPadding, leftP
   testPassed("All correct nodes found for rect");
 }
 
+function checkRect(left, top, width, height, expectedNodeString, doc)
+{
+    if (!window.internals)
+        return;
+
+    if (height <=0 || width <= 0)
+        return;
+
+    if (!doc)
+        doc = document;
+
+    var topPadding = height / 2;
+    var leftPadding =  width / 2;
+    // FIXME: When nodesFromRect is changed to not add 1 to width and height, remove the correction here.
+    var bottomPadding = (height - 1) - topPadding;
+    var rightPadding = (width - 1) - leftPadding;
+
+    var nodeString = nodesFromRectAsString(doc, left + leftPadding, top + topPadding, topPadding, rightPadding, bottomPadding, leftPadding);
+
+    if (nodeString == expectedNodeString) {
+        testPassed("All correct nodes found for rect");
+    } else {
+        testFailed("NodesFromRect should be [" + expectedNodeString + "] was [" + nodeString + "]");
+    }
+}
+
+function nodesFromRectAsString(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding)
+{
+    var nodeString = "";
+    var nodes = internals.nodesFromRect(doc, x, y, topPadding, rightPadding, bottomPadding, leftPadding, true /* ignoreClipping */, false /* allow shadow content */);
+    if (!nodes)
+        return nodeString;
+
+    for (var i = 0; i < nodes.length; i++) {
+        if (nodes[i].nodeType == 1) {
+            nodeString += nodes[i].nodeName;
+            if (nodes[i].id)
+                nodeString += '#' + nodes[i].id;
+            else if (nodes[i].class) {
+                nodeString += '.' + nodes[i].class;
+            }
+        } else if (nodes[i].nodeType == 3) {
+            nodeString += "'" + nodes[i].data + "'";
+        } else {
+            continue;
+        }
+        if (i + 1 < nodes.length) {
+            nodeString += ", ";
+        }
+    }
+    return nodeString;
+}
+
+
 function getCenterFor(element)
 {
   var rect = element.getBoundingClientRect();
index 48e374a..0ccaa05 100644 (file)
@@ -1,3 +1,30 @@
+2012-09-17  Allan Sandfeld Jensen  <allan.jensen@nokia.com>
+
+        Incorrect rect-based hit-test result when hit-test region includes culled inlines
+        https://bugs.webkit.org/show_bug.cgi?id=88376
+
+        Reviewed by Dave Hyatt.
+
+        Move the handling of culled inlines from HitTestResult::addNodeToRectBasedTestResult to 
+        InlineFlowBox::nodeAtPoint. This makes it possible to fix a number of bugs with how
+        culled inlines were handled. They are now checked after all their children, and may
+        terminate area-based hit-testing if they contain the whole area.
+
+        Tests: fast/dom/nodesFromRect/nodesFromRect-culled-inlines.html
+               fast/dom/nodesFromRect/nodesFromRect-culled-inline-with-linebreak.html
+
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestLocation::HitTestLocation):
+        (WebCore::HitTestResult::addNodeToRectBasedTestResult):
+        * rendering/HitTestResult.h:
+        (HitTestLocation):
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::nodeAtPoint):
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::hitTestCulledInline):
+        * rendering/RenderInline.h:
+        (RenderInline):
+
 2012-11-27  Kenneth Rohde Christiansen  <kenneth@webkit.org>
 
         REGRESSION(134887) [Qt][EFL][WK2] Repaint counter not working
index 54b8f19..38f1f67 100644 (file)
@@ -104,7 +104,7 @@ HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize&
     , m_boundingBox(other.m_boundingBox)
     , m_transformedPoint(other.m_transformedPoint)
     , m_transformedRect(other.m_transformedRect)
-    , m_region(region)
+    , m_region(region ? region : other.m_region)
     , m_isRectBased(other.m_isRectBased)
     , m_isRectilinear(other.m_isRectilinear)
 {
@@ -700,21 +700,6 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestReques
     mutableRectBasedTestResult().add(node);
 
     bool regionFilled = rect.contains(locationInContainer.boundingBox());
-    // FIXME: This code (incorrectly) attempts to correct for culled inline nodes. See https://bugs.webkit.org/show_bug.cgi?id=85849.
-    if (node->renderer()->isInline() && !regionFilled) {
-        for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) {
-            if (!curr->isRenderInline())
-                break;
-
-            // We need to make sure the nodes for culled inlines get included.
-            RenderInline* currInline = toRenderInline(curr);
-            if (currInline->alwaysCreateLineBoxes())
-                break;
-
-            if (currInline->visibleToHitTesting() && currInline->node())
-                mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode());
-        }
-    }
     return !regionFilled;
 }
 
@@ -735,21 +720,6 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestReques
     mutableRectBasedTestResult().add(node);
 
     bool regionFilled = rect.contains(locationInContainer.boundingBox());
-    // FIXME: This code (incorrectly) attempts to correct for culled inline nodes. See https://bugs.webkit.org/show_bug.cgi?id=85849.
-    if (node->renderer()->isInline() && !regionFilled) {
-        for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) {
-            if (!curr->isRenderInline())
-                break;
-
-            // We need to make sure the nodes for culled inlines get included.
-            RenderInline* currInline = toRenderInline(curr);
-            if (currInline->alwaysCreateLineBoxes())
-                break;
-
-            if (currInline->visibleToHitTesting() && currInline->node())
-                mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode());
-        }
-    }
     return !regionFilled;
 }
 
index ecc7e3b..57a41da 100644 (file)
@@ -56,7 +56,7 @@ public:
     // Pass non-zero padding values to perform a rect-based hit test.
     HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
     // Make a copy the HitTestLocation in a new region by applying given offset to internal point and area.
-    HitTestLocation(const HitTestLocation&, const LayoutSize& offset, RenderRegion*);
+    HitTestLocation(const HitTestLocation&, const LayoutSize& offset, RenderRegion* = 0);
     HitTestLocation(const HitTestLocation&);
     ~HitTestLocation();
     HitTestLocation& operator=(const HitTestLocation&);
index 8e411d1..f2eed4b 100644 (file)
@@ -981,12 +981,41 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
         return false;
 
     // Check children first.
+    // We need to account for culled inline parents of the hit-tested nodes, so that they may also get included in area-based hit-tests.
+    RenderObject* culledParent = 0;
     for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
-        if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
-            renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
-            return true;
+        if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) {
+            RenderObject* newParent = 0;
+            // Culled parents are only relevant for area-based hit-tests, so ignore it in point-based ones.
+            if (locationInContainer.isRectBasedTest()) {
+                newParent = curr->renderer()->parent();
+                if (newParent == renderer())
+                    newParent = 0;
+            }
+            // Check the culled parent after all its children have been checked, to do this we wait until
+            // we are about to test an element with a different parent.
+            if (newParent != culledParent) {
+                if (!newParent || !newParent->isDescendantOf(culledParent)) {
+                    while (culledParent && culledParent != renderer() && culledParent != newParent) {
+                        if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset))
+                            return true;
+                        culledParent = culledParent->parent();
+                    }
+                }
+                culledParent = newParent;
+            }
+            if (curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
+                renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
+                return true;
+            }
         }
     }
+    // Check any culled ancestor of the final children tested.
+    while (culledParent && culledParent != renderer()) {
+        if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset))
+            return true;
+        culledParent = culledParent->parent();
+    }
 
     // Now check ourselves. Pixel snap hit testing.
     LayoutRect frameRect = roundedFrameRect();
index 4e27e6d..01f9699 100644 (file)
@@ -774,6 +774,47 @@ bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& res
     return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
 }
 
+namespace {
+
+class HitTestCulledInlinesGeneratorContext {
+public:
+    HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { }
+    void operator()(const FloatRect& rect)
+    {
+        m_intersected = m_intersected || m_location.intersects(rect);
+        m_region.unite(enclosingIntRect(rect));
+    }
+    bool intersected() const { return m_intersected; }
+private:
+    bool m_intersected;
+    Region& m_region;
+    const HitTestLocation& m_location;
+};
+
+} // unnamed namespace
+
+bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
+{
+    ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
+    if (!visibleToHitTesting())
+        return false;
+
+    HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
+
+    Region regionResult;
+    HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
+    generateCulledLineBoxRects(context, this);
+
+    if (context.intersected()) {
+        updateHitTestResult(result, tmpLocation.point());
+        // We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
+        // because it can only handle rectangular targets.
+        result.addNodeToRectBasedTestResult(node(), request, locationInContainer);
+        return regionResult.contains(enclosingIntRect(tmpLocation.boundingBox()));
+    }
+    return false;
+}
+
 VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point)
 {
     // FIXME: Does not deal with relative or sticky positioned inlines (should it?)
index 0b13f63..845904b 100644 (file)
@@ -89,6 +89,8 @@ public:
 
     virtual LayoutRect localCaretRect(InlineBox*, int, LayoutUnit* extraWidthToEndOfLine) OVERRIDE;
 
+    bool hitTestCulledInline(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset);
+
 protected:
     virtual void willBeDestroyed();