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;