Commit bc939268 authored by mrowe@apple.com's avatar mrowe@apple.com

WebCore: Document.elementFromPoint() and Document.caretRangeFromPoint()...

WebCore: Document.elementFromPoint() and Document.caretRangeFromPoint() erroneously returning null at points visible only after scrolling.
https://bugs.webkit.org/show_bug.cgi?id=29245

Patch by Andrew Richards <randrew@gmail.com> on 2009-09-14
Reviewed by Sam Weinig.

Use visibleContentRect() instead of boundsRect() when checking hit point bounds on viewport.

* dom/Document.cpp:
(WebCore::Document::elementFromPoint):
(WebCore::Document::caretRangeFromPoint):

LayoutTests: Document.elementFromPoint() and Document.caretRangeFromPoint() returning null at points visible only after scrolling.
https://bugs.webkit.org/show_bug.cgi?id=29245

Patch by Andrew Richards <randrew@gmail.com> on 2009-09-14
Reviewed by Sam Weinig.

Extend tests to include hits in areas that are not in the initial containing block of the page.

* fast/dom/Document/CaretRangeFromPoint/hittest-relative-to-viewport-expected.txt:
* fast/dom/Document/CaretRangeFromPoint/hittest-relative-to-viewport.html:
* fast/dom/elementFromPoint-relative-to-viewport-expected.txt:
* fast/dom/elementFromPoint-relative-to-viewport.html:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@48398 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d338fbea
2009-09-14 Andrew Richards <randrew@gmail.com>
Reviewed by Sam Weinig.
Document.elementFromPoint() and Document.caretRangeFromPoint() returning null at points visible only after scrolling.
https://bugs.webkit.org/show_bug.cgi?id=29245
Extend tests to include hits in areas that are not in the initial containing block of the page.
* fast/dom/Document/CaretRangeFromPoint/hittest-relative-to-viewport-expected.txt:
* fast/dom/Document/CaretRangeFromPoint/hittest-relative-to-viewport.html:
* fast/dom/elementFromPoint-relative-to-viewport-expected.txt:
* fast/dom/elementFromPoint-relative-to-viewport.html:
2009-09-15 Jungshik Shin <jshin@chromium.org> 2009-09-15 Jungshik Shin <jshin@chromium.org>
Reviewed by Eric Seidel Reviewed by Eric Seidel
......
This box is here to create scrollbars. This checks for proper behavior of caretRangeFromPoint before and after scrolling.
Testing with no scroll
PASS: range.startContainer == element.firstChild. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS: range.startOffset == 0.
Test scrolling down
PASS: range.startContainer == element.firstChild. PASS Range.startContainer check (got [object Text], expected [object Text])
PASS: range.startOffset == 12. PASS Range.startOffset check (got 0, expected 0)
Test scrolling right PASS Range.startContainer check (got [object Text], expected [object Text])
PASS: range.startContainer == element.firstChild. PASS Range.startOffset check (got 12, expected 12)
PASS: range.startOffset == 2. PASS Range.startContainer check (got [object Text], expected [object Text])
Test scrolling down and right PASS Range.startOffset check (got 2, expected 2)
PASS: range.startContainer == element.firstChild. PASS Range.startContainer check (got [object Text], expected [object Text])
PASS: range.startOffset == 14. PASS Range.startOffset check (got 14, expected 14)
PASS Range.startContainer check (got [object Text], expected [object Text])
PASS Range.startOffset check (got 0, expected 0)
PASS Range.startContainer check (got [object Text], expected [object Text])
PASS Range.startOffset check (got 12, expected 12)
PASS Range.startContainer check (got [object Text], expected [object Text])
PASS Range.startOffset check (got 2, expected 2)
PASS Range.startContainer check (got [object Text], expected [object Text])
PASS Range.startOffset check (got 14, expected 14)
PASS successfullyParsed is true
TEST COMPLETE
<html> <link rel="stylesheet" href="../../../js/resources/js-test-style.css">
<head> <script src="../../../js/resources/js-test-pre.js"></script>
<style> <style>
#test { .test {
width: 100px; width: 100px;
font-family: "Ahem"; font-family: "Ahem";
} }
#pusher { .pusher {
width: 1000px; width: 4000px;
height: 1000px; height: 1000px;
outline: 1px solid black; outline: 1px solid black;
} }
</style> </style>
<script>
if (window.layoutTestController)
layoutTestController.dumpAsText();
var _log = "";
function log(msg)
{
_log += msg + "\n";
}
function swapInLog() <div id="testArea">
{ <div id="test-top" class="test">xxxxx xxxxx xxxxx xxxxx</div>
var element = document.getElementById('test'); <div class="pusher">This box is here to create scrollbars.</div>
var parent = element.parentNode; <div id="test-bottom" class="test" style="margin-left: 900px;">xxxxx xxxxx xxxxx xxxxx</div>
if (window.layoutTestController) <div class="pusher">This box is here to create additional space for the hit tests which must initially be in the scroll area.</div>
parent.removeChild(element); </div>
var console = document.createElement("pre");
console.textContent = _log; <p id="description"></p>
parent.appendChild(console); <div id="console"></div>
}
var element; <script>
if (window.layoutTestController)
layoutTestController.dumpAsText();
function test(pos, __expectedContainer, __expectedOffset) description('This checks for proper behavior of caretRangeFromPoint before and after scrolling.');
{
var expectedContainer = eval(__expectedContainer);
var expectedOffset = eval(__expectedOffset);
var range = document.caretRangeFromPoint(pos.x, pos.y); var elementTop = document.getElementById('test-top'),
elementBottom = document.getElementById('test-bottom');
if (range.startContainer == expectedContainer) { function testsWithBaseline(baselinePos, expectedContainer) {
log("PASS: range.startContainer == " + __expectedContainer + "."); function test(expectedOffset, scrollByX, scrollByY) {
} else { var hitPosition = { x: 15, y: 15 },
log("FAIL: range.startContainer == " + range.startContainer + "."); range,
doesContainerPass = function() { return range.startContainer === expectedContainer },
doesOffsetPass = function() { return range.startOffset === expectedOffset };
// Scroll relative to target.
scrollRelativeToBaseline(scrollByX, scrollByY);
range = document.caretRangeFromPoint(hitPosition.x, hitPosition.y);
// shouldn't return null range on any of these tests
if (range === null) {
testFailed("null range was returned from document.caretRangeFromPoint(" + hitPosition.x + ", " + hitPosition.y + ") at window scroll position " + window.scrollX + "x" + window.scrollY);
return;
} }
if (range.startOffset == expectedOffset) { // do an actual check
log("PASS: range.startOffset == " + __expectedOffset + "."); function check(thunk, message) {
} else { if (thunk())
log("FAIL: range.startOffset == " + range.startOffset + "."); testPassed(message);
else
testFailed(message);
} }
check(doesContainerPass, "Range.startContainer check (got " + range.startContainer + ", expected " + expectedContainer + ")");
check(doesOffsetPass, "Range.startOffset check (got " + range.startOffset + ", expected " + expectedOffset + ")");
} }
window.onload = function() function scrollRelativeToBaseline(x, y) {
{ window.scrollTo(baselinePos.x + x, baselinePos.y + y);
element = document.getElementById('test'); }
text = element.firstChild;
var positionToTest = { x: 15, y: 15 }; test(0, 0, 0);
test(12, 0, 25);
test(2, 25, 0);
test(14, 25, 25);
debug(" ");
}
log("Testing with no scroll"); var rectTop = elementTop.getBoundingClientRect(),
test(positionToTest, "element.firstChild", "0"); rectBottom = elementBottom.getBoundingClientRect(),
// Subtract some distance so we aren't in the very top left of the target.
topBaseline = { x: rectTop.left - 8, y: rectTop.top - 8 },
bottomBaseline = { x: rectBottom.left - 8, y: rectBottom.top - 8 };
log("Test scrolling down"); // Testing inside initial containing block (top left)
window.scrollTo(0, 25); testsWithBaseline(topBaseline, elementTop.firstChild);
test(positionToTest, "element.firstChild", "12");
log("Test scrolling right"); // Testing outside initial containing block (mid-page)
window.scrollTo(25, 0); testsWithBaseline(bottomBaseline, elementBottom.firstChild);
test(positionToTest, "element.firstChild", "2");
log("Test scrolling down and right"); if (window.layoutTestController) {
window.scrollTo(25, 25); var area = document.getElementById('testArea');
test(positionToTest, "element.firstChild", "14"); area.parentNode.removeChild(area);
}
swapInLog(); successfullyParsed = true;
} </script>
</script> <script src="../../../js/resources/js-test-post.js"></script>
</head>
<body>
<div id="test">xxxxx xxxxx xxxxx xxxxx</div>
<div id="pusher">This box is here to create scrollbars.</div>
</body>
</html>
...@@ -3,10 +3,14 @@ This test document.elementFromPoint is evaluated in with respect to the viewport ...@@ -3,10 +3,14 @@ This test document.elementFromPoint is evaluated in with respect to the viewport
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS unscrolledBox is '0' PASS unscrolledBoxInitial is '0'
PASS scrolledDownBox is '15' PASS scrolledDownBoxInitial is '15'
PASS scrolledRightBox is '3' PASS scrolledRightBoxInitial is '3'
PASS scrolledDownAndRightBox is '18' PASS scrolledDownAndRightBoxInitial is '18'
PASS unscrolledBoxOffscreen is '0'
PASS scrolledDownBoxOffscreen is '15'
PASS scrolledRightBoxOffscreen is '3'
PASS scrolledDownAndRightBoxOffscreen is '18'
PASS successfullyParsed is true PASS successfullyParsed is true
TEST COMPLETE TEST COMPLETE
......
<link rel="stylesheet" href="../js/resources/js-test-style.css"> <link rel="stylesheet" href="../js/resources/js-test-style.css">
<script src="../js/resources/js-test-pre.js"></script> <script src="../js/resources/js-test-pre.js"></script>
<style> <style>
#test { .test {
width: 100px; width: 100px;
height: 100px;
outline: 1px solid black; outline: 1px solid black;
} }
.testItem { .testItem {
...@@ -12,19 +13,21 @@ ...@@ -12,19 +13,21 @@
height: 20px; height: 20px;
outline: 1px solid red; outline: 1px solid red;
} }
#pusher { .pusher {
width: 1000px; width: 1000px;
height: 1000px; height: 1000px;
outline: 1px solid black; outline: 1px solid black;
} }
</style> </style>
<p id="description"></p>
<div id="console"></div>
<div id="testArea"> <div id="testArea">
<br> <br>
<div id="test"></div> <div id="test-initial" class="test"></div>
<div id="pusher">This box is here to create scrollbars.</div> <div class="pusher">This box is here to create scrollbars.</div>
<div id="test-offscreen" class="test"></div>
<div class="pusher">This box is here to create even more scrollbars!</div>
</div> </div>
<p id="description"></p>
<div id="console"></div>
<script> <script>
window.onclick = function(e) window.onclick = function(e)
{ {
...@@ -34,42 +37,59 @@ ...@@ -34,42 +37,59 @@
if (window.layoutTestController) if (window.layoutTestController)
layoutTestController.dumpAsText(); layoutTestController.dumpAsText();
var element = document.getElementById('test');
for (var i = 0; i < 25; ++i) {
var item = document.createElement("div");
item.className = "testItem";
item.textContent = String(i);
element.appendChild(item);
}
description('This test document.elementFromPoint is evaluated in with respect to the viewport, not the document.'); description('This test document.elementFromPoint is evaluated in with respect to the viewport, not the document.');
var unScrolledBoundingBox = element.getBoundingClientRect(); function testElement(element, label, offsetX, offsetY) {
var testX = unScrolledBoundingBox.left + 10; for (var i = 0; i < 25; ++i) {
var testY = unScrolledBoundingBox.top + 10; var item = document.createElement("div");
item.className = "testItem";
item.textContent = String(i);
element.appendChild(item);
}
var testX = 10;
var testY = 10;
// Get initial box. var unscrolledBox = "unscrolledBox" + label,
var unscrolledBox = document.elementFromPoint(testX, testY).textContent; scrolledDownBox = "scrolledDownBox" + label,
scrolledRightBox = "scrolledRightBox" + label,
scrolledDownAndRightBox = "scrolledDownAndRightBox" + label;
// Test scrolling down function relativeScroll(x, y) {
window.scrollTo(0, 50); window.scrollTo(offsetX + x, offsetY + y);
var scrolledDownBox = document.elementFromPoint(testX, testY).textContent; }
// Test scrolling right function getFromPoint(x, y) {
window.scrollTo(50, 0); relativeScroll(x, y);
var scrolledRightBox = document.elementFromPoint(testX, testY).textContent; var hitElement = document.elementFromPoint(testX, testY);
// shouldn't return null range on any of these tests
if (hitElement === null)
return null;
else
return hitElement.textContent;
}
// Get initial box.
window[unscrolledBox] = getFromPoint(0, 0);
// Test scrolling down and right // Test scrolling down
window.scrollTo(50, 50); window[scrolledDownBox] = getFromPoint(0, 50);
var scrolledDownAndRightBox = document.elementFromPoint(testX, testY).textContent;
// Reset // Test scrolling right
window.scrollTo(0, 0); window[scrolledRightBox] = getFromPoint(50, 0);
shouldBe("unscrolledBox", "'0'"); // Test scrolling down and right
shouldBe("scrolledDownBox", "'15'"); window[scrolledDownAndRightBox] = getFromPoint(50, 50);
shouldBe("scrolledRightBox", "'3'");
shouldBe("scrolledDownAndRightBox", "'18'"); shouldBe(unscrolledBox, "'0'");
shouldBe(scrolledDownBox, "'15'");
shouldBe(scrolledRightBox, "'3'");
shouldBe(scrolledDownAndRightBox, "'18'");
}
var elementInitial = document.getElementById('test-initial');
var elementOffscreen = document.getElementById('test-offscreen');
var offset = elementInitial.getBoundingClientRect();
testElement(elementInitial, "Initial", offset.left, offset.top);
testElement(elementOffscreen, "Offscreen", offset.left, offset.top + 1100);
if (window.layoutTestController) { if (window.layoutTestController) {
var area = document.getElementById('testArea'); var area = document.getElementById('testArea');
......
2009-09-14 Andrew Richards <randrew@gmail.com>
Reviewed by Sam Weinig.
Document.elementFromPoint() and Document.caretRangeFromPoint() erroneously returning null at points visible only after scrolling.
https://bugs.webkit.org/show_bug.cgi?id=29245
Use visibleContentRect() instead of boundsRect() when checking hit point bounds on viewport.
* dom/Document.cpp:
(WebCore::Document::elementFromPoint):
(WebCore::Document::caretRangeFromPoint):
2009-09-15 Jungshik Shin <jshin@chromium.org> 2009-09-15 Jungshik Shin <jshin@chromium.org>
Reviewed by Eric Seidel Reviewed by Eric Seidel
...@@ -940,7 +940,7 @@ Element* Document::elementFromPoint(int x, int y) const ...@@ -940,7 +940,7 @@ Element* Document::elementFromPoint(int x, int y) const
float zoomFactor = frame->pageZoomFactor(); float zoomFactor = frame->pageZoomFactor();
IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor, y * zoomFactor)) + view()->scrollOffset(); IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor, y * zoomFactor)) + view()->scrollOffset();
if (!frameView->boundsRect().contains(point)) if (!frameView->visibleContentRect().contains(point))
return 0; return 0;
HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
...@@ -970,7 +970,7 @@ PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) ...@@ -970,7 +970,7 @@ PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y)
float zoomFactor = frame->pageZoomFactor(); float zoomFactor = frame->pageZoomFactor();
IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor, y * zoomFactor)) + view()->scrollOffset(); IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor, y * zoomFactor)) + view()->scrollOffset();
if (!frameView->boundsRect().contains(point)) if (!frameView->visibleContentRect().contains(point))
return 0; return 0;
HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment