Store hit-test rect in HitTestPoint as Rect.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Jun 2012 12:21:28 +0000 (12:21 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Jun 2012 12:21:28 +0000 (12:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=89454

Patch by Allan Sandfeld Jensen <allan.jensen@nokia.com> on 2012-06-23
Reviewed by Darin Adler.

Calculate the rectangle early and store that instead of padding
to avoid recalculating the rectangle for every single element
hit tested.

No change in functionality. No new tests.

* page/EventHandler.cpp:
(WebCore::EventHandler::bestClickableNodeForTouchPoint):
(WebCore::EventHandler::bestZoomableAreaForTouchPoint):
* rendering/HitTestResult.cpp:
(WebCore::HitTestPoint::HitTestPoint):
(WebCore::HitTestPoint::operator=):
(WebCore::HitTestPoint::setPoint):
(WebCore::hitTestPointIntersects):
(WebCore::HitTestPoint::intersects):
(WebCore::HitTestResult::addNodeToRectBasedTestResult):
* rendering/HitTestResult.h:
(HitTestPoint):
(WebCore::HitTestPoint::boundingBox):
(WebCore::HitTestPoint::topPadding):
(WebCore::HitTestPoint::rightPadding):
(WebCore::HitTestPoint::bottomPadding):
(WebCore::HitTestPoint::leftPadding):
(HitTestResult):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::hitTestColumns):
* rendering/RenderTableSection.cpp:
(WebCore::RenderTableSection::nodeAtPoint):

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

Source/WebCore/ChangeLog
Source/WebCore/page/EventHandler.cpp
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/HitTestResult.h
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderTableSection.cpp

index b972b30..4285307 100644 (file)
@@ -1,3 +1,39 @@
+2012-06-23  Allan Sandfeld Jensen  <allan.jensen@nokia.com>
+
+        Store hit-test rect in HitTestPoint as Rect.
+        https://bugs.webkit.org/show_bug.cgi?id=89454
+
+        Reviewed by Darin Adler.
+
+        Calculate the rectangle early and store that instead of padding
+        to avoid recalculating the rectangle for every single element
+        hit tested.
+
+        No change in functionality. No new tests.
+
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::bestClickableNodeForTouchPoint):
+        (WebCore::EventHandler::bestZoomableAreaForTouchPoint):
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestPoint::HitTestPoint):
+        (WebCore::HitTestPoint::operator=):
+        (WebCore::HitTestPoint::setPoint):
+        (WebCore::hitTestPointIntersects):
+        (WebCore::HitTestPoint::intersects):
+        (WebCore::HitTestResult::addNodeToRectBasedTestResult):
+        * rendering/HitTestResult.h:
+        (HitTestPoint):
+        (WebCore::HitTestPoint::boundingBox):
+        (WebCore::HitTestPoint::topPadding):
+        (WebCore::HitTestPoint::rightPadding):
+        (WebCore::HitTestPoint::bottomPadding):
+        (WebCore::HitTestPoint::leftPadding):
+        (HitTestResult):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::hitTestColumns):
+        * rendering/RenderTableSection.cpp:
+        (WebCore::RenderTableSection::nodeAtPoint):
+
 2012-06-22  Benjamin Poulain  <bpoulain@apple.com>
 
         Text with text-overflow:ellipsis and text-align:right is left aligned
index d1b8c12..82f3300 100644 (file)
@@ -2485,7 +2485,7 @@ bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, c
     IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
     HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
 
-    IntRect touchRect = result.rectForPoint(touchCenter);
+    IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
     RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
     return findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
 }
@@ -2496,7 +2496,7 @@ bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, co
     IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
     HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
 
-    IntRect touchRect = result.rectForPoint(touchCenter);
+    IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
     RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
     return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, *nodeList.get());
 }
index 657b6ec..541f5d0 100644 (file)
@@ -49,41 +49,27 @@ namespace WebCore {
 using namespace HTMLNames;
 
 HitTestPoint::HitTestPoint()
-    : m_topPadding(0)
-    , m_rightPadding(0)
-    , m_bottomPadding(0)
-    , m_leftPadding(0)
-    , m_isRectBased(false)
+    : m_isRectBased(false)
 {
 }
 
 HitTestPoint::HitTestPoint(const LayoutPoint& point)
     : m_point(point)
-    , m_topPadding(0)
-    , m_rightPadding(0)
-    , m_bottomPadding(0)
-    , m_leftPadding(0)
+    , m_boundingBox(rectForPoint(point, 0, 0, 0, 0))
     , m_isRectBased(false)
 {
 }
 
 HitTestPoint::HitTestPoint(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
     : m_point(centerPoint)
-    , m_topPadding(topPadding)
-    , m_rightPadding(rightPadding)
-    , m_bottomPadding(bottomPadding)
-    , m_leftPadding(leftPadding)
+    , m_boundingBox(rectForPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding))
+    , m_isRectBased(topPadding || rightPadding || bottomPadding || leftPadding)
 {
-    // If all padding values passed in are zero then it is not a rect based hit test.
-    m_isRectBased = topPadding || rightPadding || bottomPadding || leftPadding;
 }
 
 HitTestPoint::HitTestPoint(const HitTestPoint& other)
     : m_point(other.m_point)
-    , m_topPadding(other.m_topPadding)
-    , m_rightPadding(other.m_rightPadding)
-    , m_bottomPadding(other.m_bottomPadding)
-    , m_leftPadding(other.m_leftPadding)
+    , m_boundingBox(other.m_boundingBox)
     , m_isRectBased(other.m_isRectBased)
 {
 }
@@ -95,15 +81,43 @@ HitTestPoint::~HitTestPoint()
 HitTestPoint& HitTestPoint::operator=(const HitTestPoint& other)
 {
     m_point = other.m_point;
-    m_topPadding = other.m_topPadding;
-    m_rightPadding = other.m_rightPadding;
-    m_bottomPadding = other.m_bottomPadding;
-    m_leftPadding = other.m_leftPadding;
+    m_boundingBox = other.m_boundingBox;
     m_isRectBased = other.m_isRectBased;
 
     return *this;
 }
 
+void HitTestPoint::setPoint(const LayoutPoint& point)
+{
+    m_boundingBox.move(roundedIntPoint(point) - roundedIntPoint(m_point));
+    m_point = point;
+}
+
+template<typename RectType>
+bool hitTestPointIntersects(const HitTestPoint& hitTestPoint, const RectType& rect)
+{
+    // FIXME: When the hit test is not rect based we should use rect.contains(m_point).
+    // That does change some corner case tests though.
+
+    // First check if rect even intersects our bounding rect.
+    if (!rect.intersects(hitTestPoint.boundingBox()))
+        return false;
+
+    // FIXME: Implement quad based intersection test to handle transformed hit test rectangles.
+    return true;
+
+}
+
+bool HitTestPoint::intersects(const LayoutRect& rect) const
+{
+    return hitTestPointIntersects(*this, rect);
+}
+
+bool HitTestPoint::intersects(const FloatRect& rect) const
+{
+    return hitTestPointIntersects(*this, rect);
+}
+
 IntRect HitTestPoint::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
 {
     IntPoint actualPoint(roundedIntPoint(point));
@@ -606,7 +620,7 @@ bool HitTestResult::isContentEditable() const
     return m_innerNonSharedNode->rendererIsEditable();
 }
 
-bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint& pointInContainer, const IntRect& rect)
+bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint& pointInContainer, const LayoutRect& rect)
 {
     // If it is not a rect-based hit test, this method has to be no-op.
     // Return false, so the hit test stops.
@@ -622,7 +636,7 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint&
 
     mutableRectBasedTestResult().add(node);
 
-    bool regionFilled = rect.contains(rectForPoint(pointInContainer.point()));
+    bool regionFilled = rect.contains(pointInContainer.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()) {
@@ -657,7 +671,7 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint&
 
     mutableRectBasedTestResult().add(node);
 
-    bool regionFilled = rect.contains(rectForPoint(pointInContainer.point()));
+    bool regionFilled = rect.contains(pointInContainer.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()) {
index 10ff594..affab95 100644 (file)
@@ -51,7 +51,7 @@ public:
 
     HitTestPoint();
     HitTestPoint(const LayoutPoint&);
-    // Pass non-negative padding values to perform a rect-based hit test.
+    // Pass non-zero padding values to perform a rect-based hit test.
     HitTestPoint(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
     HitTestPoint(const HitTestPoint&);
     ~HitTestPoint();
@@ -60,27 +60,25 @@ public:
     LayoutPoint point() const { return m_point; }
     IntPoint roundedPoint() const { return roundedIntPoint(m_point); }
 
-    void setPoint(const LayoutPoint& p) { m_point = p; }
+    void setPoint(const LayoutPoint&);
 
     // Rect-based hit test related methods.
     bool isRectBasedTest() const { return m_isRectBased; }
-    IntRect rectForPoint(const LayoutPoint&) const;
+    IntRect boundingBox() const { return m_boundingBox; }
+
     static IntRect rectForPoint(const LayoutPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding);
-    int topPadding() const { return m_topPadding; }
-    int rightPadding() const { return m_rightPadding; }
-    int bottomPadding() const { return m_bottomPadding; }
-    int leftPadding() const { return m_leftPadding; }
+    int topPadding() const { return roundedPoint().y() - m_boundingBox.y(); }
+    int rightPadding() const { return m_boundingBox.maxX() - roundedPoint().x() - 1; }
+    int bottomPadding() const { return m_boundingBox.maxY() - roundedPoint().y() - 1; }
+    int leftPadding() const { return roundedPoint().x() - m_boundingBox.x(); }
 
-    bool intersects(const LayoutRect& rect) const { return rect.intersects(rectForPoint(m_point)); }
-    bool intersects(const FloatRect& rect) const { return rect.intersects(rectForPoint(m_point)); }
+    bool intersects(const LayoutRect&) const;
+    bool intersects(const FloatRect&) const;
 
 private:
     LayoutPoint m_point;
 
-    int m_topPadding;
-    int m_rightPadding;
-    int m_bottomPadding;
-    int m_leftPadding;
+    IntRect m_boundingBox;
     bool m_isRectBased;
 };
 
@@ -151,7 +149,7 @@ public:
 
     // 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*, const HitTestPoint& pointInContainer, const IntRect& = IntRect());
+    bool addNodeToRectBasedTestResult(Node*, const HitTestPoint& pointInContainer, const LayoutRect& = LayoutRect());
     bool addNodeToRectBasedTestResult(Node*, const HitTestPoint& pointInContainer, const FloatRect&);
     void append(const HitTestResult&);
 
@@ -184,16 +182,6 @@ private:
     mutable OwnPtr<NodeSet> m_rectBasedTestResult;
 };
 
-// Formula:
-// x = p.x() - rightPadding
-// y = p.y() - topPadding
-// width = leftPadding + rightPadding + 1
-// height = topPadding + bottomPadding + 1
-inline IntRect HitTestPoint::rectForPoint(const LayoutPoint& point) const
-{
-    return rectForPoint(point, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding);
-}
-
 String displayString(const String&, const Node*);
 
 } // namespace WebCore
index 8973ea8..1947a3c 100755 (executable)
@@ -4706,7 +4706,7 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r
         return false;
 
     for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
-        LayoutRect hitRect = result.rectForPoint(pointInContainer.point());
+        LayoutRect hitRect = pointInContainer.boundingBox();
         LayoutRect colRect = it.columnRect();
         colRect.moveBy(accumulatedOffset);
         if (pointInContainer.intersects(colRect)) {
index 1a13d8c..09a63b9 100644 (file)
@@ -1393,7 +1393,7 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul
 
     recalcCellsIfNeeded();
 
-    LayoutRect hitTestRect = result.rectForPoint(pointInContainer.point());
+    LayoutRect hitTestRect = pointInContainer.boundingBox();
     hitTestRect.moveBy(-adjustedLocation);
 
     LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(hitTestRect);