[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

tonikitoo at webkit.org tonikitoo at webkit.org
Wed Dec 22 11:33:33 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 81c027d557f89eb2ba89752577d98c6ae39551b1
Author: tonikitoo at webkit.org <tonikitoo at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Jul 29 13:19:43 2010 +0000

    2010-07-21 Grace Kloba  <klobag at gmail.com> , Antonio Gomes  <tonikitoo at webkit.org>
    
            Reviewed by David Hyatt.
    
            Enhance the hit testing to take a rectangle instead of a point
            https://bugs.webkit.org/show_bug.cgi?id=40197
    
            The primary goal of this change is to provide mechanisms for more precise tap
            actions by the users on mobile devices.
    
            Patch extends the hit testing system to work considering a rectangular area
            as input instead of a point, when applicable. For that, the HitTestResult class
            was modified to take a padding (IntSize). The padding specifies a fuzzy range for
            accepting input events in pixels coordinates for both vertical and horizontal
            orientations. In other words, it tells how much to expand the search rect
            around a supposed touch point.
    
            If it non-positive, hit testing will behavior as the current point based hit testing,
            and methods are no-op'ed to not regress this common behavior performance-wise.
            When positive IntSize is provided, the hit test result will keep record of all
            nodes that intersect the built up test area. The logic will continue searching when it
            finds a candidate until the rectangle is fully enclosed by the boundaries of a candidate.
            The result will be a list of nodes in the z-order they are hit-tested.
            Caller will decide how to process them.
    
            In order to expose the functionality, the patch:
    
            - Adds a nodesFromRect method to the Document class, exposing the funcionality
            to the DOM. Method returns a NodeList with all nodes that intersect the given
            hit-tested area.
            - Extends hitTestResultAtPoint method of the EventHandler with an extra 'padding'
            parameter, defaulting to IntSize(0, 0). The rect-based hit test is performed when a
            positive padding is passed in.
    
            Test: fast/dom/nodesFromRect-basic.html
    
            * WebCore.base.exp:
            * dom/Document.cpp:
            (WebCore::Document::nodesFromRect): This method exposes the rect based funcionality to
            the DOM. It works similarly to elementFromPoint, however receiving a rectangular area
            as input instead of a point, and returning a z-index ordered list of nodes (not elements)
            whose area intersect the hit test rect.
            * dom/Document.h: Ditto.
            * dom/Document.idl: Ditto.
            * page/EventHandler.cpp:
            (WebCore::EventHandler::hitTestResultAtPoint): The funcionality is also exposed through this
            method. Patch adds a additional IntSize parameter to work as the padding area, building up
            the hit test rect.
            * page/EventHandler.h: Ditto.
            * rendering/HitTestResult.cpp:
            (WebCore::HitTestResult::HitTestResult): Rect based hit test constructor. Receives a
            padding IntSize as parameter. It can be (0,0).
            (WebCore::HitTestResult::operator=): Modified to assign the m_rectBasedTestResult as well.
            (WebCore::HitTestResult::append): Merge to HitTestResult objects in a way that the
            list node's of both objects get amended.
            (WebCore::HitTestResult::addNodeToRectBasedTestResult): Adds a given Node to the list of
            hit nodes.
            * rendering/HitTestResult.h:
            (WebCore::HitTestResult::padding): Returns the padding as an IntSize.
            (WebCore::HitTestResult::isRectBasedTest): Returns if the HitTestResult is rect based or not.
            (WebCore::HitTestResult::.rectBasedTestResult): Returns the list nodes hit.
            (WebCore::HitTestResult::rectFromPoint): Returns the hit test rect given the hit test point
            and padding.
            * rendering/RenderLayer.cpp:
            (WebCore::RenderLayer::hitTestLayer):
            (WebCore::RenderLayer::hitTestList):
            (WebCore::RenderLayer::hitTestChildLayerColumns):
            * rendering/EllipsisBox.cpp:
            (WebCore::EllipsisBox::nodeAtPoint): Method is modified to support rect based hit test extension.
            Now it not just checks if the boundary of the node being hit-tested contains a hit test point, but
            instead it checks if the boundary of the node intersects a hit test rect. It is implemented so
            that the common case (point based hit test) works as previously.
            * rendering/InlineFlowBox.cpp:
            (WebCore::InlineFlowBox::nodeAtPoint): Ditto.
            * rendering/InlineTextBox.cpp:
            (WebCore::InlineTextBox::nodeAtPoint): Ditto.
            * rendering/RenderBlock.cpp:
            (WebCore::RenderBlock::nodeAtPoint): Ditto.
            (WebCore::RenderBlock::hitTestColumns): Ditto.
            * rendering/RenderBox.cpp:
            (WebCore::RenderBox::nodeAtPoint): Ditto.
            * rendering/RenderImage.cpp:
            (WebCore::RenderImage::nodeAtPoint): Ditto.
            * rendering/RenderLineBoxList.cpp:
            (WebCore::RenderLineBoxList::hitTest):
            * rendering/RenderSVGRoot.cpp:
            (WebCore::RenderSVGRoot::nodeAtPoint): Ditto.
            * rendering/RenderTable.cpp:
            (WebCore::RenderTable::nodeAtPoint): Ditto.
            * rendering/RenderTableSection.cpp:
            (WebCore::RenderTableSection::nodeAtPoint): Ditto.
            * rendering/RenderWidget.cpp:
            (WebCore::RenderWidget::nodeAtPoint): Ditto.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@64272 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 8824beb..2eee200 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2010-07-21 Antonio Gomes  <tonikitoo at webkit.org> , Grace Kloba  <klobag at gmail.com>
+
+        Reviewed by David Hyatt.
+
+        Enhance the hit testing to take a rectangle instead of a point
+        https://bugs.webkit.org/show_bug.cgi?id=40197
+
+        * fast/dom/nodesFromRect-basic-expected.txt: Added.
+        * fast/dom/nodesFromRect-basic.html: Added.
+
 2010-07-29  Steve Block  <steveblock at google.com>
 
         Reviewed by Jeremy Orlow.
diff --git a/LayoutTests/fast/dom/Window/window-properties-expected.txt b/LayoutTests/fast/dom/Window/window-properties-expected.txt
index 9b09984..c977341 100644
--- a/LayoutTests/fast/dom/Window/window-properties-expected.txt
+++ b/LayoutTests/fast/dom/Window/window-properties-expected.txt
@@ -628,6 +628,7 @@ window.Document.prototype.isSameNode [function]
 window.Document.prototype.isSupported [function]
 window.Document.prototype.lookupNamespaceURI [function]
 window.Document.prototype.lookupPrefix [function]
+window.Document.prototype.nodesFromRect [function]
 window.Document.prototype.normalize [function]
 window.Document.prototype.queryCommandEnabled [function]
 window.Document.prototype.queryCommandIndeterm [function]
diff --git a/LayoutTests/fast/dom/nodesFromRect-basic-expected.txt b/LayoutTests/fast/dom/nodesFromRect-basic-expected.txt
new file mode 100644
index 0000000..89f1ea3
--- /dev/null
+++ b/LayoutTests/fast/dom/nodesFromRect-basic-expected.txt
@@ -0,0 +1,26 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS All correct nodes found for rect [53,71], [0,0]
+PASS All correct nodes found for rect [53,71], [10,0]
+PASS All correct nodes found for rect [53,71], [0,10]
+PASS All correct nodes found for rect [53,71], [10,10]
+PASS All correct nodes found for rect [152,105], [0,10]
+PASS All correct nodes found for rect [152,105], [10,0]
+PASS All correct nodes found for rect [152,105], [10,10]
+PASS All correct nodes found for rect [153,193], [0,0]
+PASS All correct nodes found for rect [153,193], [20,0]
+PASS All correct nodes found for rect [153,193], [0,20]
+PASS All correct nodes found for rect [144,183], [0,0]
+PASS All correct nodes found for rect [144,183], [0,1]
+PASS All correct nodes found for rect [144,183], [1,0]
+PASS All correct nodes found for rect [144,183], [1,1]
+PASS All correct nodes found for rect [77,240], [0,0]
+PASS All correct nodes found for rect [77,240], [10,0]
+PASS All correct nodes found for rect [77,240], [0,10]
+PASS All correct nodes found for rect [77,240], [10,10]
+PASS All correct nodes found for rect [39,212], [0,0]
+PASS All correct nodes found for rect [39,212], [0,10]
+PASS All correct nodes found for rect [39,212], [10,0]
+PASS All correct nodes found for rect [39,212], [10,10]
+
diff --git a/LayoutTests/fast/dom/nodesFromRect-basic.html b/LayoutTests/fast/dom/nodesFromRect-basic.html
new file mode 100644
index 0000000..6a4064a
--- /dev/null
+++ b/LayoutTests/fast/dom/nodesFromRect-basic.html
@@ -0,0 +1,89 @@
+<html>
+<head>
+  <title>Document::nodesFromRect test - bug 40197</title>
+  <style type="text/css"> @import "resources/nodesFromRect.css"; </style>
+  <script src="../js/resources/js-test-pre.js"></script>
+  <script src="resources/nodesFromRect.js"></script>
+  <script type="application/javascript">
+    function runTest()
+    {
+      if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+      }
+
+      var e = {};
+
+      // Set up shortcut access to elements
+      e['html'] = document.getElementsByTagName("html")[0];
+      ['h1', 'd1', 'd2', 'p1', 'p2', 'p3', 'p4', 'p5', 'span', 'body'].forEach(function(a) {
+        e[a] = document.getElementById(a);
+      });
+
+      window.scrollTo(0, 0);
+
+      check(53, 71, 0, 0, [e.body]);
+      check(53, 71, 10, 0, [e.p3, e.body]);
+      check(53, 71, 0, 10, [e.d1, e.h1, e.body]);
+      check(53, 71, 10, 10, [e.p3, e.d1, e.h1, e.body]);
+
+      check(152, 105, 0, 10, [e.p3, e.body]);
+      check(152, 105, 10, 0, [e.p4, e.d1, e.body]);
+      check(152, 105, 10, 10, [e.p4, e.p3, e.d1, e.body]);
+
+      // e.p1 is invisible and shouldn't appear:
+      check(153,193,0,0,[e.p5]);
+      // NOTE: [e.p5, e.d2]) should be returned if we did not stop
+      // at e.p5, which fully encloses the target rect.
+      check(153,193,20,0, [e.p5]);
+      check(153,193,0,20, [e.p5, e.body]);
+
+      // Precise pixel checks:
+      check(144, 183, 0, 0, [e.body]);
+      check(144, 183, 0, 1, [e.p5, e.body]);
+      check(144, 183, 1, 0, [e.d2, e.body]);
+      check(144, 183, 1, 1, [e.p5, e.d2, e.body]);
+      check(77, 240, 0, 0, [e.p2]);
+      check(77, 240, 10, 0, [e.p2]);
+      check(77, 240, 0, 10, [e.p5, e.span, e.p2]);
+      check(77, 240, 10, 10, [e.p5, e.span, e.p2]);
+
+      // Expanding area checks:
+      check(39, 212, 0,  0, [e.body]);
+      check(39, 212, 0, 10, [e.d2, e.p2, e.body]);
+      check(39, 212, 10, 0, [e.p5, e.body]);
+      check(39, 212, 10, 10, [e.p5, e.d2, e.p2, e.body]);
+
+      if (window.layoutTestController)
+        layoutTestController.notifyDone();
+    }
+
+    window.onload = runTest;
+  </script>
+</head>
+<body id="body">
+  <h1 id="h1"></h1>
+  <div id="d1"></div>
+
+  <!-- floated element -->
+  <div id="d2" style="float: left"></div>
+
+  <!-- hidden element -->
+  <p id="p1" style="float: left; visibility: hidden"></p>
+
+  <p id="p2" style="clear: left"><span id="span"></span></p>
+
+  <!-- absolute position -->
+  <p id="p3" style="position:absolute; top: 10px; left:50px; height:50px;"></p>
+
+  <!-- fixed position -->
+  <p id="p4" style="position: fixed; top: 30px; left: 150px; height: 50px; background-color: blue;"></p>
+
+  <!-- relative position -->
+  <p id="p5" style="position:relative; top: -100px; left: 30px; margin-bottom: -70px; background-color: green"></p>
+
+  <span id="console"></span>
+  <script src="../js/resources/js-test-post.js"></script>
+</body>
+</html>
+
diff --git a/LayoutTests/fast/dom/resources/nodesFromRect.css b/LayoutTests/fast/dom/resources/nodesFromRect.css
new file mode 100644
index 0000000..72e6fc0
--- /dev/null
+++ b/LayoutTests/fast/dom/resources/nodesFromRect.css
@@ -0,0 +1,44 @@
+body {
+  margin: 8px;
+  padding: 0;
+}
+
+h1, div, p, iframe {
+  display: block;
+  width: 100px;
+  height: 30px;
+  border: 3px solid black;
+  padding: 10px;
+  margin: 10px;
+}
+
+#span {
+  display: block;
+  width: 100px;
+  height: 30px;
+  border: 3px solid black;
+  padding: 10px;
+  margin: 10px;
+  display: inline-block;
+}
+
+#iframe1 {
+  height: 100px;
+  margin-top: 60px;
+}
+
+#p6 {
+  height: 50px;
+  margin-top: 30px;
+}
+
+#transf {
+  margin-top: 60px;
+  -webkit-transform: rotate(-45deg);
+}
+
+#decimal {
+  position: relative;
+  left: 0.5px;
+  top: 50.5px;
+}
diff --git a/LayoutTests/fast/dom/resources/nodesFromRect.js b/LayoutTests/fast/dom/resources/nodesFromRect.js
new file mode 100644
index 0000000..be06c6a
--- /dev/null
+++ b/LayoutTests/fast/dom/resources/nodesFromRect.js
@@ -0,0 +1,44 @@
+/*
+ * Contributors:
+ *     * Antonio Gomes <tonikitoo at webkit.org>
+ **/
+
+function check(x, y, hPadding, vPadding, list)
+{
+  /*
+    NodeList nodesFromRect(in long x,
+                           in long y,
+                           in long hPadding,
+                           in long vPadding,
+                           in boolean ignoreClipping);
+  */
+  var nodes = document.nodesFromRect(x, y, hPadding, vPadding, true /* ignoreClipping */);
+
+  if (nodes.length != list.length) {
+    testFailed("Different number of nodes for rect" +
+              "[" + x + "," + y + "], " +
+              "[" + hPadding + "," + vPadding + "]: '" + list.length + "' vs '" + nodes.length + "'");
+    return;
+  }
+
+  for (var i = 0; i < nodes.length; i++) {
+    if (nodes[i] != list[i]) {
+      testFailed("Unexpected node #" + i + " for rect " +
+                "[" + x + "," + y + "], " +
+                "[" + hPadding + "," + vPadding + "]" + " - " + nodes[i]);
+      return;
+    }
+  }
+
+  testPassed("All correct nodes found for rect "  +
+           "[" + x + "," + y + "], " +
+           "[" + hPadding + "," + vPadding + "]");
+}
+
+function getCenterFor(element)
+{
+  var rect = element.getBoundingClientRect();
+  return { x : parseInt((rect.left + rect.right) / 2) , y : parseInt((rect.top + rect.bottom) / 2)};
+}
+
+var successfullyParsed = true;
diff --git a/LayoutTests/platform/qt/fast/dom/Window/window-properties-expected.txt b/LayoutTests/platform/qt/fast/dom/Window/window-properties-expected.txt
index 449379f..2e9a586 100644
--- a/LayoutTests/platform/qt/fast/dom/Window/window-properties-expected.txt
+++ b/LayoutTests/platform/qt/fast/dom/Window/window-properties-expected.txt
@@ -628,6 +628,7 @@ window.Document.prototype.isSameNode [function]
 window.Document.prototype.isSupported [function]
 window.Document.prototype.lookupNamespaceURI [function]
 window.Document.prototype.lookupPrefix [function]
+window.Document.prototype.nodesFromRect [function]
 window.Document.prototype.normalize [function]
 window.Document.prototype.queryCommandEnabled [function]
 window.Document.prototype.queryCommandIndeterm [function]
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 9479840..4156b5b 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,97 @@
+2010-07-21 Grace Kloba  <klobag at gmail.com> , Antonio Gomes  <tonikitoo at webkit.org>
+
+        Reviewed by David Hyatt.
+
+        Enhance the hit testing to take a rectangle instead of a point
+        https://bugs.webkit.org/show_bug.cgi?id=40197
+
+        The primary goal of this change is to provide mechanisms for more precise tap
+        actions by the users on mobile devices.
+
+        Patch extends the hit testing system to work considering a rectangular area
+        as input instead of a point, when applicable. For that, the HitTestResult class
+        was modified to take a padding (IntSize). The padding specifies a fuzzy range for
+        accepting input events in pixels coordinates for both vertical and horizontal
+        orientations. In other words, it tells how much to expand the search rect
+        around a supposed touch point.
+
+        If it is non-positive padding (e.g. (-1, -1), (5, -1), (0, 0)), hit testing will behavior
+        as the current point based hit testing: methods are no-op'ed to not regress it performance-wise
+        since it is the common behavior. When positive padding is provided, the HitTestResult class will
+        keep record of all nodes that intersect the built up test area. The logic will continue searching
+        when it finds a candidate until the hit test area is fully enclosed by the boundaries of a candidate.
+        The result will be a list of nodes in the z-order they are hit-tested. Caller will decide how
+        to process them.
+
+        In order to expose the functionality, the patch:
+
+        - Adds a nodesFromRect method to the Document class, exposing the funcionality
+        to the DOM. Method returns a NodeList with all nodes that intersect the given
+        hit-tested area.
+        - Extends hitTestResultAtPoint method of the EventHandler with an extra 'padding'
+        parameter, defaulting to IntSize(-1, -1). The rect-based hit test is performed when a
+        non-negative padding is passed in.
+
+        Test: fast/dom/nodesFromRect-basic.html
+
+        * WebCore.base.exp:
+        * dom/Document.cpp:
+        (WebCore::Document::nodesFromRect): This method exposes the rect based funcionality to
+        the DOM. It works similarly to elementFromPoint, however receiving a rectangular area
+        as input instead of a point, and returning a z-index ordered list of nodes (not elements)
+        whose area intersect the hit test rect.
+        * dom/Document.h: Ditto.
+        * dom/Document.idl: Ditto.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::hitTestResultAtPoint): The funcionality is also exposed through this
+        method. Patch adds a additional IntSize parameter to work as the padding area, building up
+        the hit test rect.
+        * page/EventHandler.h: Ditto.
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::HitTestResult): Rect based hit test constructor. Receives a
+        padding IntSize as parameter. It can be (0,0).
+        (WebCore::HitTestResult::operator=): Modified to assign the m_rectBasedTestResult as well.
+        (WebCore::HitTestResult::append): Merge to HitTestResult objects in a way that the
+        list node's of both objects get amended.
+        (WebCore::HitTestResult::addNodeToRectBasedTestResult): Adds a given Node to the list of
+        hit nodes.
+        * rendering/HitTestResult.h:
+        (WebCore::HitTestResult::padding): Returns the padding as an IntSize.
+        (WebCore::HitTestResult::isRectBasedTest): Returns if the HitTestResult is rect based or not.
+        (WebCore::HitTestResult::.rectBasedTestResult): Returns the list nodes hit.
+        (WebCore::HitTestResult::rectFromPoint): Returns the hit test rect given the hit test point
+        and padding.
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::hitTestLayer):
+        (WebCore::RenderLayer::hitTestList):
+        (WebCore::RenderLayer::hitTestChildLayerColumns):
+        * rendering/EllipsisBox.cpp:
+        (WebCore::EllipsisBox::nodeAtPoint): Method is modified to support rect based hit test extension.
+        Now it not just checks if the boundary of the node being hit-tested contains a hit test point, but
+        instead it checks if the boundary of the node intersects a hit test rect. It is implemented so
+        that the common case (point based hit test) works as previously.
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::nodeAtPoint): Ditto.
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::nodeAtPoint): Ditto.
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::nodeAtPoint): Ditto.
+        (WebCore::RenderBlock::hitTestColumns): Ditto.
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::nodeAtPoint): Ditto.
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::nodeAtPoint): Ditto.
+        * rendering/RenderLineBoxList.cpp:
+        (WebCore::RenderLineBoxList::hitTest):
+        * rendering/RenderSVGRoot.cpp:
+        (WebCore::RenderSVGRoot::nodeAtPoint): Ditto.
+        * rendering/RenderTable.cpp:
+        (WebCore::RenderTable::nodeAtPoint): Ditto.
+        * rendering/RenderTableSection.cpp:
+        (WebCore::RenderTableSection::nodeAtPoint): Ditto.
+        * rendering/RenderWidget.cpp:
+        (WebCore::RenderWidget::nodeAtPoint): Ditto.
+
 2010-07-29  Steve Block  <steveblock at google.com>
 
         Reviewed by Jeremy Orlow.
diff --git a/WebCore/WebCore.exp.in b/WebCore/WebCore.exp.in
index 70e4aa3..6ebc8a5 100644
--- a/WebCore/WebCore.exp.in
+++ b/WebCore/WebCore.exp.in
@@ -217,7 +217,7 @@ __ZN7WebCore12EventHandler15sendScrollEventEv
 __ZN7WebCore12EventHandler16handleWheelEventERNS_18PlatformWheelEventE
 __ZN7WebCore12EventHandler17scrollRecursivelyENS_15ScrollDirectionENS_17ScrollGranularityEPNS_4NodeE
 __ZN7WebCore12EventHandler20handleTextInputEventERKNS_6StringEPNS_5EventEbb
-__ZN7WebCore12EventHandler20hitTestResultAtPointERKNS_8IntPointEbbNS_17HitTestScrollbarsEj
+__ZN7WebCore12EventHandler20hitTestResultAtPointERKNS_8IntPointEbbNS_17HitTestScrollbarsEjRKNS_7IntSizeE
 __ZN7WebCore12EventHandler21handleMousePressEventERKNS_18PlatformMouseEventE
 __ZN7WebCore12EventHandler23handleMouseReleaseEventERKNS_18PlatformMouseEventE
 __ZN7WebCore12EventHandler27capsLockStateMayHaveChangedEv
diff --git a/WebCore/config.h b/WebCore/config.h
index 6f9a7ad..9c7bc22 100644
--- a/WebCore/config.h
+++ b/WebCore/config.h
@@ -225,3 +225,4 @@ typedef float CGFloat;
 #if PLATFORM(WIN) && PLATFORM(CG)
 #define WTF_USE_SAFARI_THEME 1
 #endif
+
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
index 1c0e57c..848a9f5 100644
--- a/WebCore/dom/Document.cpp
+++ b/WebCore/dom/Document.cpp
@@ -119,6 +119,7 @@
 #include "SegmentedString.h"
 #include "SelectionController.h"
 #include "Settings.h"
+#include "StaticHashSetNodeList.h"
 #include "StringBuffer.h"
 #include "StyleSheetList.h"
 #include "TextEvent.h"
@@ -1004,6 +1005,63 @@ KURL Document::baseURI() const
     return m_baseURL;
 }
 
+// FIXME: We need to discuss the DOM API here at some point. Ideas:
+// * making it receive a rect as parameter, i.e. nodesFromRect(x, y, w, h);
+// * making it receive the expading size of each direction separately,
+//   i.e. nodesFromRect(x, y, topSize, rightSize, bottomSize, leftSize);
+PassRefPtr<NodeList> Document::nodesFromRect(int centerX, int centerY, unsigned hPadding, unsigned vPadding, bool ignoreClipping) const
+{
+    // FIXME: Share code between this, elementFromPoint and caretRangeFromPoint.
+    if (!renderer())
+        return 0;
+    Frame* frame = this->frame();
+    if (!frame)
+        return 0;
+    FrameView* frameView = frame->view();
+    if (!frameView)
+        return 0;
+
+    float zoomFactor = frameView->pageZoomFactor();
+    IntPoint point = roundedIntPoint(FloatPoint(centerX * zoomFactor + view()->scrollX(), centerY * zoomFactor + view()->scrollY()));
+    IntSize padding(hPadding, vPadding);
+
+    int type = HitTestRequest::ReadOnly | HitTestRequest::Active;
+
+    // When ignoreClipping is false, this method returns null for coordinates outside of the viewport.
+    if (ignoreClipping)
+        type |= HitTestRequest::IgnoreClipping;
+    else if (!frameView->visibleContentRect().intersects(IntRect(point, padding)))
+        return 0;
+
+    HitTestRequest request(type);
+
+    // Passing a zero padding will trigger a rect hit test, however for the purposes of nodesFromRect,
+    // we special handle this case in order to return a valid NodeList.
+    if (padding.isZero()) {
+        HitTestResult result(point);
+        return handleZeroPadding(request, result);
+    }
+
+    HitTestResult result(point, padding);
+    renderView()->layer()->hitTest(request, result);
+
+    return StaticHashSetNodeList::adopt(result.rectBasedTestResult());
+}
+
+PassRefPtr<NodeList> Document::handleZeroPadding(const HitTestRequest& request, HitTestResult& result) const
+{
+    renderView()->layer()->hitTest(request, result);
+
+    Node* node = result.innerNode();
+    if (!node)
+        return 0;
+
+    node = node->shadowAncestorNode();
+    ListHashSet<RefPtr<Node> > list;
+    list.add(node);
+    return StaticHashSetNodeList::adopt(list);
+}
+
 Element* Document::elementFromPoint(int x, int y) const
 {
     // FIXME: Share code between this and caretRangeFromPoint.
diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h
index ee46f53..8e42aad 100644
--- a/WebCore/dom/Document.h
+++ b/WebCore/dom/Document.h
@@ -87,6 +87,7 @@ namespace WebCore {
     class HTMLMapElement;
     class HistoryItem;
     class HitTestRequest;
+    class HitTestResult;
     class InspectorTimelineAgent;
     class IntPoint;
     class DOMWrapperWorld;
@@ -302,6 +303,18 @@ public:
     bool hasElementWithId(AtomicStringImpl* id) const;
     bool containsMultipleElementsWithId(const AtomicString& elementId) { return m_duplicateIds.contains(elementId.impl()); }
 
+    /**
+     * Retrieve all nodes that intersect a rect in the window's document, until it is fully enclosed by
+     * the boundaries of node.
+     *
+     * @param centerX x reference for the rectangle in CSS pixels
+     * @param centerY y reference for the rectangle in CSS pixels
+     * @param hPadding How much to expand the rectangle horizontally
+     * @param vPadding How much to expand the rectangle vertically
+     * @param ignoreClipping whether or not to ignore the root scroll frame when retrieving the element.
+     *        If false, this method returns null for coordinates outside of the viewport.
+     */
+    PassRefPtr<NodeList> nodesFromRect(int centerX, int centerY, unsigned hPadding, unsigned vPadding, bool ignoreClipping) const;
     Element* elementFromPoint(int x, int y) const;
     PassRefPtr<Range> caretRangeFromPoint(int x, int y);
 
@@ -1050,6 +1063,8 @@ private:
     void enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject);
     void pendingEventTimerFired(Timer<Document>*);
 
+    PassRefPtr<NodeList> handleZeroPadding(const HitTestRequest&, HitTestResult&) const;
+
     OwnPtr<CSSStyleSelector> m_styleSelector;
     bool m_didCalculateStyleSelector;
 
diff --git a/WebCore/dom/Document.idl b/WebCore/dom/Document.idl
index 9599d76..3ae551e 100644
--- a/WebCore/dom/Document.idl
+++ b/WebCore/dom/Document.idl
@@ -186,6 +186,11 @@ module core {
         readonly attribute [ConvertNullStringTo=Undefined] DOMString defaultCharset;
         readonly attribute [ConvertNullStringTo=Undefined] DOMString readyState;
 
+
+        NodeList           nodesFromRect(in long x, in long y,
+                                         in unsigned long hPadding,
+                                         in unsigned long vPadding,
+                                         in boolean ignoreClipping);
         Element            elementFromPoint(in long x, in long y);
         Range              caretRangeFromPoint(in long x, in long y);
 
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
index 2b10c6d..e10a3a1 100644
--- a/WebCore/page/EventHandler.cpp
+++ b/WebCore/page/EventHandler.cpp
@@ -863,9 +863,9 @@ void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
 }
 #endif // ENABLE(DRAG_SUPPORT)
     
-HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType)
+HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const IntSize& padding)
 {
-    HitTestResult result(point);
+    HitTestResult result(point, padding);
     if (!m_frame->contentRenderer())
         return result;
     if (ignoreClipping)
@@ -886,7 +886,7 @@ HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all
         FrameView* view = static_cast<FrameView*>(widget);
         IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(), 
             result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
-        HitTestResult widgetHitTestResult(widgetPoint);
+        HitTestResult widgetHitTestResult(widgetPoint, padding);
         frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
         result = widgetHitTestResult;
 
@@ -908,7 +908,7 @@ HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool all
             if (resultView && mainView) {
                 IntPoint windowPoint = resultView->contentsToWindow(result.point());
                 IntPoint mainFramePoint = mainView->windowToContents(windowPoint);
-                result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping);
+                result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
             }
         }
     }
diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h
index a4730bb..242601b 100644
--- a/WebCore/page/EventHandler.h
+++ b/WebCore/page/EventHandler.h
@@ -106,7 +106,10 @@ public:
 
     void dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&);
 
-    HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false, HitTestScrollbars scrollbars = DontHitTestScrollbars, HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active);
+    HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false,
+                                       HitTestScrollbars scrollbars = DontHitTestScrollbars,
+                                       HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active,
+                                       const IntSize& padding = IntSize());
 
     bool mousePressed() const { return m_mousePressed; }
     void setMousePressed(bool pressed) { m_mousePressed = pressed; }
diff --git a/WebCore/rendering/EllipsisBox.cpp b/WebCore/rendering/EllipsisBox.cpp
index 3e1342f..61cd524 100644
--- a/WebCore/rendering/EllipsisBox.cpp
+++ b/WebCore/rendering/EllipsisBox.cpp
@@ -113,9 +113,11 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
         }
     }
 
-    if (visibleToHitTesting() && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
+    IntRect boundsRect = IntRect(tx, ty, m_width, m_height);
+    if (visibleToHitTesting() && boundsRect.intersects(result.rectFromPoint(x, y))) {
         renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
-        return true;
+        if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, boundsRect))
+            return true;
     }
 
     return false;
diff --git a/WebCore/rendering/HitTestResult.cpp b/WebCore/rendering/HitTestResult.cpp
index 50933c6..dd96e0e 100644
--- a/WebCore/rendering/HitTestResult.cpp
+++ b/WebCore/rendering/HitTestResult.cpp
@@ -49,9 +49,20 @@ using namespace HTMLNames;
 HitTestResult::HitTestResult(const IntPoint& point)
     : m_point(point)
     , m_isOverWidget(false)
+    , m_isRectBased(false)
 {
 }
 
+HitTestResult::HitTestResult(const IntPoint& centerPoint, const IntSize& padding)
+    : m_point(centerPoint)
+    , m_isOverWidget(false)
+{
+    // If a zero padding is passed in or either width or height is negative, then it
+    // is not a valid padding and hence not a rect based hit test.
+    m_isRectBased = !(padding.isZero() || (padding.width() < 0 || padding.height() < 0));
+    m_padding = m_isRectBased ? padding : IntSize();
+}
+
 HitTestResult::HitTestResult(const HitTestResult& other)
     : m_innerNode(other.innerNode())
     , m_innerNonSharedNode(other.innerNonSharedNode())
@@ -61,6 +72,12 @@ HitTestResult::HitTestResult(const HitTestResult& other)
     , m_scrollbar(other.scrollbar())
     , m_isOverWidget(other.isOverWidget())
 {
+    // Only copy the padding and ListHashSet in case of rect hit test.
+    // Copying the later is rather expensive.
+    if ((m_isRectBased = other.isRectBasedTest())) {
+        m_padding = other.padding();
+        m_rectBasedTestResult = other.rectBasedTestResult();
+    }
 }
 
 HitTestResult::~HitTestResult()
@@ -76,6 +93,12 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other)
     m_innerURLElement = other.URLElement();
     m_scrollbar = other.scrollbar();
     m_isOverWidget = other.isOverWidget();
+    // Only copy the padding and ListHashSet in case of rect hit test.
+    // Copying the later is rather expensive.
+    if ((m_isRectBased = other.isRectBasedTest())) {
+        m_padding = other.padding();
+        m_rectBasedTestResult = other.rectBasedTestResult();
+    }
     return *this;
 }
 
@@ -362,4 +385,40 @@ bool HitTestResult::isContentEditable() const
     return m_innerNonSharedNode->isContentEditable();
 }
 
+bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const IntRect& rect)
+{
+    // If it is not a rect-based hit test, this method has to be no-op.
+    // Return false, so the hit test stops.
+    if (!isRectBasedTest())
+        return false;
+
+    // If node is null, return true so the hit test can continue.
+    if (!node)
+        return true;
+
+    node = node->shadowAncestorNode();
+    m_rectBasedTestResult.add(node);
+
+    return !rect.contains(rectFromPoint(x, y));
+}
+
+void HitTestResult::append(const HitTestResult& other)
+{
+    ASSERT(isRectBasedTest() && other.isRectBasedTest());
+
+    if (!m_innerNode && other.innerNode()) {
+        m_innerNode = other.innerNode();
+        m_innerNonSharedNode = other.innerNonSharedNode();
+        m_localPoint = other.localPoint();
+        m_innerURLElement = other.URLElement();
+        m_scrollbar = other.scrollbar();
+        m_isOverWidget = other.isOverWidget();
+    }
+
+    const ListHashSet<RefPtr<Node> >& list = other.rectBasedTestResult();
+    ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
+    for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it)
+        m_rectBasedTestResult.add(it->get());
+}
+
 } // namespace WebCore
diff --git a/WebCore/rendering/HitTestResult.h b/WebCore/rendering/HitTestResult.h
index d1906ba..f47e2a5 100644
--- a/WebCore/rendering/HitTestResult.h
+++ b/WebCore/rendering/HitTestResult.h
@@ -21,7 +21,10 @@
 #define HitTestResult_h
 
 #include "IntPoint.h"
+#include "IntRect.h"
+#include "IntSize.h"
 #include "TextDirection.h"
+#include <wtf/ListHashSet.h>
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
@@ -38,6 +41,8 @@ class String;
 class HitTestResult {
 public:
     HitTestResult(const IntPoint&);
+    // Pass a non-negative IntSize value as padding to perform a rect-based hit test.
+    HitTestResult(const IntPoint& centerPoint, const IntSize& padding);
     HitTestResult(const HitTestResult&);
     ~HitTestResult();
     HitTestResult& operator=(const HitTestResult&);
@@ -76,7 +81,21 @@ public:
     bool isLiveLink() const;
     bool isContentEditable() const;
 
+    // Rect-based hit test related methods.
+    bool isRectBasedTest() const { return m_isRectBased; }
+    IntRect rectFromPoint(int x, int y) const;
+    IntRect rectFromPoint(const IntPoint&) const;
+    IntSize padding() const { return m_padding; }
+    int paddingWidth() const { return m_padding.width() >= 0 ? m_padding.width() : 0; }
+    int paddingHeight() const { return m_padding.height() >= 0 ? m_padding.height() : 0; }
+    // Returns true if it is rect-based hit test and needs to continue until the rect is fully
+    // enclosed by the boundaries of a node.
+    bool addNodeToRectBasedTestResult(Node*, int x, int y, const IntRect& rect = IntRect());
+    const ListHashSet<RefPtr<Node> >& rectBasedTestResult() const { return m_rectBasedTestResult; }
+    void append(const HitTestResult&);
+
 private:
+
     RefPtr<Node> m_innerNode;
     RefPtr<Node> m_innerNonSharedNode;
     IntPoint m_point;
@@ -85,8 +104,37 @@ private:
     RefPtr<Element> m_innerURLElement;
     RefPtr<Scrollbar> m_scrollbar;
     bool m_isOverWidget; // Returns true if we are over a widget (and not in the border/padding area of a RenderWidget for example).
+    bool m_isRectBased;
+    IntSize m_padding;
+    ListHashSet<RefPtr<Node> > m_rectBasedTestResult;
 };
 
+inline IntRect HitTestResult::rectFromPoint(int x, int y) const
+{
+    return rectFromPoint(IntPoint(x, y));
+}
+
+// Formula:
+// x = p.x() - padding.width()
+// y = p.y() - padding.height()
+// width = 2 * padding.width() + 1
+// height = 2 * m_padding.height() + 1
+inline IntRect HitTestResult::rectFromPoint(const IntPoint& point) const
+{
+    IntPoint realPoint(point);
+    IntSize realPadding(m_padding);
+
+    // Real IntPoint for the rect.
+    realPadding.clampNegativeToZero();
+    realPoint -= realPadding;
+
+    // Real IntSize for the rect.
+    realPadding.scale(2);
+    realPadding += IntSize(1, 1);
+
+    return IntRect(realPoint, realPadding);
+}
+
 String displayString(const String&, const Node*);
 
 } // namespace WebCore
diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp
index fbfe56d..dfe7561 100644
--- a/WebCore/rendering/InlineFlowBox.cpp
+++ b/WebCore/rendering/InlineFlowBox.cpp
@@ -611,7 +611,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
 {
     IntRect overflowRect(visibleOverflowRect());
     overflowRect.move(tx, ty);
-    if (!overflowRect.contains(x, y))
+    if (!overflowRect.intersects(result.rectFromPoint(x, y)))
         return false;
 
     // Check children first.
@@ -624,9 +624,10 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
 
     // Now check ourselves.
     IntRect rect(tx + m_x, ty + m_y, m_width, height());
-    if (visibleToHitTesting() && rect.contains(x, y)) {
+    if (visibleToHitTesting() && rect.intersects(result.rectFromPoint(x, y))) {
         renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space.
-        return true;
+        if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect))
+            return true;
     }
     
     return false;
diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp
index 8547fe0..50f6cfa 100644
--- a/WebCore/rendering/InlineTextBox.cpp
+++ b/WebCore/rendering/InlineTextBox.cpp
@@ -287,9 +287,10 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in
         return false;
 
     IntRect rect(tx + m_x, ty + m_y, m_width, height());
-    if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.contains(x, y)) {
+    if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.intersects(result.rectFromPoint(x, y))) {
         renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
-        return true;
+        if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect))
+            return true;
     }
     return false;
 }
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index e8b5822..9550ebf 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -3752,19 +3752,22 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
         // Check if we need to do anything at all.
         IntRect overflowBox = visibleOverflowRect();
         overflowBox.move(tx, ty);
-        if (!overflowBox.contains(_x, _y))
+        if (!overflowBox.intersects(result.rectFromPoint(_x, _y)))
             return false;
     }
 
     if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, _x, _y, tx, ty)) {
         updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
-        return true;
+        // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
+        if (!result.addNodeToRectBasedTestResult(node(), _x, _y))
+           return true;
     }
 
     // If we have clipping, then we can't have any spillout.
     bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
     bool useClip = (hasControlClip() || useOverflowClip);
-    bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).contains(_x, _y) : overflowClipRect(tx, ty).contains(_x, _y));
+    IntRect hitTestArea(result.rectFromPoint(_x, _y));
+    bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).intersects(hitTestArea) : overflowClipRect(tx, ty).intersects(hitTestArea));
     if (checkChildren) {
         // Hit test descendants first.
         int scrolledX = tx;
@@ -3812,9 +3815,10 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
     // Now hit test our background
     if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
         IntRect boundsRect(tx, ty, width(), height());
-        if (visibleToHitTesting() && boundsRect.contains(_x, _y)) {
+        if (visibleToHitTesting() && boundsRect.intersects(result.rectFromPoint(_x, _y))) {
             updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
-            return true;
+            if (!result.addNodeToRectBasedTestResult(node(), _x, _y, boundsRect))
+                return true;
         }
     }
 
@@ -3839,13 +3843,16 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r
         currYOffset += colRect.height();
         colRect.move(tx, ty);
         
-        if (colRect.contains(x, y)) {
+        if (colRect.intersects(result.rectFromPoint(x, y))) {
             // The point is inside this column.
             // Adjust tx and ty to change where we hit test.
         
             int finalX = tx + currXOffset;
             int finalY = ty + currYOffset;
-            return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
+            if (result.isRectBasedTest() && !colRect.contains(result.rectFromPoint(x, y)))
+                hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
+            else
+                return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
         }
     }
 
diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp
index 2020003..daf94ea 100644
--- a/WebCore/rendering/RenderBox.cpp
+++ b/WebCore/rendering/RenderBox.cpp
@@ -31,6 +31,7 @@
 #include "Document.h"
 #include "FrameView.h"
 #include "GraphicsContext.h"
+#include "HitTestResult.h"
 #include "htmlediting.h"
 #include "HTMLElement.h"
 #include "HTMLNames.h"
@@ -554,9 +555,11 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result
 
     // Check our bounds next. For this purpose always assume that we can only be hit in the
     // foreground phase (which is true for replaced elements like images).
-    if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) {
+    IntRect boundsRect = IntRect(tx, ty, width(), height());
+    if (visibleToHitTesting() && action == HitTestForeground && boundsRect.intersects(result.rectFromPoint(xPos, yPos))) {
         updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
-        return true;
+        if (!result.addNodeToRectBasedTestResult(node(), xPos, yPos, boundsRect))
+            return true;
     }
 
     return false;
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index 8e7d165..2073479 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -377,10 +377,10 @@ HTMLMapElement* RenderImage::imageMap() const
 
 bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
 {
-    HitTestResult tempResult(result.point());
+    HitTestResult tempResult(result.point(), result.padding());
     bool inside = RenderReplaced::nodeAtPoint(request, tempResult, x, y, tx, ty, hitTestAction);
 
-    if (inside && node()) {
+    if (tempResult.innerNode() && node()) {
         if (HTMLMapElement* map = imageMap()) {
             IntRect contentBox = contentBoxRect();
             float zoom = style()->effectiveZoom();
@@ -391,6 +391,8 @@ bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
         }
     }
 
+    if (!inside && result.isRectBasedTest())
+        result.append(tempResult);
     if (inside)
         result = tempResult;
     return inside;
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index d40a6f8..3417868 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -2739,14 +2739,16 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
 #if USE(ACCELERATED_COMPOSITING)
     useTemporaryClipRects = compositor()->inCompositingMode();
 #endif
-    
+
+    IntRect hitTestArea = result.rectFromPoint(hitTestPoint);
+
     // Apply a transform if we have one.
     if (transform() && !appliedTransform) {
         // Make sure the parent's clip rects have been calculated.
         if (parent()) {
             IntRect clipRect = backgroundClipRect(rootLayer, useTemporaryClipRects);
             // Go ahead and test the enclosing clip now.
-            if (!clipRect.contains(hitTestPoint))
+            if (!clipRect.intersects(hitTestArea))
                 return 0;
         }
 
@@ -2859,17 +2861,21 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
     }
 
     // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
-    if (fgRect.contains(hitTestPoint) && isSelfPaintingLayer()) {
+    if (fgRect.intersects(hitTestArea) && isSelfPaintingLayer()) {
         // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
-        HitTestResult tempResult(result.point());
+        HitTestResult tempResult(result.point(), result.padding());
         if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) &&
             isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
-            result = tempResult;
+            if (result.isRectBasedTest())
+                result.append(tempResult);
+            else
+                result = tempResult;
             if (!depthSortDescendants)
                 return this;
             // Foreground can depth-sort with descendant layers, so keep this as a candidate.
             candidateLayer = this;
-        }
+        } else if (result.isRectBasedTest())
+            result.append(tempResult);
     }
 
     // Now check our negative z-index children.
@@ -2885,13 +2891,17 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
     if (candidateLayer)
         return candidateLayer;
 
-    if (bgRect.contains(hitTestPoint) && isSelfPaintingLayer()) {
-        HitTestResult tempResult(result.point());
+    if (bgRect.intersects(hitTestArea) && isSelfPaintingLayer()) {
+        HitTestResult tempResult(result.point(), result.padding());
         if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) &&
             isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
-            result = tempResult;
+            if (result.isRectBasedTest())
+                result.append(tempResult);
+            else
+                result = tempResult;
             return this;
-        }
+        } else if (result.isRectBasedTest())
+            result.append(tempResult);
     }
     
     return 0;
@@ -2903,8 +2913,9 @@ bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult&
                             layerBounds.x() - renderBoxX(),
                             layerBounds.y() - renderBoxY(), 
                             hitTestFilter)) {
-        // It's wrong to set innerNode, but then claim that you didn't hit anything.
-        ASSERT(!result.innerNode());
+        // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
+        // a rect-based test.
+        ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
         return false;
     }
 
@@ -2938,14 +2949,21 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r
     for (int i = list->size() - 1; i >= 0; --i) {
         RenderLayer* childLayer = list->at(i);
         RenderLayer* hitLayer = 0;
-        HitTestResult tempResult(result.point());
+        HitTestResult tempResult(result.point(), result.padding());
         if (childLayer->isPaginated())
             hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestPoint, transformState, zOffsetForDescendants);
         else
             hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, transformState, zOffsetForDescendants);
+
+        // If it a rect-based test, we can safely append the temporary result since it might had hit
+        // nodes but not necesserily had hitLayer set.
+        if (result.isRectBasedTest())
+            result.append(tempResult);
+
         if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) {
             resultLayer = hitLayer;
-            result = tempResult;
+            if (!result.isRectBasedTest())
+                result = tempResult;
             if (!depthSortDescendants)
                 break;
         }
@@ -3005,7 +3023,7 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend
         IntRect localClipRect(hitTestRect);
         localClipRect.intersect(colRect);
         
-        if (!localClipRect.isEmpty() && localClipRect.contains(hitTestPoint)) {
+        if (!localClipRect.isEmpty() && localClipRect.intersects(result.rectFromPoint(hitTestPoint))) {
             RenderLayer* hitLayer = 0;
             if (!columnIndex) {
                 // Apply a translation transform to change where the layer paints.
diff --git a/WebCore/rendering/RenderLineBoxList.cpp b/WebCore/rendering/RenderLineBoxList.cpp
index 2d27748..4d0dcd6 100644
--- a/WebCore/rendering/RenderLineBoxList.cpp
+++ b/WebCore/rendering/RenderLineBoxList.cpp
@@ -29,6 +29,7 @@
 #include "config.h"
 #include "RenderLineBoxList.h"
 
+#include "HitTestResult.h"
 #include "InlineTextBox.h"
 #include "RenderArena.h"
 #include "RenderInline.h"
@@ -245,14 +246,16 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq
     // contain the point.  This is a quick short-circuit that we can take to avoid walking any lines.
     // FIXME: This check is flawed in the following extremely obscure way:
     // if some line in the middle has a huge overflow, it might actually extend below the last line.
-    if ((y >= ty + lastLineBox()->root()->bottomVisibleOverflow()) || (y < ty + firstLineBox()->root()->topVisibleOverflow()))
+    if (y - result.paddingHeight() >= ty + lastLineBox()->root()->bottomVisibleOverflow()
+     || y + result.paddingHeight() < ty + firstLineBox()->root()->topVisibleOverflow())
         return false;
 
     // See if our root lines contain the point.  If so, then we hit test
     // them further.  Note that boxes can easily overlap, so we can't make any assumptions
     // based off positions of our first line box or our last line box.
     for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) {
-        if (y >= ty + curr->root()->topVisibleOverflow() && y < ty + curr->root()->bottomVisibleOverflow()) {
+        if (y + result.paddingHeight() >= ty + curr->root()->topVisibleOverflow()
+         && y - result.paddingHeight() < ty + curr->root()->bottomVisibleOverflow()) {
             bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty);
             if (inside) {
                 renderer->updateHitTestResult(result, IntPoint(x - tx, y - ty));
diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp
index 7713445..e2dee5f 100644
--- a/WebCore/rendering/RenderSVGRoot.cpp
+++ b/WebCore/rendering/RenderSVGRoot.cpp
@@ -26,6 +26,7 @@
 #include "RenderSVGRoot.h"
 
 #include "GraphicsContext.h"
+#include "HitTestResult.h"
 #include "RenderSVGContainer.h"
 #include "RenderSVGResource.h"
 #include "RenderView.h"
@@ -319,6 +320,8 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
         if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
             // FIXME: CSS/HTML assumes the local point is relative to the border box, right?
             updateHitTestResult(result, pointInBorderBox);
+            // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet.
+            result.addNodeToRectBasedTestResult(child->node(), _x, _y);
             return true;
         }
     }
diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp
index c3b2b2f..bd36ae8 100644
--- a/WebCore/rendering/RenderTable.cpp
+++ b/WebCore/rendering/RenderTable.cpp
@@ -31,6 +31,7 @@
 #include "Document.h"
 #include "FixedTableLayout.h"
 #include "FrameView.h"
+#include "HitTestResult.h"
 #include "HTMLNames.h"
 #include "RenderLayer.h"
 #include "RenderTableCell.h"
@@ -1121,7 +1122,7 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
     ty += y();
 
     // Check kids first.
-    if (!hasOverflowClip() || overflowClipRect(tx, ty).contains(xPos, yPos)) {
+    if (!hasOverflowClip() || overflowClipRect(tx, ty).intersects(result.rectFromPoint(xPos, yPos))) {
         for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
             if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption) &&
                 child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
@@ -1132,9 +1133,11 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
     }
 
     // Check our bounds next.
-    if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) {
+    IntRect boundsRect = IntRect(tx, ty, width(), height());
+    if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && boundsRect.intersects(result.rectFromPoint(xPos, yPos))) {
         updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
-        return true;
+        if (!result.addNodeToRectBasedTestResult(node(), xPos, yPos, boundsRect))
+            return true;
     }
 
     return false;
diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp
index 2517cab..56c9746 100644
--- a/WebCore/rendering/RenderTableSection.cpp
+++ b/WebCore/rendering/RenderTableSection.cpp
@@ -28,6 +28,7 @@
 
 #include "CachedImage.h"
 #include "Document.h"
+#include "HitTestResult.h"
 #include "HTMLNames.h"
 #include "RenderTableCell.h"
 #include "RenderTableCol.h"
@@ -1177,7 +1178,7 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul
     tx += x();
     ty += y();
 
-    if (hasOverflowClip() && !overflowClipRect(tx, ty).contains(xPos, yPos))
+    if (hasOverflowClip() && !overflowClipRect(tx, ty).intersects(result.rectFromPoint(xPos, yPos)))
         return false;
 
     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp
index 6fb2749..6ec5b70 100644
--- a/WebCore/rendering/RenderWidget.cpp
+++ b/WebCore/rendering/RenderWidget.cpp
@@ -394,7 +394,7 @@ bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& res
     bool inside = RenderReplaced::nodeAtPoint(request, result, x, y, tx, ty, action);
     
     // Check to see if we are really over the widget itself (and not just in the border/padding area).
-    if (inside && !hadResult && result.innerNode() == node())
+    if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode() == node())
         result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
     return inside;
 }

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list