Range sliders and spin buttons don't work with multi-columns.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Dec 2011 08:26:05 +0000 (08:26 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Dec 2011 08:26:05 +0000 (08:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=70898

Patch by Yosifumi Inoue <yosin@chromium.org> on 2011-12-02
Reviewed by Dan Bernstein.

Source/WebCore:

This patch makes RenderBlock::hitTestColumns and
RenderBoxModelObject::mapAbsoluteToLocal to handle point
in multi-column same logic.

In multi-column, coordinate of box model rendering object is different
from absolute coordinate.. Columns in box model rendering object spans
vertically rather than horizontally.

When absolute point is represented in (column[i]+dx, column[0]+dy),
it is (column[0]+dx, column[0] + columnHeight + dy) in box model
rendering object coordinate.

Tests: fast/events/document-elementFromPoint.html
       fast/events/offsetX-offsetY.html
       fast/forms/number/spin-in-multi-column.html
       fast/forms/range/slider-in-multi-column.html
       fast/forms/select/listbox-in-multi-column.html

* rendering/RenderBlock.cpp:
(WebCore::ColumnRectIterator::ColumnRectIterator): Added
(WebCore::ColumnRectIterator::advance): Added
(WebCore::ColumnRectIterator::columnRect): Added
(WebCore::ColumnRectIterator::hasMore): Added
(WebCore::ColumnRectIterator::adjust): Added
(WebCore::ColumnRectIterator::update): Added
(WebCore::RenderBlock::hitTestColumns): Use ColumnRectIterator.
(WebCore::RenderBlock::adjustForColumnRect): Added
* rendering/RenderBlock.h: Add adjustForColumnRect.
* rendering/RenderBox.cpp:
(WebCore::RenderBox::mapAbsoluteToLocalPoint): Call RenderBoxModelObject::mapAbsoluteToLocalPoint.
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::mapAbsoluteToLocalPoint): Move from RenderInline::mapAbsoluteToLocalPoint and call RenderBlock::adjustForColumnRect.
* rendering/RenderBoxModelObject.h: add mapAbsoluteToLocalPoint.
* rendering/RenderInline.cpp: Move mapAbsoluteToLocalPoint to RenderBoxModelObject.
* rendering/RenderInline.h: remove mapAbsoluteToLocalPoint.

LayoutTests:

* fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.
* fast/events/offsetX-offsetY.html: Change offset for "in-columns" test.
* fast/forms/listbox/listbox-in-multi-column-expected.txt: Added.
* fast/forms/listbox/listbox-in-multi-column.html: Added.
* fast/forms/number/spin-in-multi-column-expected.txt: Added.
* fast/forms/number/spin-in-multi-column.html: Added.
* fast/forms/range/slider-in-multi-column-expected.txt: Added.
* fast/forms/range/slider-in-multi-column.html: Added.
* platform/chromium-win/fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.
* platform/efl/fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.
* platform/gtk/fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.

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

20 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/offsetX-offsetY-expected.txt
LayoutTests/fast/events/offsetX-offsetY.html
LayoutTests/fast/forms/number/spin-in-multi-column-expected.txt [new file with mode: 0644]
LayoutTests/fast/forms/number/spin-in-multi-column.html [new file with mode: 0644]
LayoutTests/fast/forms/range/slider-in-multi-column-expected.txt [new file with mode: 0644]
LayoutTests/fast/forms/range/slider-in-multi-column.html [new file with mode: 0644]
LayoutTests/fast/forms/select/listbox-in-multi-column-expected.txt [new file with mode: 0644]
LayoutTests/fast/forms/select/listbox-in-multi-column.html [new file with mode: 0644]
LayoutTests/platform/chromium-win/fast/events/offsetX-offsetY-expected.txt
LayoutTests/platform/efl/fast/events/offsetX-offsetY-expected.txt
LayoutTests/platform/gtk/fast/events/offsetX-offsetY-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlock.h
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBoxModelObject.cpp
Source/WebCore/rendering/RenderBoxModelObject.h
Source/WebCore/rendering/RenderInline.cpp
Source/WebCore/rendering/RenderInline.h

index fa6b66e..addac5b 100644 (file)
@@ -1,3 +1,22 @@
+2011-12-02  Yosifumi Inoue  <yosin@chromium.org>
+
+        Range sliders and spin buttons don't work with multi-columns.
+        https://bugs.webkit.org/show_bug.cgi?id=70898
+
+        Reviewed by Dan Bernstein.
+
+        * fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.
+        * fast/events/offsetX-offsetY.html: Change offset for "in-columns" test.
+        * fast/forms/listbox/listbox-in-multi-column-expected.txt: Added.
+        * fast/forms/listbox/listbox-in-multi-column.html: Added.
+        * fast/forms/number/spin-in-multi-column-expected.txt: Added.
+        * fast/forms/number/spin-in-multi-column.html: Added.
+        * fast/forms/range/slider-in-multi-column-expected.txt: Added.
+        * fast/forms/range/slider-in-multi-column.html: Added.
+        * platform/chromium-win/fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.
+        * platform/efl/fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.
+        * platform/gtk/fast/events/offsetX-offsetY-expected.txt: Change offset for "in-columns" test.
+
 2011-12-02  Pavel Feldman  <pfeldman@google.com>
 
         InspectorController destruction order leads to use-after-free
index 05024cf..7112241 100644 (file)
@@ -18,7 +18,7 @@ PASS: event at (112, 62) hit abs-box at offset (32, 37)
 PASS: event at (157, 32) hit rel-box at offset (22, 24)
 PASS: event at (410, 30) hit fixed-box at offset (10, 10)
 PASS: event at (36, 272) hit with-bordertopextra at offset (4, 4)
-PASS: event at (639, 207) hit in-columns at offset (173, -189)
+PASS: event at (639, 207) hit in-columns at offset (35, 5)
 PASS: event at (563, 410) hit inside-overflow at offset (7, 6)
 PASS: event at (112, 369) hit transformed at offset (11, 16)
 
index bf38e04..9c82f8e 100644 (file)
@@ -37,7 +37,7 @@
       dispatchEvent(157, 32, 'rel-box', 22, 24);
       dispatchEvent(410, 30, 'fixed-box', 10, 10);
       dispatchEvent(36, 272, 'with-bordertopextra', 4, 4);
-      dispatchEvent(639, 207, 'in-columns', 173, -189);
+      dispatchEvent(639, 207, 'in-columns', 35, 5);
       dispatchEvent(563, 410, 'inside-overflow', 7, 6);
       dispatchEvent(112, 369, 'transformed', 11, 16);
             
diff --git a/LayoutTests/fast/forms/number/spin-in-multi-column-expected.txt b/LayoutTests/fast/forms/number/spin-in-multi-column-expected.txt
new file mode 100644 (file)
index 0000000..63dce3b
--- /dev/null
@@ -0,0 +1,38 @@
+Spin In Multi-Coulumn
+
+This is test cases for BUG 70898.
+No outer
+
+
+
+
+DIV outer
+
+
+
+
+SPAN outer
+
+
+
+TABLE outer
+
+
+
+
+Results
+
+PASSED c00
+PASSED c01
+PASSED c02
+PASSED c10
+PASSED c11
+PASSED c12
+PASSED c20
+PASSED c21
+PASSED c22
+PASSED c30
+PASSED c31
+PASSED c32
+
diff --git a/LayoutTests/fast/forms/number/spin-in-multi-column.html b/LayoutTests/fast/forms/number/spin-in-multi-column.html
new file mode 100644 (file)
index 0000000..a8bf62d
--- /dev/null
@@ -0,0 +1,143 @@
+<html>
+<head>
+<style type="text/css" media="screen">
+form {
+    -webkit-column-count: 3;
+    -webkit-column-gap: 0px;
+    -moz-column-count: 3;
+    -moz-column-gap: 0px;
+    background: #ccccff;
+    margin: 0px;
+    padding: 0px;
+    border: solid 1px red;
+}
+
+input[type="number"] {
+    width: 100px;
+    height: 50px;
+}
+
+td {
+    background: red;
+}
+</style>
+<script>
+const numForms = 4;
+const numCols = 3;
+
+function log(msg)
+{
+    var res = document.getElementById('res');
+    res.innerHTML = res.innerHTML + msg + "<br>";
+}
+
+function pageX(runner) {
+    var acc = 0;
+    while (runner) {
+        acc += runner.offsetLeft;
+        runner = runner.offsetParent;
+    }
+    return acc;
+}
+
+function pageY(runner) {
+    var acc = 0;
+    while (runner) {
+        acc += runner.offsetTop;
+        runner = runner.offsetParent;
+    }
+    return acc;
+}
+
+function testIt(formIndex, colIndex, ofsX, expected)
+{
+    const form = document.getElementById("f" + formIndex);
+    const column = document.getElementById("c" + formIndex + "0");
+    const colWidth = Math.floor(form.offsetWidth / numCols);
+
+    const spinId = "c" + formIndex + colIndex;
+    const spin = document.getElementById(spinId);
+
+    const clickX = pageX(column) + colWidth * colIndex + ofsX;
+    const clickY = pageY(column) + Math.floor(spin.offsetHeight / 3);
+
+    eventSender.mouseMoveTo(clickX, clickY);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    eventSender.mouseMoveTo(0, 0);
+
+    if (spin.value == expected)
+        log("PASSED " + spinId);
+    else
+        log("FAILED " + spinId + " expected=" + expected + " got=" + spin.value + " " + clickX + "@" + clickY);
+}
+
+function installMouseTracker() {
+    document.body.onmousemove = function(e) {
+        var resultBox = document.getElementById("mousepos");
+        var offsets = "element id: " + e.target.id + "<br> clientX: " + e.clientX + " clientY: " + e.clientY + "<br>";
+        offsets += "offsetX: " + e.offsetX + " offsetY: " + e.offsetY;
+        resultBox.innerHTML = offsets;
+    }
+}
+
+function test()
+{
+    if (!window.layoutTestController) {
+        installMouseTracker();
+        return;
+    }
+
+    layoutTestController.dumpAsText();
+
+    for (var formIndex = 0; formIndex < numForms; formIndex++) {
+        for (var colIndex = 0; colIndex < numCols; colIndex++) {
+          testIt(formIndex, colIndex, 93, 10);
+        }
+    }
+}
+</script>
+</head>
+<body onload="test()">
+<h1>Spin In Multi-Coulumn</h1>
+This is test cases for <a href="https://webkit.org/b/70898">BUG 70898</a>.
+
+<h2>No outer</h2>
+<form id="f0">
+<input id="c00" type="number" min="0" max="100" step="10" /><br />
+<input id="c01" type="number" min="0" max="100" step="10" /><br />
+<input id="c02" type="number" min="0" max="100" step="10" /><br />
+</form>
+
+<h2>DIV outer</h2>
+<form id="f1">
+<div>
+<input id="c10" type="number" min="0" max="100" step="10" /><br />
+<input id="c11" type="number" min="0" max="100" step="10" /><br />
+<input id="c12" type="number" min="0" max="100" step="10" /><br />
+</div>
+</form>
+
+<h2>SPAN outer</h2>
+<form id="f2">
+<span>
+<input id="c20" type="number" min="0" max="100" step="10" /><br />
+<input id="c21" type="number" min="0" max="100" step="10" /><br />
+<input id="c22" type="number" min="0" max="100" step="10" /><br />
+</span>
+</form>
+
+<h2>TABLE outer</h2>
+<form id="f3">
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td><input id="c30" type="number" min="0" max="100" step="10" /></td></tr>
+<tr><td><input id="c31" type="number" min="0" max="100" step="10" /></td></tr>
+<tr><td><input id="c32" type="number" min="0" max="100" step="10" /></td></tr>
+</table>
+</form>
+
+<h2>Results</h2>
+<div id="mousepos"></div>
+<div id="res"></div>
+
+</html>
diff --git a/LayoutTests/fast/forms/range/slider-in-multi-column-expected.txt b/LayoutTests/fast/forms/range/slider-in-multi-column-expected.txt
new file mode 100644 (file)
index 0000000..cfcd330
--- /dev/null
@@ -0,0 +1,38 @@
+Slider In Multi-Coulumn
+
+This is test cases for BUG 70898.
+No outer
+
+
+
+
+DIV outer
+
+
+
+
+SPAN outer
+
+
+
+TABLE outer
+
+
+
+
+Results
+
+PASSED c00
+PASSED c01
+PASSED c02
+PASSED c10
+PASSED c11
+PASSED c12
+PASSED c20
+PASSED c21
+PASSED c22
+PASSED c30
+PASSED c31
+PASSED c32
+
diff --git a/LayoutTests/fast/forms/range/slider-in-multi-column.html b/LayoutTests/fast/forms/range/slider-in-multi-column.html
new file mode 100644 (file)
index 0000000..fc0c3b2
--- /dev/null
@@ -0,0 +1,129 @@
+<html>
+<head>
+<style type="text/css" media="screen">
+form {
+    -webkit-column-count: 3;
+    -webkit-column-gap: 0px;
+    background: #ccccff;
+    margin: 0px;
+    padding: 0px;
+    border: solid 1px red;
+}
+
+input[type="range"] {
+    width: 100px;
+    height: 50px;
+}
+
+td {
+    background: red;
+}
+</style>
+<script>
+const numForms = 4;
+const numCols = 3;
+
+function log(msg)
+{
+    var res = document.getElementById('res');
+    res.innerHTML = res.innerHTML + msg + "<br>";
+}
+
+function pageX(runner) {
+    var acc = 0;
+    while (runner) {
+        acc += runner.offsetLeft;
+        runner = runner.offsetParent;
+    }
+    return acc;
+}
+
+function pageY(runner) {
+    var acc = 0;
+    while (runner) {
+        acc += runner.offsetTop;
+        runner = runner.offsetParent;
+    }
+    return acc;
+}
+
+function testIt(formIndex, colIndex, ofsX, expected)
+{
+    const form = document.getElementById("f" + formIndex);
+    const column = document.getElementById("c" + formIndex + "0");
+    const colWidth = Math.floor(form.offsetWidth / numCols);
+
+    const sliderId = "c" + formIndex + colIndex;
+    const slider = document.getElementById(sliderId);
+
+    const clickX = pageX(column) + colWidth * colIndex + ofsX;
+    const clickY = pageY(column) + slider.offsetHeight / 2;
+
+    eventSender.mouseMoveTo(clickX, clickY);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+
+    if (slider.value == expected)
+        log("PASSED " + sliderId);
+    else
+        log("FAILED " + sliderId + " expected=" + expected + " got=" + slider.value + " " + clickX + "@" + clickY);
+}
+
+function test()
+{
+    if (!window.layoutTestController)
+        return;
+
+    layoutTestController.dumpAsText();
+
+    for (var formIndex = 0; formIndex < numForms; formIndex++) {
+        for (var colIndex = 0; colIndex < numCols; colIndex++) {
+          testIt(formIndex, colIndex, 23, 20);
+        }
+    }
+}
+</script>
+</head>
+<body onload="test()">
+<h1>Slider In Multi-Coulumn</h1>
+This is test cases for <a href="https://webkit.org/b/70898">BUG 70898</a>.
+
+<h2>No outer</h2>
+<form id="f0">
+<input id="c00" type="range" min="0" max="100" step="10" /><br />
+<input id="c01" type="range" min="0" max="100" step="10" /><br />
+<input id="c02" type="range" min="0" max="100" step="10" /><br />
+</form>
+
+<h2>DIV outer</h2>
+<form id="f1">
+<div>
+<input id="c10" type="range" min="0" max="100" step="10" /><br />
+<input id="c11" type="range" min="0" max="100" step="10" /><br />
+<input id="c12" type="range" min="0" max="100" step="10" /><br />
+</div>
+</form>
+
+<h2>SPAN outer</h2>
+<form id="f2">
+<span>
+<input id="c20" type="range" min="0" max="100" step="10" /><br />
+<input id="c21" type="range" min="0" max="100" step="10" /><br />
+<input id="c22" type="range" min="0" max="100" step="10" /><br />
+</span>
+</form>
+
+<h2>TABLE outer</h2>
+<form id="f3">
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td><input id="c30" type="range" min="0" max="100" step="10" /></td></tr>
+<tr><td><input id="c31" type="range" min="0" max="100" step="10" /></td></tr>
+<tr><td><input id="c32" type="range" min="0" max="100" step="10" /></td></tr>
+</table>
+</form>
+
+<h2>Results</h2>
+<div id="res">
+</div>
+
+</html>
diff --git a/LayoutTests/fast/forms/select/listbox-in-multi-column-expected.txt b/LayoutTests/fast/forms/select/listbox-in-multi-column-expected.txt
new file mode 100644 (file)
index 0000000..4113ce7
--- /dev/null
@@ -0,0 +1,38 @@
+ListBox In Multi-Coulumn
+
+This is test cases for BUG 70898.
+No outer
+
+
+
+
+DIV outer
+
+
+
+
+SPAN outer
+
+
+
+TABLE outer
+
+
+
+
+Results
+
+PASSED c00
+PASSED c01
+PASSED c02
+PASSED c10
+PASSED c11
+PASSED c12
+PASSED c20
+PASSED c21
+PASSED c22
+PASSED c30
+PASSED c31
+PASSED c32
+
diff --git a/LayoutTests/fast/forms/select/listbox-in-multi-column.html b/LayoutTests/fast/forms/select/listbox-in-multi-column.html
new file mode 100644 (file)
index 0000000..4fc6358
--- /dev/null
@@ -0,0 +1,133 @@
+<html>
+<head>
+<style type="text/css" media="screen">
+body {
+    font-size: 13px;
+}
+form {
+    -webkit-column-count: 3;
+    -webkit-column-gap: 0px;
+    background: #ccccff;
+    margin: 0px;
+    padding: 0px;
+    border: solid 1px red;
+}
+
+input[type="number"] {
+    width: 200px;
+    height: 50px;
+}
+
+td {
+    background: red;
+}
+</style>
+<script>
+const numForms = 4;
+const numCols = 3;
+
+function log(msg)
+{
+    var res = document.getElementById('res');
+    res.innerHTML = res.innerHTML + msg + "<br>";
+}
+
+function pageX(runner) {
+    var acc = 0;
+    while (runner) {
+        acc += runner.offsetLeft;
+        runner = runner.offsetParent;
+    }
+    return acc;
+}
+
+function pageY(runner) {
+    var acc = 0;
+    while (runner) {
+        acc += runner.offsetTop;
+        runner = runner.offsetParent;
+    }
+    return acc;
+}
+
+function testIt(formIndex, colIndex, ofsX, expected)
+{
+    const form = document.getElementById("f" + formIndex);
+    const column = document.getElementById("c" + formIndex + "0");
+    const colWidth = Math.floor(form.offsetWidth / numCols);
+
+    const spinId = "c" + formIndex + colIndex;
+    const spin = document.getElementById(spinId);
+
+    const clickX = pageX(column) + colWidth * colIndex + ofsX;
+    const clickY = pageY(column) + Math.floor(spin.offsetHeight / 3);
+
+    eventSender.mouseMoveTo(clickX, clickY);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    eventSender.mouseMoveTo(0, 0);
+
+    if (spin.value == expected)
+        log("PASSED " + spinId);
+    else
+        log("FAILED " + spinId + " expected=" + expected + " got=" + spin.value + " " + clickX + "@" + clickY);
+}
+
+function test()
+{
+    if (!window.layoutTestController)
+        return;
+
+    layoutTestController.dumpAsText();
+
+    for (var formIndex = 0; formIndex < numForms; formIndex++) {
+        for (var colIndex = 0; colIndex < numCols; colIndex++) {
+          testIt(formIndex, colIndex, 10, "b");
+        }
+    }
+}
+</script>
+</head>
+<body onload="test()">
+<h1>ListBox In Multi-Coulumn</h1>
+This is test cases for <a href="https://webkit.org/b/70898">BUG 70898</a>.
+
+<h2>No outer</h2>
+<form id="f0">
+<select id="c00" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+<select id="c01" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+<select id="c02" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+</form>
+
+<h2>DIV outer</h2>
+<form id="f1">
+<div>
+<select id="c10" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+<select id="c11" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+<select id="c12" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+</div>
+</form>
+
+<h2>SPAN outer</h2>
+<form id="f2">
+<span>
+<select id="c20" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+<select id="c21" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+<select id="c22" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select><br />
+</span>
+</form>
+
+<h2>TABLE outer</h2>
+<form id="f3">
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td><select id="c30" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select></td></tr>
+<tr><td><select id="c31" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select></td></tr>
+<tr><td><select id="c32" size="4"><option value="a">Alpha</option><option value="b">Bravo</option><option value="c">Charlie</option><option value="d">Delta</option></select></td></tr>
+</table>
+</form>
+
+<h2>Results</h2>
+<div id="res">
+</div>
+
+</html>
index 59be17e..9261efb 100644 (file)
@@ -18,7 +18,7 @@ PASS: event at (112, 62) hit abs-box at offset (32, 37)
 FAIL: event at (157, 32) expected to hit rel-box at (22, 24) but hit rel-box at (22, 22)
 PASS: event at (410, 30) hit fixed-box at offset (10, 10)
 FAIL: event at (36, 272) expected to hit with-bordertopextra at (4, 4) but hit filler at (56, 372)
-FAIL: event at (639, 207) expected to hit in-columns at (173, -189) but hit in-columns at (173, -205)
+PASS: event at (639, 207) hit in-columns at offset (35, 5)
 FAIL: event at (563, 410) expected to hit inside-overflow at (7, 6) but hit overflow-contents at (178, 112)
 FAIL: event at (112, 369) expected to hit transformed at (11, 16) but hit transformed at (7, 2)
 
index 3440f5c..78016c2 100644 (file)
@@ -18,7 +18,7 @@ PASS: event at (112, 62) hit abs-box at offset (32, 37)
 FAIL: event at (157, 32) expected to hit rel-box at (22, 24) but hit rel-box at (22, 23)
 PASS: event at (410, 30) hit fixed-box at offset (10, 10)
 FAIL: event at (36, 272) expected to hit with-bordertopextra at (4, 4) but hit with-bordertopextra at (4, 0)
-FAIL: event at (639, 207) expected to hit in-columns at (173, -189) but hit in-columns at (173, -210)
+PASS: event at (639, 207) hit in-columns at offset (35, 5)
 FAIL: event at (563, 410) expected to hit inside-overflow at (7, 6) but hit inside-overflow at (7, 1)
 FAIL: event at (112, 369) expected to hit transformed at (11, 16) but hit transformed at (9, 9)
 
index a037eca..7112241 100644 (file)
@@ -18,7 +18,7 @@ PASS: event at (112, 62) hit abs-box at offset (32, 37)
 PASS: event at (157, 32) hit rel-box at offset (22, 24)
 PASS: event at (410, 30) hit fixed-box at offset (10, 10)
 PASS: event at (36, 272) hit with-bordertopextra at offset (4, 4)
-FAIL: event at (639, 207) expected to hit in-columns at (173, -189) but hit in-columns at (173, -199)
+PASS: event at (639, 207) hit in-columns at offset (35, 5)
 PASS: event at (563, 410) hit inside-overflow at offset (7, 6)
 PASS: event at (112, 369) hit transformed at offset (11, 16)
 
index 8f626b1..6dd6558 100644 (file)
@@ -1,3 +1,46 @@
+2011-12-02  Yosifumi Inoue  <yosin@chromium.org>
+
+        Range sliders and spin buttons don't work with multi-columns.
+        https://bugs.webkit.org/show_bug.cgi?id=70898
+
+        Reviewed by Dan Bernstein.
+
+        This patch makes RenderBlock::hitTestColumns and
+        RenderBoxModelObject::mapAbsoluteToLocal to handle point
+        in multi-column same logic.
+
+        In multi-column, coordinate of box model rendering object is different
+        from absolute coordinate.. Columns in box model rendering object spans
+        vertically rather than horizontally.
+
+        When absolute point is represented in (column[i]+dx, column[0]+dy),
+        it is (column[0]+dx, column[0] + columnHeight + dy) in box model
+        rendering object coordinate.
+
+        Tests: fast/events/document-elementFromPoint.html
+               fast/events/offsetX-offsetY.html
+               fast/forms/number/spin-in-multi-column.html
+               fast/forms/range/slider-in-multi-column.html
+               fast/forms/select/listbox-in-multi-column.html
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::ColumnRectIterator::ColumnRectIterator): Added
+        (WebCore::ColumnRectIterator::advance): Added
+        (WebCore::ColumnRectIterator::columnRect): Added
+        (WebCore::ColumnRectIterator::hasMore): Added
+        (WebCore::ColumnRectIterator::adjust): Added
+        (WebCore::ColumnRectIterator::update): Added
+        (WebCore::RenderBlock::hitTestColumns): Use ColumnRectIterator.
+        (WebCore::RenderBlock::adjustForColumnRect): Added
+        * rendering/RenderBlock.h: Add adjustForColumnRect.
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::mapAbsoluteToLocalPoint): Call RenderBoxModelObject::mapAbsoluteToLocalPoint.
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::mapAbsoluteToLocalPoint): Move from RenderInline::mapAbsoluteToLocalPoint and call RenderBlock::adjustForColumnRect.
+        * rendering/RenderBoxModelObject.h: add mapAbsoluteToLocalPoint.
+        * rendering/RenderInline.cpp: Move mapAbsoluteToLocalPoint to RenderBoxModelObject.
+        * rendering/RenderInline.h: remove mapAbsoluteToLocalPoint.
+
 2011-12-02  Pavel Feldman  <pfeldman@google.com>
 
         InspectorController destruction order leads to use-after-free
index ca80b8c..4c71440 100755 (executable)
@@ -4237,51 +4237,102 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re
     return false;
 }
 
+class ColumnRectIterator {
+    WTF_MAKE_NONCOPYABLE(ColumnRectIterator);
+public:
+    ColumnRectIterator(const RenderBlock& block)
+        : m_block(block)
+        , m_colInfo(block.columnInfo())
+        , m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1)
+        , m_isHorizontal(block.isHorizontalWritingMode())
+        , m_logicalLeft(block.logicalLeftOffsetForContent())
+    {
+        int colCount = m_colInfo->columnCount();
+        m_colIndex = colCount - 1;
+        m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
+        update();
+    }
+
+    void advance()
+    {
+        ASSERT(hasMore());
+        m_colIndex--;
+        update();
+    }
+
+    LayoutRect columnRect() const { return m_colRect; }
+    bool hasMore() const { return m_colIndex >= 0; }
+
+    void adjust(LayoutSize& offset) const
+    {
+        LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
+        offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
+        if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
+            if (m_isHorizontal)
+                offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
+            else
+                offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
+        }
+    }
+
+private:
+    void update()
+    {
+        if (m_colIndex < 0)
+            return;
+
+        m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
+        m_block.flipForWritingMode(m_colRect);
+        m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
+    }
+
+    const RenderBlock& m_block;
+    const ColumnInfo* const m_colInfo;
+    const int m_direction;
+    const bool m_isHorizontal;
+    const LayoutUnit m_logicalLeft;
+    int m_colIndex;
+    LayoutUnit m_currLogicalTopOffset;
+    LayoutRect m_colRect;
+};
+
 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
 {
     // We need to do multiple passes, breaking up our hit testing into strips.
-    ColumnInfo* colInfo = columnInfo();
-    int colCount = columnCount(colInfo);
-    if (!colCount)
+    if (!hasColumns())
         return false;
-    LayoutUnit logicalLeft = logicalLeftOffsetForContent();
-    LayoutUnit currLogicalTopOffset = !style()->isFlippedBlocksWritingMode() ? -colCount * colInfo->columnHeight() : colCount * colInfo->columnHeight();
-    bool isHorizontal = isHorizontalWritingMode();
 
-    for (int i = colCount - 1; i >= 0; i--) {
-        LayoutRect colRect = columnRectAt(colInfo, i);
-        flipForWritingMode(colRect);
-        LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
-        LayoutUnit blockDelta =  (isHorizontal ? colRect.height() : colRect.width());
-        if (style()->isFlippedBlocksWritingMode())
-            currLogicalTopOffset -= blockDelta;
-        else
-            currLogicalTopOffset += blockDelta;
+    for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
+        LayoutRect hitRect = result.rectForPoint(pointInContainer);
+        LayoutRect colRect = it.columnRect();
         colRect.moveBy(accumulatedOffset);
-        
-        if (colRect.intersects(result.rectForPoint(pointInContainer))) {
+        if (colRect.intersects(hitRect)) {
             // The point is inside this column.
             // Adjust accumulatedOffset to change where we hit test.
-        
-            LayoutSize offset = isHorizontal ? IntSize(currLogicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
-            if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
-                if (isHorizontal)
-                    offset.expand(0, colRect.y() - accumulatedOffset.y() - borderTop() - paddingTop());
-                else
-                    offset.expand(colRect.x() - accumulatedOffset.x() - borderLeft() - paddingLeft(), 0);
-            }
-
+            LayoutSize offset;
+            it.adjust(offset);
             LayoutPoint finalLocation = accumulatedOffset + offset;
-            if (result.isRectBasedTest() && !colRect.contains(result.rectForPoint(pointInContainer)))
-                hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction);
-            else
+            if (!result.isRectBasedTest() || colRect.contains(hitRect))
                 return hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, pointInContainer, finalLocation));
+
+            hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction);
         }
     }
 
     return false;
 }
 
+void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& pointInContainer) const
+{
+    for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
+        LayoutRect colRect = it.columnRect();
+        if (colRect.contains(pointInContainer)) {
+            it.adjust(offset);
+            return;
+        }
+    }
+}
+
 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
 {
     if (childrenInline() && !isTable()) {
index 7b75251..cb262ec 100644 (file)
@@ -196,6 +196,7 @@ public:
 
     void adjustRectForColumns(LayoutRect&) const;
     virtual void adjustForColumns(LayoutSize&, const LayoutPoint&) const;
+    void adjustForColumnRect(LayoutSize& offset, const LayoutPoint& pointInContainer) const;
 
     void addContinuationWithOutline(RenderInline*);
     bool paintsContinuationOutline(RenderInline*);
index 5d7a67f..bce02ce 100644 (file)
@@ -1393,22 +1393,8 @@ void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Transfor
         fixed &= isFixedPos;
     } else
         fixed |= isFixedPos;
-    
-    RenderObject* o = container();
-    if (!o)
-        return;
 
-    o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
-
-    LayoutSize containerOffset = offsetFromContainer(o, LayoutPoint());
-
-    bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
-    if (useTransforms && shouldUseTransformFromContainer(o)) {
-        TransformationMatrix t;
-        getTransformFromContainer(o, containerOffset, t);
-        transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
-    } else
-        transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+    RenderBoxModelObject::mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
 }
 
 LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point) const
index 5a9137a..9213db3 100644 (file)
@@ -37,6 +37,7 @@
 #include "RenderLayer.h"
 #include "RenderView.h"
 #include "Settings.h"
+#include "TransformState.h"
 #include <wtf/CurrentTime.h>
 
 using namespace std;
@@ -2717,4 +2718,33 @@ bool RenderBoxModelObject::shouldAntialiasLines(GraphicsContext* context)
     return !context->getCTM().isIdentityOrTranslationOrFlipped();
 }
 
+void RenderBoxModelObject::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
+{
+    // We don't expect absoluteToLocal() to be called during layout (yet)
+    ASSERT(!view() || !view()->layoutStateEnabled());
+
+    RenderObject* o = container();
+    if (!o)
+        return;
+
+    o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
+
+    LayoutSize containerOffset = offsetFromContainer(o, LayoutPoint());
+
+    if (style()->position() != AbsolutePosition && style()->position() != FixedPosition && o->hasColumns()) {
+        RenderBlock* block = static_cast<RenderBlock*>(o);
+        LayoutPoint point(roundedLayoutPoint(transformState.mappedPoint()));
+        point -= containerOffset;
+        block->adjustForColumnRect(containerOffset, point);
+    }
+
+    bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
+    if (useTransforms && shouldUseTransformFromContainer(o)) {
+        TransformationMatrix t;
+        getTransformFromContainer(o, containerOffset, t);
+        transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+    } else
+        transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+}
+
 } // namespace WebCore
index af199ef..b07e8d6 100644 (file)
@@ -125,6 +125,8 @@ public:
     virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const = 0;
     virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const = 0;
 
+    virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const OVERRIDE;
+
     // Called by RenderObject::willBeDestroyed() and is the only way layers should ever be destroyed
     void destroyLayer();
 
index 1e8a1e2..9c6678d 100644 (file)
@@ -1161,28 +1161,6 @@ void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b
     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, wasFixed);
 }
 
-void RenderInline::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
-{
-    // We don't expect this function to be called during layout.
-    ASSERT(!view() || !view()->layoutStateEnabled());
-
-    RenderObject* o = container();
-    if (!o)
-        return;
-
-    o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
-
-    LayoutSize containerOffset = offsetFromContainer(o, LayoutPoint());
-
-    bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
-    if (useTransforms && shouldUseTransformFromContainer(o)) {
-        TransformationMatrix t;
-        getTransformFromContainer(o, containerOffset, t);
-        transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
-    } else
-        transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
-}
-
 void RenderInline::updateDragState(bool dragOn)
 {
     RenderBoxModelObject::updateDragState(dragOn);
index fe95af1..04905c2 100644 (file)
@@ -131,7 +131,6 @@ private:
     virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect&, bool fixed) const;
 
     virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, bool* wasFixed = 0) const;
-    virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const;
 
     virtual VisiblePosition positionForPoint(const LayoutPoint&);