2009-03-10  Simon Fraser  <simon.fraser@apple.com>

        Reviewed by Darin Adler

        https://bugs.webkit.org/show_bug.cgi?id=24503

        Fix hit testing of absolutely positioned single line text controls by
        ensuring that we set result.innerNode() correctly. If the hit node is
        a descendant of the inner text element or if it is the <input> itself,
        then we say we hit the innerTextElement.

        Rename hitInnerTextBlock() to hitInnerTextElement() to match the
        'innerTextElement' terminology used elsewhere.

        Assert that if renderer()->hitTest() returns false, no-one set
        result.innerNode().

        Test: fast/forms/search-abs-pos-cancel-button.html

        * rendering/RenderLayer.cpp:
        (WebCore::RenderLayer::hitTestContents):
        * rendering/RenderTextControl.cpp:
        (WebCore::RenderTextControl::hitInnerTextElement):
        * rendering/RenderTextControl.h:
        * rendering/RenderTextControlMultiLine.cpp:
        (WebCore::RenderTextControlMultiLine::nodeAtPoint):
        * rendering/RenderTextControlSingleLine.cpp:
        (WebCore::RenderTextControlSingleLine::nodeAtPoint):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@41576 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index 6eb789e..aae7800 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -2400,8 +2400,11 @@
     if (!renderer()->hitTest(request, result, hitTestPoint,
                             layerBounds.x() - renderBoxX(),
                             layerBounds.y() - renderBoxY(), 
-                            hitTestFilter))
+                            hitTestFilter)) {
+        // It's wrong to set innerNode, but then claim that you didn't hit anything.
+        ASSERT(!result.innerNode());
         return false;
+    }
 
     // For positioned generated content, we might still not have a
     // node by the time we get to the layer level, since none of
diff --git a/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp
index 32d8290..d359596 100644
--- a/WebCore/rendering/RenderTextControl.cpp
+++ b/WebCore/rendering/RenderTextControl.cpp
@@ -451,7 +451,7 @@
     RenderBlock::calcHeight();
 }
 
-void RenderTextControl::hitInnerTextBlock(HitTestResult& result, int xPos, int yPos, int tx, int ty)
+void RenderTextControl::hitInnerTextElement(HitTestResult& result, int xPos, int yPos, int tx, int ty)
 {
     result.setInnerNode(m_innerText.get());
     result.setLocalPoint(IntPoint(xPos - tx - x() - m_innerText->renderBox()->x(),
diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h
index dfeaa2b..1c20f7d 100644
--- a/WebCore/rendering/RenderTextControl.h
+++ b/WebCore/rendering/RenderTextControl.h
@@ -92,7 +92,7 @@
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
 
     void createSubtreeIfNeeded(TextControlInnerElement* innerBlock);
-    void hitInnerTextBlock(HitTestResult&, int x, int y, int tx, int ty);
+    void hitInnerTextElement(HitTestResult&, int x, int y, int tx, int ty);
     void forwardEvent(Event*);
 
     int textBlockWidth() const;
diff --git a/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp
index 9eb3fa3..9ce6941 100644
--- a/WebCore/rendering/RenderTextControlMultiLine.cpp
+++ b/WebCore/rendering/RenderTextControlMultiLine.cpp
@@ -84,7 +84,7 @@
         return false;
 
     if (result.innerNode() == node())
-        hitInnerTextBlock(result, x, y, tx, ty);
+        hitInnerTextElement(result, x, y, tx, ty);
 
     return true;
 }
diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp
index ca885f8..0e84aaf 100644
--- a/WebCore/rendering/RenderTextControlSingleLine.cpp
+++ b/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -270,12 +270,14 @@
     if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction))
         return false;
 
-    if (result.innerNode() != node() && result.innerNode() != innerTextElement())
-        return false;
+    // If we hit a node inside the inner text element, say that we hit that element,
+    // and if we hit our node (e.g. we're over the border or padding), also say that we hit the
+    // inner text element so that it gains focus.
+    if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node())
+        hitInnerTextElement(result, xPos, yPos, tx, ty);
 
-    hitInnerTextBlock(result, xPos, yPos, tx, ty);
-
-    if (!m_innerBlock)
+    // If we're not a search field, or we already found the results or cancel buttons, we're done.
+    if (!m_innerBlock || result.innerNode() == m_resultsButton || result.innerNode() == m_cancelButton)
         return true;
 
     Node* innerNode = 0;