Commit 6a2ac52c authored by hyatt's avatar hyatt

Rework positionForCoordinates to be more efficient and to handle...

        Rework positionForCoordinates to be more efficient and to handle multi-column content.  This entailed
        adding a new field to HitTestResult called localPoint that cached the mouse coordinate in the coordinate
        space of the renderer.

        positionForCoordinates now takes local coordinates and so no longer needs to waste time recomputing
        absolute positions over and over again.

        Reviewed by darin

        * bridge/mac/WebCoreAXObject.mm:
        (-[WebCoreAXObject value]):
        (-[WebCoreAXObject doAXTextMarkerRangeForLine:]):
        (-[WebCoreAXObject doAXTextMarkerForPosition:]):
        * dom/Document.cpp:
        (WebCore::Document::prepareMouseEvent):
        * editing/SelectionController.cpp:
        (WebCore::SelectionController::contains):
        * editing/visible_units.cpp:
        (WebCore::previousLinePosition):
        (WebCore::nextLinePosition):
        * page/EventHandler.cpp:
        (WebCore::EventHandler::selectClosestWordFromMouseEvent):
        (WebCore::EventHandler::handleMousePressEventDoubleClick):
        (WebCore::EventHandler::handleMousePressEventTripleClick):
        (WebCore::EventHandler::handleMousePressEventSingleClick):
        (WebCore::EventHandler::handleMouseMoveEvent):
        (WebCore::EventHandler::handleMouseReleaseEvent):
        (WebCore::EventHandler::sendContextMenuEvent):
        * page/EventHandler.h:
        * page/MouseEventWithHitTestResults.cpp:
        (WebCore::MouseEventWithHitTestResults::MouseEventWithHitTestResults):
        * page/MouseEventWithHitTestResults.h:
        (WebCore::MouseEventWithHitTestResults::localPoint):
        * page/mac/WebCoreFrameBridge.mm:
        (-[WebCoreFrameBridge _visiblePositionForPoint:]):
        * rendering/EllipsisBox.cpp:
        (WebCore::EllipsisBox::nodeAtPoint):
        * rendering/HitTestResult.h:
        (WebCore::HitTestResult::localPoint):
        (WebCore::HitTestResult::setLocalPoint):
        * rendering/InlineFlowBox.cpp:
        (WebCore::InlineFlowBox::nodeAtPoint):
        * rendering/InlineTextBox.cpp:
        (WebCore::InlineTextBox::nodeAtPoint):
        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::nodeAtPoint):
        (WebCore::RenderBlock::hitTestContents):
        (WebCore::RenderBlock::positionForCoordinates):
        * rendering/RenderBox.cpp:
        (WebCore::RenderBox::nodeAtPoint):
        * rendering/RenderContainer.cpp:
        (WebCore::RenderContainer::positionForCoordinates):
        * rendering/RenderFlow.cpp:
        (WebCore::RenderFlow::hitTestLines):
        * rendering/RenderInline.cpp:
        (WebCore::RenderInline::positionForCoordinates):
        * rendering/RenderLayer.cpp:
        (WebCore::RenderLayer::autoscroll):
        (WebCore::RenderLayer::hitTestLayer):
        * rendering/RenderObject.cpp:
        (WebCore::RenderObject::updateHitTestResult):
        * rendering/RenderObject.h:
        * rendering/RenderPath.cpp:
        (WebCore::RenderPath::nodeAtPoint):
        * rendering/RenderReplaced.cpp:
        (WebCore::RenderReplaced::positionForCoordinates):
        * rendering/RenderTableRow.cpp:
        (WebCore::RenderTableRow::nodeAtPoint):
        * rendering/RenderTableSection.cpp:
        (WebCore::RenderTableSection::nodeAtPoint):
        * rendering/RenderText.cpp:
        (WebCore::RenderText::positionForCoordinates):
        * rendering/RootInlineBox.cpp:
        (WebCore::RootInlineBox::nodeAtPoint):
        (WebCore::RootInlineBox::closestLeafChildForXPos):
        * rendering/RootInlineBox.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@18758 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 15d2d71f
2007-01-10 David Hyatt <hyatt@apple.com>
Rework positionForCoordinates to be more efficient and to handle multi-column content. This entailed
adding a new field to HitTestResult called localPoint that cached the mouse coordinate in the coordinate
space of the renderer.
positionForCoordinates now takes local coordinates and so no longer needs to waste time recomputing
absolute positions over and over again.
Reviewed by darin
* bridge/mac/WebCoreAXObject.mm:
(-[WebCoreAXObject value]):
(-[WebCoreAXObject doAXTextMarkerRangeForLine:]):
(-[WebCoreAXObject doAXTextMarkerForPosition:]):
* dom/Document.cpp:
(WebCore::Document::prepareMouseEvent):
* editing/SelectionController.cpp:
(WebCore::SelectionController::contains):
* editing/visible_units.cpp:
(WebCore::previousLinePosition):
(WebCore::nextLinePosition):
* page/EventHandler.cpp:
(WebCore::EventHandler::selectClosestWordFromMouseEvent):
(WebCore::EventHandler::handleMousePressEventDoubleClick):
(WebCore::EventHandler::handleMousePressEventTripleClick):
(WebCore::EventHandler::handleMousePressEventSingleClick):
(WebCore::EventHandler::handleMouseMoveEvent):
(WebCore::EventHandler::handleMouseReleaseEvent):
(WebCore::EventHandler::sendContextMenuEvent):
* page/EventHandler.h:
* page/MouseEventWithHitTestResults.cpp:
(WebCore::MouseEventWithHitTestResults::MouseEventWithHitTestResults):
* page/MouseEventWithHitTestResults.h:
(WebCore::MouseEventWithHitTestResults::localPoint):
* page/mac/WebCoreFrameBridge.mm:
(-[WebCoreFrameBridge _visiblePositionForPoint:]):
* rendering/EllipsisBox.cpp:
(WebCore::EllipsisBox::nodeAtPoint):
* rendering/HitTestResult.h:
(WebCore::HitTestResult::localPoint):
(WebCore::HitTestResult::setLocalPoint):
* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::nodeAtPoint):
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::nodeAtPoint):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::nodeAtPoint):
(WebCore::RenderBlock::hitTestContents):
(WebCore::RenderBlock::positionForCoordinates):
* rendering/RenderBox.cpp:
(WebCore::RenderBox::nodeAtPoint):
* rendering/RenderContainer.cpp:
(WebCore::RenderContainer::positionForCoordinates):
* rendering/RenderFlow.cpp:
(WebCore::RenderFlow::hitTestLines):
* rendering/RenderInline.cpp:
(WebCore::RenderInline::positionForCoordinates):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::autoscroll):
(WebCore::RenderLayer::hitTestLayer):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::updateHitTestResult):
* rendering/RenderObject.h:
* rendering/RenderPath.cpp:
(WebCore::RenderPath::nodeAtPoint):
* rendering/RenderReplaced.cpp:
(WebCore::RenderReplaced::positionForCoordinates):
* rendering/RenderTableRow.cpp:
(WebCore::RenderTableRow::nodeAtPoint):
* rendering/RenderTableSection.cpp:
(WebCore::RenderTableSection::nodeAtPoint):
* rendering/RenderText.cpp:
(WebCore::RenderText::positionForCoordinates):
* rendering/RootInlineBox.cpp:
(WebCore::RootInlineBox::nodeAtPoint):
(WebCore::RootInlineBox::closestLeafChildForXPos):
* rendering/RootInlineBox.h:
2007-01-11 George Staikos <staikos@kde.org>
Reviewed by Maciej.
......
......@@ -579,8 +579,8 @@ static int headingLevel(RenderObject* renderer)
return nil;
// FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here
VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates (0, 0);
VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates (LONG_MAX, LONG_MAX);
VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0);
VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates(LONG_MAX, LONG_MAX);
if (startVisiblePosition.isNull() || endVisiblePosition.isNull())
return nil;
......@@ -1221,7 +1221,7 @@ static IntRect boundingBoxRect(RenderObject* obj)
// iterate over the lines
// NOTE: BUG this is wrong when lineNumber is lineCount+1, because nextLinePosition takes you to the
// last offset of the last line
VisiblePosition visiblePos = [self topRenderer]->positionForCoordinates (0, 0);
VisiblePosition visiblePos = [self topRenderer]->positionForCoordinates(0, 0);
VisiblePosition savedVisiblePos;
while (--lineCount != 0) {
savedVisiblePos = visiblePos;
......@@ -1266,21 +1266,23 @@ static IntRect boundingBoxRect(RenderObject* obj)
NSView* view = docView->getDocumentView();
RenderObject* renderer = [self topRenderer];
Node* innerNode = NULL;
NSPoint ourpoint;
// locate the node containing the point
IntPoint pointResult;
while (1) {
// ask the document layer to hitTest
NSPoint windowCoord = [[view window] convertScreenToBase: point];
ourpoint = [view convertPoint:windowCoord fromView:nil];
IntPoint ourpoint([view convertPoint:windowCoord fromView:nil]);
HitTestRequest request(true, true);
HitTestResult result = HitTestResult(IntPoint(ourpoint));
HitTestResult result(ourpoint);
renderer->layer()->hitTest(request, result);
innerNode = result.innerNode();
if (!innerNode || !innerNode->renderer())
return nil;
pointResult = result.localPoint();
// done if hit something other than a widget
renderer = innerNode->renderer();
if (!renderer->isWidget())
......@@ -1302,7 +1304,7 @@ static IntRect boundingBoxRect(RenderObject* obj)
}
// get position within the node
VisiblePosition pos = innerNode->renderer()->positionForCoordinates ((int)ourpoint.x, (int)ourpoint.y);
VisiblePosition pos = innerNode->renderer()->positionForPoint(pointResult);
return (id) [self textMarkerForVisiblePosition:pos];
}
......
......@@ -1663,7 +1663,7 @@ MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r
ASSERT(!renderer() || renderer()->isRenderView());
if (!renderer())
return MouseEventWithHitTestResults(event, 0, 0, false);
return MouseEventWithHitTestResults(event, 0, IntPoint(), 0, false);
HitTestResult result(documentPoint);
renderer()->layer()->hitTest(request, result);
......@@ -1672,7 +1672,7 @@ MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r
updateRendering();
bool isOverLink = result.URLElement() && !result.URLElement()->getAttribute(hrefAttr).isNull();
return MouseEventWithHitTestResults(event, result.innerNode(), result.scrollbar(), isOverLink);
return MouseEventWithHitTestResults(event, result.innerNode(), result.localPoint(), result.scrollbar(), isOverLink);
}
// DOM Section 1.1.1
......
......@@ -1007,7 +1007,7 @@ bool SelectionController::contains(const IntPoint& point)
if (!innerNode || !innerNode->renderer())
return false;
Position pos(innerNode->renderer()->positionForPoint(point).deepEquivalent());
Position pos(innerNode->renderer()->positionForPoint(result.localPoint()).deepEquivalent());
if (pos.isNull())
return false;
......
......@@ -443,15 +443,16 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
}
if (root) {
// FIXME: Can be wrong for multi-column layout.
int absx, absy;
containingBlock->absolutePositionForContent(absx, absy);
if (containingBlock->hasOverflowClip())
containingBlock->layer()->subtractScrollOffset(absx, absy);
RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
RenderObject *renderer = root->closestLeafChildForXPos(x - absx)->object();
Node* node = renderer->element();
if (editingIgnoresContent(node))
return Position(node->parent(), node->nodeIndex());
return renderer->positionForCoordinates(x, absy + root->topOverflow());
return renderer->positionForCoordinates(x - absx, root->topOverflow());
}
// Could not find a previous line. This means we must already be on the first line.
......@@ -512,15 +513,16 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
}
if (root) {
// FIXME: Can be wrong for multi-column layout.
int absx, absy;
containingBlock->absolutePositionForContent(absx, absy);
if (containingBlock->hasOverflowClip())
containingBlock->layer()->subtractScrollOffset(absx, absy);
RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
RenderObject *renderer = root->closestLeafChildForXPos(x - absx)->object();
Node* node = renderer->element();
if (editingIgnoresContent(node))
return Position(node->parent(), node->nodeIndex());
return renderer->positionForCoordinates(x, absy + root->topOverflow());
return renderer->positionForCoordinates(x - absx, root->topOverflow());
}
// Could not find a next line. This means we must already be on the last line.
......
......@@ -125,13 +125,13 @@ void EventHandler::clear()
m_mousePressed = false;
}
void EventHandler::selectClosestWordFromMouseEvent(const PlatformMouseEvent& mouse, Node *innerNode)
void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
{
Node* innerNode = result.targetNode();
Selection newSelection;
if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect && innerNode->renderer()->shouldSelect()) {
IntPoint vPoint = m_frame->view()->windowToContents(mouse.pos());
VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
if (pos.isNotNull()) {
newSelection = Selection(pos);
newSelection.expandUsingGranularity(WordGranularity);
......@@ -160,7 +160,7 @@ bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestR
// from setting caret selection.
m_beganSelectingText = true;
else
selectClosestWordFromMouseEvent(event.event(), event.targetNode());
selectClosestWordFromMouseEvent(event);
return true;
}
......@@ -176,8 +176,7 @@ bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR
return false;
Selection newSelection;
IntPoint vPoint = m_frame->view()->windowToContents(event.event().pos());
VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
if (pos.isNotNull()) {
newSelection = Selection(pos);
newSelection.expandUsingGranularity(ParagraphGranularity);
......@@ -212,7 +211,7 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR
if (!extendSelection && m_frame->selectionController()->contains(vPoint))
return false;
VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(vPoint));
VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
if (visiblePos.isNull())
visiblePos = VisiblePosition(innerNode, innerNode->caretMinOffset(), DOWNSTREAM);
Position pos = visiblePos.deepEquivalent();
......@@ -323,8 +322,7 @@ bool EventHandler::handleMouseMoveEvent(const MouseEventWithHitTestResults& even
return false;
// handle making selection
IntPoint vPoint = m_frame->view()->windowToContents(event.event().pos());
VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
updateSelectionForMouseDragOverPosition(pos);
......@@ -378,8 +376,7 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e
Selection newSelection;
Node *node = event.targetNode();
if (node && node->isContentEditable() && node->renderer()) {
IntPoint vPoint = m_frame->view()->windowToContents(event.event().pos());
VisiblePosition pos = node->renderer()->positionForPoint(vPoint);
VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
newSelection = Selection(pos);
}
if (m_frame->shouldChangeSelection(newSelection))
......@@ -1128,7 +1125,7 @@ bool EventHandler::sendContextMenuEvent(PlatformMouseEvent event)
(m_frame->editor()->selectWordBeforeMenuEvent() || m_frame->editor()->clientIsEditable()
|| (mev.targetNode() && mev.targetNode()->isContentEditable()))) {
m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
selectClosestWordFromMouseEvent(event, mev.targetNode());
selectClosestWordFromMouseEvent(mev);
}
return swallowEvent;
......
......@@ -147,7 +147,7 @@ public:
#endif
private:
void selectClosestWordFromMouseEvent(const PlatformMouseEvent&, Node* innerNode);
void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& event);
bool handleMouseDoubleClickEvent(const PlatformMouseEvent&);
......
......@@ -35,10 +35,11 @@ static inline Element* targetElement(Node* node)
}
MouseEventWithHitTestResults::MouseEventWithHitTestResults(const PlatformMouseEvent& event,
PassRefPtr<Node> node, PlatformScrollbar* scrollbar, bool isOverLink)
PassRefPtr<Node> node, const IntPoint& localPoint, PlatformScrollbar* scrollbar, bool isOverLink)
: m_event(event)
, m_targetNode(node)
, m_targetElement(targetElement(m_targetNode.get()))
, m_localPoint(localPoint)
, m_scrollbar(scrollbar)
, m_isOverLink(isOverLink)
{
......
......@@ -28,12 +28,14 @@ namespace WebCore {
class PlatformScrollbar;
// FIXME: Why doesn't this class just cache a HitTestResult instead of copying all of HitTestResult's fields over?
class MouseEventWithHitTestResults {
public:
MouseEventWithHitTestResults(const PlatformMouseEvent&, PassRefPtr<Node>, PlatformScrollbar*, bool isOverLink);
MouseEventWithHitTestResults(const PlatformMouseEvent&, PassRefPtr<Node>, const IntPoint& localPoint, PlatformScrollbar*, bool isOverLink);
const PlatformMouseEvent& event() const { return m_event; }
Node* targetNode() const;
const IntPoint& localPoint() const { return m_localPoint; }
PlatformScrollbar* scrollbar() const { return m_scrollbar; }
bool isOverLink() const { return m_isOverLink; }
......@@ -41,6 +43,7 @@ private:
PlatformMouseEvent m_event;
RefPtr<Node> m_targetNode;
RefPtr<Element> m_targetElement;
IntPoint m_localPoint;
PlatformScrollbar* m_scrollbar;
bool m_isOverLink;
};
......
......@@ -1205,16 +1205,14 @@ static HTMLFormElement *formElementFromDOMElement(DOMElement *element)
- (VisiblePosition)_visiblePositionForPoint:(NSPoint)point
{
IntPoint outerPoint(point);
Node* node = m_frame->eventHandler()->hitTestResultAtPoint(outerPoint, true).innerNode();
HitTestResult result = m_frame->eventHandler()->hitTestResultAtPoint(outerPoint, true);
Node* node = result.innerNode();
if (!node)
return VisiblePosition();
RenderObject* renderer = node->renderer();
if (!renderer)
return VisiblePosition();
FrameView* outerView = m_frame->view();
FrameView* innerView = node->document()->view();
IntPoint innerPoint = innerView->windowToContents(outerView->contentsToWindow(outerPoint));
VisiblePosition visiblePos = renderer->positionForCoordinates(innerPoint.x(), innerPoint.y());
VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y());
if (visiblePos.isNull())
visiblePos = VisiblePosition(Position(node, 0));
return visiblePos;
......
......@@ -71,13 +71,13 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
int mtx = tx + m_width - m_markupBox->xPos();
int mty = ty + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline());
if (m_markupBox->nodeAtPoint(request, result, x, y, mtx, mty)) {
object()->setInnerNode(result);
object()->updateHitTestResult(result, IntPoint(x - mtx, y - mty));
return true;
}
}
if (object()->style()->visibility() == VISIBLE && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
object()->setInnerNode(result);
object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
return true;
}
......
......@@ -46,12 +46,14 @@ public:
Node* innerNode() const { return m_innerNode.get(); }
Node* innerNonSharedNode() const { return m_innerNonSharedNode.get(); }
IntPoint point() const { return m_point; }
IntPoint localPoint() const { return m_localPoint; }
Element* URLElement() const { return m_innerURLElement.get(); }
PlatformScrollbar* scrollbar() const { return m_scrollbar.get(); }
void setInnerNode(Node*);
void setInnerNonSharedNode(Node*);
void setPoint(const IntPoint& p) { m_point = p; }
void setLocalPoint(const IntPoint& p) { m_localPoint = p; }
void setURLElement(Element*);
void setScrollbar(PlatformScrollbar*);
......@@ -73,6 +75,8 @@ private:
RefPtr<Node> m_innerNode;
RefPtr<Node> m_innerNonSharedNode;
IntPoint m_point;
IntPoint m_localPoint; // A point in the local coordinate space of m_innerNonSharedNode's renderer. Allows us to efficiently
// determine where inside the renderer we hit on subsequent operations.
RefPtr<Element> m_innerURLElement;
RefPtr<PlatformScrollbar> m_scrollbar;
};
......
......@@ -534,7 +534,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
// Check children first.
for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
if (!curr->object()->layer() && curr->nodeAtPoint(request, result, x, y, tx, ty)) {
object()->setInnerNode(result);
object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
return true;
}
}
......@@ -542,7 +542,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
// Now check ourselves.
IntRect rect(tx + m_x, ty + m_y, m_width, m_height);
if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
object()->setInnerNode(result);
object()->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;
}
......
......@@ -248,7 +248,7 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
IntRect rect(tx + m_x, ty + m_y, m_width, m_height);
if (m_truncation != cFullTruncation && object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
object()->setInnerNode(result);
object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
return true;
}
return false;
......
This diff is collapsed.
......@@ -282,6 +282,8 @@ public:
virtual bool hasColumns() const { return m_columnCount > 1; }
void adjustRectForColumns(IntRect&) const;
private:
void adjustPointToColumnContents(IntPoint&) const;
protected:
void newLine();
......
......@@ -272,7 +272,7 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result
// table-specific hit-test method (which we should do for performance reasons anyway),
// then we can remove this check.
if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) {
setInnerNode(result);
updateHitTestResult(result, IntPoint(x - tx, y - ty));
return true;
}
}
......@@ -280,7 +280,7 @@ 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 (action == HitTestForeground && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
setInnerNode(result);
updateHitTestResult(result, IntPoint(x - tx, y - ty));
return true;
}
......
......@@ -539,16 +539,11 @@ VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
return VisiblePosition(element(), 0, DOWNSTREAM);
if (isTable() && element()) {
int absx, absy;
absolutePositionForContent(absx, absy);
int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
int left = absx;
int right = left + contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
int top = absy;
int bottom = top + contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
if (x < left || x > right || y < top || y > bottom) {
if (x <= (left + right) / 2)
if (x < 0 || x > right || y < 0 || y > bottom) {
if (x <= right / 2)
return VisiblePosition(Position(element(), 0));
else
return VisiblePosition(Position(element(), maxDeepOffset(element())));
......@@ -558,22 +553,28 @@ VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
// Pass off to the closest child.
int minDist = INT_MAX;
RenderObject* closestRenderer = 0;
int newX = x;
int newY = y;
if (isTableRow()) {
newX += xPos();
newY += yPos();
}
for (RenderObject* renderer = m_firstChild; renderer; renderer = renderer->nextSibling()) {
if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow()
|| renderer->style()->visibility() != VISIBLE)
continue;
int absx, absy;
renderer->absolutePositionForContent(absx, absy);
int top = absy + borderTop() + paddingTop();
int top = borderTop() + paddingTop() + isTableRow() ? 0 : renderer->xPos();
int bottom = top + renderer->contentHeight();
int left = absx + borderLeft() + paddingLeft();
int left = borderLeft() + paddingLeft() + isTableRow() ? 0 : renderer->yPos();
int right = left + renderer->contentWidth();
if (x <= right && x >= left && y <= top && y >= bottom)
return renderer->positionForCoordinates(x, y);
if (x <= right && x >= left && y <= top && y >= bottom) {
if (renderer->isTableRow())
return renderer->positionForCoordinates(x + newX - renderer->xPos(), y + newY - renderer->yPos());
return renderer->positionForCoordinates(x - renderer->xPos(), y - renderer->yPos());
}
// Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
// and use a different compare depending on which piece (x, y) is in.
IntPoint cmp;
......@@ -609,7 +610,7 @@ VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
}
if (closestRenderer)
return closestRenderer->positionForCoordinates(x, y);
return closestRenderer->positionForCoordinates(newX - closestRenderer->xPos(), newY - closestRenderer->yPos());
return VisiblePosition(element(), 0, DOWNSTREAM);
}
......
......@@ -433,7 +433,7 @@ bool RenderFlow::hitTestLines(const HitTestRequest& request, HitTestResult& resu
if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) {
bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty);
if (inside) {
setInnerNode(result);
updateHitTestResult(result, IntPoint(x - tx, y - ty));
return true;
}
}
......
......@@ -354,9 +354,16 @@ bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& res
VisiblePosition RenderInline::positionForCoordinates(int x, int y)
{
// Translate the coords from the pre-anonymous block to the post-anonymous block.
RenderBlock* cb = containingBlock();
int parentBlockX = cb->xPos() + x;
int parentBlockY = cb->yPos() + y;
for (RenderObject* c = continuation(); c; c = c->continuation()) {
RenderObject* contBlock = c;
if (c->isInline())
contBlock = c->containingBlock();
if (c->isInline() || c->firstChild())
return c->positionForCoordinates(x, y);
return c->positionForCoordinates(parentBlockX - contBlock->xPos(), parentBlockY - contBlock->yPos());
}
return RenderFlow::positionForCoordinates(x, y);
......
......@@ -871,7 +871,7 @@ void RenderLayer::autoscroll()
HitTestRequest request(true, false, true);
HitTestResult result(currentPos);
if (hitTest(request, result)) {
VisiblePosition pos(result.innerNode()->renderer()->positionForPoint(currentPos));
VisiblePosition pos(result.innerNode()->renderer()->positionForPoint(result.localPoint()));
currentFrame->eventHandler()->updateSelectionForMouseDragOverPosition(pos);
}
}
......@@ -1589,7 +1589,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequ
// return ourselves. We do this so mouse events continue getting delivered after a drag has
// exited the WebView, and so hit testing over a scrollbar hits the content document.
if ((request.active || request.mouseUp) && renderer()->isRenderView()) {
renderer()->setInnerNode(result);
renderer()->updateHitTestResult(result, result.point());
return this;
}
......
......@@ -2609,12 +2609,13 @@ bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result,
return inside;
}
void RenderObject::setInnerNode(HitTestResult& result)
void RenderObject::updateHitTestResult(HitTestResult& result, const IntPoint& point)
{
if (result.innerNode())
return;
Node* node = element();
IntPoint localPoint(point);
if (isRenderView())
node = document()->documentElement();
else if (!isInline() && continuation())
......@@ -2624,9 +2625,23 @@ void RenderObject::setInnerNode(HitTestResult& result)
node = continuation()->element();
if (node) {
if (node->renderer()->continuation() && node->renderer() != this) {
// We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
// of the principal renderer's containing block. This will end up being the innerNonSharedNode.
RenderObject* firstBlock = node->renderer()->containingBlock();
// Get our containing block.
RenderObject* block = this;
if (isInline())
block = containingBlock();
localPoint.move(block->xPos() - firstBlock->xPos(), block->yPos() - firstBlock->yPos());
}
result.setInnerNode(node);
if (!result.innerNonSharedNode())
result.setInnerNonSharedNode(node);
result.setLocalPoint(localPoint);
}
}
......
......@@ -526,7 +526,7 @@ public:
bool hitTest(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestFilter = HitTestAll);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
void setInnerNode(HitTestResult&);
void updateHitTestResult(HitTestResult&, const IntPoint&);