[CSS Regions] Selection focusNode set to the "region" block, instead of the "source...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Nov 2013 18:21:05 +0000 (18:21 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Nov 2013 18:21:05 +0000 (18:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=120769

Patch by Javier Fernandez <jfernandez@igalia.com> on 2013-11-11
Reviewed by David Hyatt.

Source/WebCore:

When a point hits a Region block, current positionForPoint algorithm determines its
position in the DOM and returns either the start or end offset for such block, since
Region blocks have no children in the DOM.

It's necessary to map the point into Flow Thread coordinates in order to determine
the DOM position of the specific element rendered by the Region.

Top margin, padding and border points should be mapped to the beginning of the Region
block, while bottom points are mapped to the block end. The Left coordinate its just
adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow
direction.

Besides, when inspecting the Flow Thread blocks looking for the last candidate box,
the Region originally associated to the point might be taken into account. Only the
blocks/boxes rendered by the Region are potential candidates.

Tests: fast/regions/selection/position-for-point-1-vert-lr.html
       fast/regions/selection/position-for-point-1-vert-rl.html
       fast/regions/selection/position-for-point-1.html
       fast/regions/selection/position-for-point-vert-lr.html
       fast/regions/selection/position-for-point-vert-rl.html
       fast/regions/selection/position-for-point.html

* rendering/RenderBlock.cpp:
(WebCore::isChildHitTestCandidate):
(WebCore::RenderBlock::positionForPoint):
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::positionForPoint): Added.
It just redirects the call to the associated RenderNamedFlowFragment instance.
* rendering/RenderBlockFlow.h:
* rendering/RenderRegion.cpp:
(WebCore::RenderRegion::mapRegionPointIntoFlowThreadCoordinates): Added.
It performs the coordinates mapping.
(WebCore::RenderRegion::positionForPoint): Added.
It determines the corresponding LayoutPoint in the FlowThread the Region
is associated to, forwarding the call to the RenderBlock class using the
FlowThread's first child block and such new point.
* rendering/RenderRegion.h:

LayoutTests:

* fast/regions/resources/helper.js:
(selectContentFromIdToPos):
(selectContentFromIdToPosVert):
(.document.onmouseup):
(onMouseUpLogSelectionAndFocus):
* fast/regions/selection/position-for-point-1-expected.txt: Added.
* fast/regions/selection/position-for-point-1-vert-lr-expected.txt: Added.
* fast/regions/selection/position-for-point-1-vert-lr.html: Added.
* fast/regions/selection/position-for-point-1-vert-rl-expected.txt: Added.
* fast/regions/selection/position-for-point-1-vert-rl.html: Added.
* fast/regions/selection/position-for-point-1.html: Added.
* fast/regions/selection/position-for-point-expected.txt: Added.
* fast/regions/selection/position-for-point-vert-lr-expected.txt: Added.
* fast/regions/selection/position-for-point-vert-lr.html: Added.
* fast/regions/selection/position-for-point-vert-rl-expected.txt: Added.
* fast/regions/selection/position-for-point-vert-rl.html: Added.
* fast/regions/selection/position-for-point.html: Added.

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

20 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/regions/resources/helper.js
LayoutTests/fast/regions/selection/position-for-point-1-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-1-vert-lr-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-1-vert-lr.html [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-1-vert-rl-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-1-vert-rl.html [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-1.html [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-vert-lr-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-vert-lr.html [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-vert-rl-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point-vert-rl.html [new file with mode: 0644]
LayoutTests/fast/regions/selection/position-for-point.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlockFlow.cpp
Source/WebCore/rendering/RenderBlockFlow.h
Source/WebCore/rendering/RenderRegion.cpp
Source/WebCore/rendering/RenderRegion.h

index aae8e20..16cd7cf 100644 (file)
@@ -1,3 +1,28 @@
+2013-11-11  Javier Fernandez  <jfernandez@igalia.com>
+
+        [CSS Regions] Selection focusNode set to the "region" block, instead of the "source" block
+        https://bugs.webkit.org/show_bug.cgi?id=120769
+
+        Reviewed by David Hyatt.
+
+        * fast/regions/resources/helper.js:
+        (selectContentFromIdToPos):
+        (selectContentFromIdToPosVert):
+        (.document.onmouseup):
+        (onMouseUpLogSelectionAndFocus):
+        * fast/regions/selection/position-for-point-1-expected.txt: Added.
+        * fast/regions/selection/position-for-point-1-vert-lr-expected.txt: Added.
+        * fast/regions/selection/position-for-point-1-vert-lr.html: Added.
+        * fast/regions/selection/position-for-point-1-vert-rl-expected.txt: Added.
+        * fast/regions/selection/position-for-point-1-vert-rl.html: Added.
+        * fast/regions/selection/position-for-point-1.html: Added.
+        * fast/regions/selection/position-for-point-expected.txt: Added.
+        * fast/regions/selection/position-for-point-vert-lr-expected.txt: Added.
+        * fast/regions/selection/position-for-point-vert-lr.html: Added.
+        * fast/regions/selection/position-for-point-vert-rl-expected.txt: Added.
+        * fast/regions/selection/position-for-point-vert-rl.html: Added.
+        * fast/regions/selection/position-for-point.html: Added.
+
 2013-11-10  Sun-woo Nam  <sunny.nam@samsung.com>
 
         [EFL] Layout tests with css1 box properties need to be rebaselined.
index 5233d70..3c2850d 100644 (file)
@@ -214,6 +214,20 @@ function selectContentByRange(fromX, fromY, toX, toY) {
     eventSender.mouseUp();
 }
 
+function selectContentFromIdToPos(fromId, toX, toY) {
+  var fromRect = document.getElementById(fromId).getBoundingClientRect();
+  var fromRectVerticalCenter = fromRect.top + fromRect.height / 2;
+
+  selectContentByRange(fromRect.left, fromRectVerticalCenter, toX, toY);
+}
+
+function selectContentFromIdToPosVert(fromId, toX, toY) {
+  var fromRect = document.getElementById(fromId).getBoundingClientRect();
+  var fromRectHorizontalCenter = fromRect.left + fromRect.width / 2;
+
+  selectContentByRange(fromRectHorizontalCenter, fromRect.top, toX, toY);
+}
+
 function selectContentByIds(fromId, toId) {
     var fromRect = document.getElementById(fromId).getBoundingClientRect();
     var toRect = document.getElementById(toId).getBoundingClientRect();
@@ -251,6 +265,22 @@ function mouseClick(positionX, positionY) {
     eventSender.mouseUp();
 }
 
+function onMouseUpLogSelectionAndFocus(contentId, nodeId, offsetId) {
+    document.onmouseup = function() {
+        var selectedContent = document.getElementById(contentId);
+        var focusNode = document.getElementById(nodeId);
+        var focusOffset = document.getElementById(offsetId);
+        var sel = window.getSelection();
+        var node = sel['focusNode'];
+        var id = " (id: " + node.id + ")";
+        if (node.nodeType == 3)
+            id = " (parent id: " + node.parentNode.id + ")";
+        focusNode.innerHTML = id + " " + sel['focusNode'] + " " + sel['focusNode'].nodeValue;
+        focusOffset.innerHTML = sel['focusOffset'];
+        selectedContent.innerHTML = sel.getRangeAt(0);
+    }
+}
+
 function onMouseUpLogSelection(elementId) {
     document.onmouseup = function() {
         var selectedContent = document.getElementById(elementId);
diff --git a/LayoutTests/fast/regions/selection/position-for-point-1-expected.txt b/LayoutTests/fast/regions/selection/position-for-point-1-expected.txt
new file mode 100644 (file)
index 0000000..38976bf
--- /dev/null
@@ -0,0 +1,15 @@
+word1 inside region inside region inside region inside region inside region inside region inside region inside region word2 inside region inside region inside region inside region word5 inside region inside region inside region inside region inside region inside region inside region inside region word6
+word3 outside region outside region outside region outside region word4
+Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block
+
+Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+
+Test 1) Select the entire content of "region-1" and move down without leaving the region. Focus should be at the last word rendered by "region-1" block. Selected content should be the entire "region-1" block. PASS
+
+Test 2) Select the entire content of "region-1" and move down until reaching the region border. Focus should be at at the last word rendered by "region-1" block. Selected content should be the entire "region-1" block. PASS
+
+Test 3) Select the entire content of "region-1" and move down leaving the block without entering in the next element. Focus should be at at the beginning of the "outside" block. Selected content should go from "word1" to "word2" and from "word5" to "word6". PASS
+
+Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at the first word rendered by the "region-2" block. Selected content should be the whole "region-2" content. PASS
+
+Test 5) Select the entire content of "region-2" and move down without leaving the region. Focus should be at the end of "word6". Selected content should be the entire "region-2" block. PASS
diff --git a/LayoutTests/fast/regions/selection/position-for-point-1-vert-lr-expected.txt b/LayoutTests/fast/regions/selection/position-for-point-1-vert-lr-expected.txt
new file mode 100644 (file)
index 0000000..215e0cb
--- /dev/null
@@ -0,0 +1,15 @@
+word1 inside region inside region inside region word2 inside region inside region inside region inside region word5 inside region inside region inside region inside region inside region word6
+word3 outside region outside region outside region outside region word4
+Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block
+
+Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+
+Test 1) Select the entire content of "region-1" and move down without leaving the region. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. PASS
+
+Test 2) Select the entire content of "region-1" and move down until reaching the region border. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. PASS
+
+Test 3) Select the entire content of "region-1" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6".PASS
+
+Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at the first word rendered by the "region-2" block. Selected content should be the whole "region-2" content.PASS
+
+Test 5) Select the entire content of "region-2" and move down without leaving the region. Focus should be at the end of "word6". Selected content should be the entire "region-2" content. PASS
diff --git a/LayoutTests/fast/regions/selection/position-for-point-1-vert-lr.html b/LayoutTests/fast/regions/selection/position-for-point-1-vert-lr.html
new file mode 100644 (file)
index 0000000..4b11252
--- /dev/null
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html style="-webkit-writing-mode: vertical-lr; font: 14px/1.25 monospace;">
+<head>
+    <link rel="stylesheet" href="../resources/region-style.css"></link>
+    <style>
+        .region {
+            height: 120px;
+            width: 170px;
+            padding: 10px;
+            margin: 0px 50px 0px 50px;
+            border: 5px solid black;
+        }
+
+        #outside {
+            height: 120px;
+            width: 170px;
+            margin: 0px 50px 0px 50px;
+            padding: 10px;
+            border: 5px solid black;
+        }
+
+        #debug {
+            border: 1px solid black;
+        }
+    </style>
+    <script src="../resources/helper.js"></script>
+    <script>
+        onMouseUpLogSelectionAndFocus("selected-content", "focus-node", "focus-offset");
+    </script>
+    <script>
+        function clearSelection() {
+           mouseClick(0, 0);
+        }
+
+        function checkResult(id, content) {
+            var sel = window.getSelection();
+            var node = sel['focusNode'];
+            var focusId = node.id;
+            var selected = sel.getRangeAt(0).toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+            var result = (selected == content);
+            document.getElementById(id).innerHTML = result ? "PASS" : "FAIL";
+            if (!result) {
+              console.log("Selection: " + selected + "\n");
+              console.log("Should be: " + content + "\n");
+            }
+        }
+
+        function selectText() {
+            if (window.testRunner) {
+                window.testRunner.dumpAsText();
+
+                var selectedText = document.getElementById("debug");
+                selectedText.style.display = "none";
+
+                var region1 = document.getElementById("region-1");
+                var outside = document.getElementById("outside");
+                var region2 = document.getElementById("region-2");
+
+                var region1Rect = region1.getBoundingClientRect();
+                var outsideRect = outside.getBoundingClientRect();
+                var region2Rect = region2.getBoundingClientRect();
+
+                var region1Data = region1.webkitGetRegionFlowRanges()[0].toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+                var region2Data = region2.webkitGetRegionFlowRanges()[0].toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.left, region1Rect.top, region1Rect.right - 10, region1Rect.bottom);
+                checkResult("result1", region1Data);
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.left, region1Rect.top, region1Rect.right - 2 , region1Rect.bottom);
+                checkResult("result2", region1Data);
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.left, region1Rect.top, region1Rect.right, region1Rect.bottom);
+                checkResult("result3", region1Data + region2Data);
+
+                clearSelection();
+
+                selectContentByRange(outsideRect.left, outsideRect.top, outsideRect.right + 20 , outsideRect.bottom);
+                checkResult("result4", region2Data);
+
+                clearSelection();
+
+                selectContentByRange(region2Rect.left, region2Rect.top, region2Rect.right - 10, region2Rect.bottom);
+                checkResult("result5", region2Data);
+            }
+        }
+    </script>
+</head>
+<body onload="selectText();">
+    <div id="source" class="flowArticle">
+        <span id="word1" class="token">word1</span> inside region inside region inside region <span id="word2" class="token">word2</span> inside region inside region inside region inside region <span id="word5" class="token">word5</span> inside region inside region inside region inside region inside region <span id="word6" class="token">word6</span>
+    </div>
+    <div id="region-1" class="regionArticle greyBigBox region"></div>
+    <div id="outside"><span id="word3" class="token">word3</span> outside region outside region outside region outside region <span id="word4" class="token">word4</span></div>
+    <div id="region-2" class="regionArticle greyBigBox region"></div>
+    <div id="desc" class="description">
+        <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=120769">Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block</a></h1>
+        <p>Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just
+          adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+        </p>
+        <p>Test 1) Select the entire content of "region-1" and move down without leaving the region. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. <span id="result1"></span></p>
+        <p>Test 2) Select the entire content of "region-1" and move down until reaching the region border. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. <span id="result2"></span></p>
+        <p>Test 3) Select the entire content of "region-1" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6".<span id="result3"></span></p>
+        <p>Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at the first word rendered by the "region-2" block. Selected content should be the whole "region-2" content.<span id="result4"></span></p>
+        <p>Test 5) Select the entire content of "region-2" and move down without leaving the region. Focus should be at the end of "word6". Selected content should be the entire "region-2" content. <span id="result5"></span></p>
+    </div>
+    <div id="debug">
+        <ul>
+            <li>Focus node: <span id="focus-node"></span></li>
+            <li>Focus offset: <span id="focus-offset"></span></li>
+            <li>Selected content: <span id="selected-content"></span></li>
+        </ul>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/regions/selection/position-for-point-1-vert-rl-expected.txt b/LayoutTests/fast/regions/selection/position-for-point-1-vert-rl-expected.txt
new file mode 100644 (file)
index 0000000..215e0cb
--- /dev/null
@@ -0,0 +1,15 @@
+word1 inside region inside region inside region word2 inside region inside region inside region inside region word5 inside region inside region inside region inside region inside region word6
+word3 outside region outside region outside region outside region word4
+Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block
+
+Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+
+Test 1) Select the entire content of "region-1" and move down without leaving the region. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. PASS
+
+Test 2) Select the entire content of "region-1" and move down until reaching the region border. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. PASS
+
+Test 3) Select the entire content of "region-1" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6".PASS
+
+Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at the first word rendered by the "region-2" block. Selected content should be the whole "region-2" content.PASS
+
+Test 5) Select the entire content of "region-2" and move down without leaving the region. Focus should be at the end of "word6". Selected content should be the entire "region-2" content. PASS
diff --git a/LayoutTests/fast/regions/selection/position-for-point-1-vert-rl.html b/LayoutTests/fast/regions/selection/position-for-point-1-vert-rl.html
new file mode 100644 (file)
index 0000000..c84eb04
--- /dev/null
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html style="-webkit-writing-mode: vertical-rl; font: 14px/1.25 monospace">
+<head>
+    <link rel="stylesheet" href="../resources/region-style.css"></link>
+    <style>
+        .region {
+            height: 120px;
+            width: 170px;
+            padding: 10px;
+            margin: 0px 50px 0px 50px;
+            border: 5px solid black;
+        }
+
+        #outside {
+            height: 120px;
+            width: 170px;
+            margin: 0px 50px 0px 50px;
+            padding: 10px;
+            border: 5px solid black;
+        }
+
+        #debug {
+            border: 1px solid black;
+        }
+    </style>
+    <script src="../resources/helper.js"></script>
+    <script>
+        onMouseUpLogSelectionAndFocus("selected-content", "focus-node", "focus-offset");
+    </script>
+    <script>
+        function clearSelection() {
+           mouseClick(0, 0);
+        }
+
+        function checkResult(id, content) {
+            var sel = window.getSelection();
+            var node = sel['focusNode'];
+            var focusId = node.id;
+            var selected = sel.getRangeAt(0).toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+            var result = (selected == content);
+            document.getElementById(id).innerHTML = result ? "PASS" : "FAIL";
+            if (!result) {
+              console.log("Selection: " + selected + "\n");
+              console.log("Should be: " + content + "\n");
+            }
+        }
+
+        function selectText() {
+            if (window.testRunner) {
+                window.testRunner.dumpAsText();
+
+                var selectedText = document.getElementById("debug");
+                selectedText.style.display = "none";
+
+                var region1 = document.getElementById("region-1");
+                var outside = document.getElementById("outside");
+                var region2 = document.getElementById("region-2");
+
+                var region1Rect = region1.getBoundingClientRect();
+                var outsideRect = outside.getBoundingClientRect();
+                var region2Rect = region2.getBoundingClientRect();
+
+                var region1Data = region1.webkitGetRegionFlowRanges()[0].toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+                var region2Data = region2.webkitGetRegionFlowRanges()[0].toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.right, region1Rect.top, region1Rect.left + 10, region1Rect.bottom);
+                checkResult("result1", region1Data);
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.right, region1Rect.top, region1Rect.left, region1Rect.bottom);
+                checkResult("result2", region1Data);
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.right, region1Rect.top, region1Rect.left - 1, region1Rect.bottom);
+                checkResult("result3", region1Data + region2Data);
+
+                clearSelection();
+
+                selectContentByRange(outsideRect.right, outsideRect.top, outsideRect.left - 20 , outsideRect.bottom);
+                checkResult("result4", region2Data);
+
+                clearSelection();
+
+                selectContentByRange(region2Rect.right, region2Rect.top, region2Rect.left + 10, region2Rect.bottom);
+                checkResult("result5", region2Data);
+            }
+        }
+    </script>
+</head>
+<body onload="selectText();">
+    <div id="source" class="flowArticle">
+        <span id="word1" class="token">word1</span> inside region inside region inside region <span id="word2" class="token">word2</span> inside region inside region inside region inside region <span id="word5" class="token">word5</span> inside region inside region inside region inside region inside region <span id="word6" class="token">word6</span>
+    </div>
+    <div id="region-1" class="regionArticle greyBigBox region"></div>
+    <div id="outside"><span id="word3" class="token">word3</span> outside region outside region outside region outside region <span id="word4" class="token">word4</span></div>
+    <div id="region-2" class="regionArticle greyBigBox region"></div>
+    <div id="desc" class="description">
+        <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=120769">Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block</a></h1>
+        <p>Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just
+          adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+        </p>
+        <p>Test 1) Select the entire content of "region-1" and move down without leaving the region. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. <span id="result1"></span></p>
+        <p>Test 2) Select the entire content of "region-1" and move down until reaching the region border. Focus should be at the end of "region-1" content. Selected content should be the entire "region-1" content. <span id="result2"></span></p>
+        <p>Test 3) Select the entire content of "region-1" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6".<span id="result3"></span></p>
+        <p>Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at the first word rendered by the "region-2" block. Selected content should be the whole "region-2" content.<span id="result4"></span></p>
+        <p>Test 5) Select the entire content of "region-2" and move down without leaving the region. Focus should be at the end of "word6". Selected content should be the entire "region-2" content. <span id="result5"></span></p>
+    </div>
+    <div id="debug">
+        <ul>
+            <li>Focus node: <span id="focus-node"></span></li>
+            <li>Focus offset: <span id="focus-offset"></span></li>
+            <li>Selected content: <span id="selected-content"></span></li>
+        </ul>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/regions/selection/position-for-point-1.html b/LayoutTests/fast/regions/selection/position-for-point-1.html
new file mode 100644 (file)
index 0000000..ecba7fe
--- /dev/null
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html style="font: 14px/1.25 monospace;">
+<head>
+    <link rel="stylesheet" href="../resources/region-style.css"></link>
+    <style>
+        .region {
+            padding: 10px;
+            margin: 50px 0px 50px 0px;
+            border: 5px solid black;
+        }
+
+        #outside {
+            height: 100px;
+            width: 300px;
+            margin: 50px 0px 50px 0px;
+            padding: 10px;
+            border: 5px solid black;
+        }
+
+        #debug {
+            border: 1px solid black;
+        }
+    </style>
+    <script src="../resources/helper.js"></script>
+    <script>
+        onMouseUpLogSelectionAndFocus("selected-content", "focus-node", "focus-offset");
+    </script>
+    <script>
+        function clearSelection() {
+           mouseClick(0, 0);
+        }
+
+        function checkResult(id, content) {
+            var sel = window.getSelection();
+            var node = sel['focusNode'];
+            var focusId = node.id;
+            var selected = sel.getRangeAt(0).toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+            var result = (selected == content);
+            document.getElementById(id).innerHTML = result ? "PASS" : "FAIL";
+            if (!result) {
+              console.log("Selection: " + selected + "\n");
+              console.log("Should be: " + content + "\n");
+            }
+        }
+
+        function selectText() {
+            if (window.testRunner) {
+                window.testRunner.dumpAsText();
+
+                var selectedText = document.getElementById("debug");
+                selectedText.style.display = "none";
+
+                var region1 = document.getElementById("region-1");
+                var outside = document.getElementById("outside");
+                var region2 = document.getElementById("region-2");
+
+                var region1Rect = region1.getBoundingClientRect();
+                var outsideRect = outside.getBoundingClientRect();
+                var region2Rect = region2.getBoundingClientRect();
+
+                var region1Data = region1.webkitGetRegionFlowRanges()[0].toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+                var region2Data = region2.webkitGetRegionFlowRanges()[0].toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, "");
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.left, region1Rect.top, region1Rect.right, region1Rect.bottom - 10);
+                checkResult("result1", region1Data);
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.left, region1Rect.top, region1Rect.right, region1Rect.bottom - 2);
+                checkResult("result2", region1Data);
+
+                clearSelection();
+
+                selectContentByRange(region1Rect.left, region1Rect.top, region1Rect.right, region1Rect.bottom);
+                checkResult("result3", region1Data + region2Data);
+
+                clearSelection();
+
+                selectContentByRange(outsideRect.left, outsideRect.top, outsideRect.right , outsideRect.bottom + 20);
+                checkResult("result4", region2Data);
+
+                clearSelection();
+
+                selectContentByRange(region2Rect.left, region2Rect.top, region2Rect.right, region2Rect.bottom - 10);
+                checkResult("result5", region2Data);
+            }
+        }
+    </script>
+</head>
+<body onload="selectText();">
+    <div id="source" class="flowArticle">
+        <span id="word1" class="token">word1</span> inside region inside region inside region inside region inside region inside region inside region inside region <span id="word2" class="token">word2</span> inside region inside region inside region inside region <span id="word5" class="token">word5</span> inside region inside region inside region inside region inside region inside region inside region inside region <span id="word6" class="token">word6</span>
+    </div>
+    <div id="region-1" class="regionArticle greyBigBox region"></div>
+    <div id="outside"><span id="word3" class="token">word3</span> outside region outside region outside region outside region <span id="word4" class="token">word4</span></div>
+    <div id="region-2" class="regionArticle greyBigBox region"></div>
+    <div id="desc" class="description">
+        <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=120769">Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block</a></h1>
+        <p>Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just
+          adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+        </p>
+        <p>Test 1) Select the entire content of "region-1" and move down without leaving the region. Focus should be at the last word rendered by "region-1" block. Selected content should be the entire "region-1" block. <span id="result1"></span></p>
+        <p>Test 2) Select the entire content of "region-1" and move down until reaching the region border. Focus should be at at the last word rendered by "region-1" block. Selected content should be the entire "region-1" block. <span id="result2"></span></p>
+        <p>Test 3) Select the entire content of "region-1" and move down leaving the block without entering in the next element. Focus should be at at the beginning of the "outside" block. Selected content should go from "word1" to "word2" and from "word5" to "word6". <span id="result3"></span></p>
+        <p>Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at the first word rendered by the "region-2" block. Selected content should be the whole "region-2" content. <span id="result4"></span></p>
+        <p>Test 5) Select the entire content of "region-2" and move down without leaving the region. Focus should be at the end of "word6". Selected content should be the entire "region-2" block. <span id="result5"></span></p>
+    </div>
+    <div id="debug">
+        <ul>
+            <li>Focus node: <span id="focus-node"></span></li>
+            <li>Focus offset: <span id="focus-offset"></span></li>
+            <li>Selected content: <span id="selected-content"></span></li>
+        </ul>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/regions/selection/position-for-point-expected.txt b/LayoutTests/fast/regions/selection/position-for-point-expected.txt
new file mode 100644 (file)
index 0000000..0270d52
--- /dev/null
@@ -0,0 +1,16 @@
+word1 inside region inside region inside region inside region word2
+word5 inside region inside region inside region inside region word6
+word3 outside region outside region outside region outside region word4
+Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block
+
+Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+
+Test 1) Select from "word1" to "word2" and move down without leaving the region. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". PASS
+
+Test 2) Select from "word1" to "word2" and move down until reaching the region border. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". PASS
+
+Test 3) Select from "word1" to "word2" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6". PASS
+
+Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "word5". Selected content should go from "word5" to "word6". PASS
+
+Test 5) Select from "word5" to "word6" and move down without leaving the region. Focus should be at the end of "word6". Selected content should go from "word5" to "word6". PASS
diff --git a/LayoutTests/fast/regions/selection/position-for-point-vert-lr-expected.txt b/LayoutTests/fast/regions/selection/position-for-point-vert-lr-expected.txt
new file mode 100644 (file)
index 0000000..0270d52
--- /dev/null
@@ -0,0 +1,16 @@
+word1 inside region inside region inside region inside region word2
+word5 inside region inside region inside region inside region word6
+word3 outside region outside region outside region outside region word4
+Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block
+
+Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+
+Test 1) Select from "word1" to "word2" and move down without leaving the region. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". PASS
+
+Test 2) Select from "word1" to "word2" and move down until reaching the region border. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". PASS
+
+Test 3) Select from "word1" to "word2" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6". PASS
+
+Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "word5". Selected content should go from "word5" to "word6". PASS
+
+Test 5) Select from "word5" to "word6" and move down without leaving the region. Focus should be at the end of "word6". Selected content should go from "word5" to "word6". PASS
diff --git a/LayoutTests/fast/regions/selection/position-for-point-vert-lr.html b/LayoutTests/fast/regions/selection/position-for-point-vert-lr.html
new file mode 100644 (file)
index 0000000..434fa45
--- /dev/null
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html style="-webkit-writing-mode: vertical-lr; font: 14px/1.25 monospace;">
+<head>
+    <link rel="stylesheet" href="../resources/region-style.css"></link>
+    <style>
+        .region {
+            width: 200px;
+            margin: 0px 50px 0px 50px;
+            border: 5px solid black;
+        }
+
+        #outside {
+            height: 100px;
+            width: 200px;
+            margin: 0px 50px 0px 50px;
+            border: 5px solid black;
+        }
+
+        #debug {
+            border: 1px solid black;
+        }
+    </style>
+    <script src="../resources/helper.js"></script>
+    <script>
+        onMouseUpLogSelectionAndFocus("selected-content", "focus-node", "focus-offset");
+    </script>
+    <script>
+        function clearSelection() {
+           mouseClick(0, 0);
+        }
+
+        function checkResult(id, nodeId, offset, content) {
+            var sel = window.getSelection();
+            var node = sel['focusNode'];
+            var focusId = node.id;
+            var selected = sel.getRangeAt(0).toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, " ");;
+            if (node.nodeType == 3)
+              focusId =  node.parentNode.id;
+            var result = (focusId == nodeId) && (sel['focusOffset'] == offset) && (selected == content);
+            document.getElementById(id).innerHTML = result ? "PASS" : "FAIL";
+            if (!result)
+               console.log("Focus: " + focusId + " offset: " + sel['focusOffset'] + " selected: " + selected);
+        }
+
+        function selectText() {
+            if (window.testRunner) {
+                window.testRunner.dumpAsText();
+
+                var selectedText = document.getElementById("debug");
+                selectedText.style.display = "none";
+
+                var region1 = document.getElementById("region-1");
+                var outside = document.getElementById("outside");
+                var region2 = document.getElementById("region-2");
+
+                var region1Rect = region1.getBoundingClientRect();
+                var outsideRect = outside.getBoundingClientRect();
+                var region2Rect = region2.getBoundingClientRect();
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word1", region1Rect.right - 10 , region1Rect.bottom);
+                checkResult("result1", "word2", "5", "word1 inside region inside region inside region inside region word2");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word1", region1Rect.right - 2, region1Rect.bottom);
+                checkResult("result2", "word2", "5", "word1 inside region inside region inside region inside region word2");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word1", region1Rect.right, region1Rect.bottom);
+                checkResult("result3", "outside", "0", "word1 inside region inside region inside region inside region word2 word5 inside region inside region inside region inside region word6 ");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word3", outsideRect.right + 20 , outsideRect.bottom);
+                checkResult("result4", "word5", "0", "word5 inside region inside region inside region inside region word6 ");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word5", region2Rect.right - 10, region2Rect.bottom);
+                checkResult("result5", "word6", "5", "word5 inside region inside region inside region inside region word6");
+            }
+        }
+    </script>
+</head>
+<body onload="selectText();">
+    <div id="source" class="flowArticle">
+        <span id="word1" class="token">word1</span> inside region inside region inside region inside region <span id="word2" class="token">word2</span>
+        <span class="break"></span>
+        <span id="word5" class="token">word5</span> inside region inside region inside region inside region <span id="word6" class="token">word6</span>
+    </div>
+    <div id="region-1" class="regionArticle greyBigBox region"></div>
+    <div id="outside"><span id="word3" class="token">word3</span> outside region outside region outside region outside region <span id="word4" class="token">word4</span></div>
+    <div id="region-2" class="regionArticle greyBigBox region"></div>
+    <div id="desc" class="description">
+        <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=120769">Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block</a></h1>
+        <p>Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just
+          adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+        </p>
+        <p>Test 1) Select from "word1" to "word2" and move down without leaving the region. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". <span id="result1"></span></p>
+        <p>Test 2) Select from "word1" to "word2" and move down until reaching the region border. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". <span id="result2"></span></p>
+        <p>Test 3) Select from "word1" to "word2" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6". <span id="result3"></span></p>
+        <p>Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "word5". Selected content should go from "word5" to "word6". <span id="result4"></span></p>
+        <p>Test 5) Select from "word5" to "word6" and move down without leaving the region. Focus should be at the end of "word6". Selected content should go from "word5" to "word6". <span id="result5"></span></p>
+    </div>
+    <div id="debug">
+        <ul>
+            <li>Focus node: <span id="focus-node"></span></li>
+            <li>Focus offset: <span id="focus-offset"></span></li>
+            <li>Selected content: <span id="selected-content"></span></li>
+         </ul>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/regions/selection/position-for-point-vert-rl-expected.txt b/LayoutTests/fast/regions/selection/position-for-point-vert-rl-expected.txt
new file mode 100644 (file)
index 0000000..0270d52
--- /dev/null
@@ -0,0 +1,16 @@
+word1 inside region inside region inside region inside region word2
+word5 inside region inside region inside region inside region word6
+word3 outside region outside region outside region outside region word4
+Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block
+
+Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+
+Test 1) Select from "word1" to "word2" and move down without leaving the region. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". PASS
+
+Test 2) Select from "word1" to "word2" and move down until reaching the region border. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". PASS
+
+Test 3) Select from "word1" to "word2" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6". PASS
+
+Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "word5". Selected content should go from "word5" to "word6". PASS
+
+Test 5) Select from "word5" to "word6" and move down without leaving the region. Focus should be at the end of "word6". Selected content should go from "word5" to "word6". PASS
diff --git a/LayoutTests/fast/regions/selection/position-for-point-vert-rl.html b/LayoutTests/fast/regions/selection/position-for-point-vert-rl.html
new file mode 100644 (file)
index 0000000..bc45270
--- /dev/null
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html style="-webkit-writing-mode: vertical-rl; font: 14px/1.25 monospace;">
+<head>
+    <link rel="stylesheet" href="../resources/region-style.css"></link>
+    <style>
+        .region {
+            width: 200px;
+            margin: 0px 50px 0px 50px;
+            border: 5px solid black;
+        }
+
+        #outside {
+            height: 100px;
+            width: 200px;
+            margin: 0px 50px 0px 50px;
+            border: 5px solid black;
+        }
+
+        #debug {
+            border: 1px solid black;
+        }
+    </style>
+    <script src="../resources/helper.js"></script>
+    <script>
+        onMouseUpLogSelectionAndFocus("selected-content", "focus-node", "focus-offset");
+    </script>
+    <script>
+        function clearSelection() {
+           mouseClick(0, 0);
+        }
+
+        function checkResult(id, nodeId, offset, content) {
+            var sel = window.getSelection();
+            var node = sel['focusNode'];
+            var focusId = node.id;
+            var selected = sel.getRangeAt(0).toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, " ");;
+            if (node.nodeType == 3)
+              focusId =  node.parentNode.id;
+            var result = (focusId == nodeId) && (sel['focusOffset'] == offset) && (selected == content);
+            document.getElementById(id).innerHTML = result ? "PASS" : "FAIL";
+            if (!result)
+               console.log("Focus: " + focusId + " offset: " + sel['focusOffset'] + " selected: " + selected);
+        }
+
+        function selectText() {
+            if (window.testRunner) {
+                window.testRunner.dumpAsText();
+
+                var selectedText = document.getElementById("debug");
+                selectedText.style.display = "none";
+
+                var region1 = document.getElementById("region-1");
+                var outside = document.getElementById("outside");
+                var region2 = document.getElementById("region-2");
+
+                var region1Rect = region1.getBoundingClientRect();
+                var outsideRect = outside.getBoundingClientRect();
+                var region2Rect = region2.getBoundingClientRect();
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word1", region1Rect.left + 10, region1Rect.bottom);
+                checkResult("result1", "word2", "5", "word1 inside region inside region inside region inside region word2");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word1", region1Rect.left, region1Rect.bottom);
+                checkResult("result2", "word2", "5", "word1 inside region inside region inside region inside region word2");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word1", region1Rect.left - 1, region1Rect.bottom);
+                checkResult("result3", "outside", "0", "word1 inside region inside region inside region inside region word2 word5 inside region inside region inside region inside region word6 ");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word3", outsideRect.left - 20, outsideRect.bottom);
+                checkResult("result4", "word5", "0", "word5 inside region inside region inside region inside region word6 ");
+
+                clearSelection();
+
+                selectContentFromIdToPosVert("word5", region2Rect.left, region2Rect.bottom);
+                checkResult("result5", "word6", "5", "word5 inside region inside region inside region inside region word6");
+            }
+        }
+    </script>
+</head>
+<body onload="selectText();">
+    <div id="source" class="flowArticle">
+        <span id="word1" class="token">word1</span> inside region inside region inside region inside region <span id="word2" class="token">word2</span>
+        <span class="break"></span>
+        <span id="word5" class="token">word5</span> inside region inside region inside region inside region <span id="word6" class="token">word6</span>
+    </div>
+    <div id="region-1" class="regionArticle greyBigBox region"></div>
+    <div id="outside"><span id="word3" class="token">word3</span> outside region outside region outside region outside region <span id="word4" class="token">word4</span></div>
+    <div id="region-2" class="regionArticle greyBigBox region"></div>
+    <div id="desc" class="description">
+        <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=120769">Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block</a></h1>
+        <p>Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just
+          adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+        </p>
+        <p>Test 1) Select from "word1" to "word2" and move down without leaving the region. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". <span id="result1"></span></p>
+        <p>Test 2) Select from "word1" to "word2" and move down until reaching the region border. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". <span id="result2"></span></p>
+        <p>Test 3) Select from "word1" to "word2" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6". <span id="result3"></span></p>
+        <p>Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "word5". Selected content should go from "word5" to "word6". <span id="result4"></span></p>
+        <p>Test 5) Select from "word5" to "word6" and move down without leaving the region. Focus should be at the end of "word6". Selected content should go from "word5" to "word6". <span id="result5"></span></p>
+    </div>
+    <div id="debug">
+        <ul>
+            <li>Focus node: <span id="focus-node"></span></li>
+            <li>Focus offset: <span id="focus-offset"></span></li>
+            <li>Selected content: <span id="selected-content"></span></li>
+        </ul>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/regions/selection/position-for-point.html b/LayoutTests/fast/regions/selection/position-for-point.html
new file mode 100644 (file)
index 0000000..9650af7
--- /dev/null
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html style="font: 14px/1.25 monospace;">
+<head>
+    <link rel="stylesheet" href="../resources/region-style.css"></link>
+    <style>
+        .region {
+            margin: 50px 0px 50px 0px;
+            border: 5px solid black;
+        }
+
+        #outside {
+            height: 100px;
+            width: 300px;
+            margin: 50px 0px 50px 0px;
+            border: 5px solid black;
+        }
+
+        #debug {
+            border: 1px solid black;
+        }
+    </style>
+    <script src="../resources/helper.js"></script>
+    <script>
+        onMouseUpLogSelectionAndFocus("selected-content", "focus-node", "focus-offset");
+    </script>
+    <script>
+        function clearSelection() {
+           mouseClick(0, 0);
+        }
+
+        function checkResult(id, nodeId, offset, content) {
+            var sel = window.getSelection();
+            var node = sel['focusNode'];
+            var focusId = node.id;
+            var selected = sel.getRangeAt(0).toString().replace(/(\r\n|\n|\r)/gm,"").replace(/\s+/gm, " ");;
+            if (node.nodeType == 3)
+              focusId =  node.parentNode.id;
+            var result = (focusId == nodeId) && (sel['focusOffset'] == offset) && (selected == content);
+            document.getElementById(id).innerHTML = result ? "PASS" : "FAIL";
+            if (!result) {
+                console.log("Focus: " + focusId + " offset: " + sel['focusOffset'] + " selected: " + selected + "\n");
+            }
+        }
+
+        function selectText() {
+            if (window.testRunner) {
+                window.testRunner.dumpAsText();
+
+                var selectedText = document.getElementById("debug");
+                selectedText.style.display = "none";
+
+                var region1 = document.getElementById("region-1");
+                var outside = document.getElementById("outside");
+                var region2 = document.getElementById("region-2");
+
+                var region1Rect = region1.getBoundingClientRect();
+                var outsideRect = outside.getBoundingClientRect();
+                var region2Rect = region2.getBoundingClientRect();
+
+                clearSelection();
+
+                selectContentFromIdToPos("word1", region1Rect.right, region1Rect.bottom - 10);
+                checkResult("result1", "word2", "5", "word1 inside region inside region inside region inside region word2");
+
+                clearSelection();
+
+                selectContentFromIdToPos("word1", region1Rect.right, region1Rect.bottom - 2);
+                checkResult("result2", "word2", "5", "word1 inside region inside region inside region inside region word2");
+
+                clearSelection();
+
+                selectContentFromIdToPos("word1", region1Rect.right, region1Rect.bottom);
+                checkResult("result3", "outside", "0", "word1 inside region inside region inside region inside region word2 word5 inside region inside region inside region inside region word6 ");
+
+                clearSelection();
+
+                selectContentFromIdToPos("word3", outsideRect.right , outsideRect.bottom + 20);
+                checkResult("result4", "word5", "0", "word5 inside region inside region inside region inside region word6 ");
+
+                clearSelection();
+
+                selectContentFromIdToPos("word5", region2Rect.right, region2Rect.bottom - 10);
+                checkResult("result5", "word6", "5", "word5 inside region inside region inside region inside region word6");
+            }
+        }
+    </script>
+</head>
+<body onload="selectText();">
+    <div id="source" class="flowArticle">
+        <span id="word1" class="token">word1</span> inside region inside region inside region inside region <span id="word2" class="token">word2</span>
+        <span class="break"></span>
+        <span id="word5" class="token">word5</span> inside region inside region inside region inside region <span id="word6" class="token">word6</span>
+    </div>
+    <div id="region-1" class="regionArticle greyBigBox region"></div>
+    <div id="outside"><span id="word3" class="token">word3</span> outside region outside region outside region outside region <span id="word4" class="token">word4</span></div>
+    <div id="region-2" class="regionArticle greyBigBox region"></div>
+    <div id="desc" class="description">
+        <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=120769">Bug #120769 - [CSSRegions] Selection focusNode set to the "region" block, instead of the "source" block</a></h1>
+        <p>Top margin, padding and border points should be mapped to the beginning of the Region block, while bottom points are mapped to the block end. The Left coordinate its just
+          adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow direction.
+        </p>
+        <p>Test 1) Select from "word1" to "word2" and move down without leaving the region. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". <span id="result1"></span></p>
+        <p>Test 2) Select from "word1" to "word2" and move down until reaching the region border. Focus should be at the end of "word2". Selected content should go from "word1" to "word2". <span id="result2"></span></p>
+        <p>Test 3) Select from "word1" to "word2" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "outside". Selected content should go from "word1" to "word2" and from "word5" to "word6". <span id="result3"></span></p>
+        <p>Test 4) Select from "word3" to "word4" and move down leaving the block without entering in the next element. Focus should be at at the beginning of "word5". Selected content should go from "word5" to "word6". <span id="result4"></span></p>
+        <p>Test 5) Select from "word5" to "word6" and move down without leaving the region. Focus should be at the end of "word6". Selected content should go from "word5" to "word6". <span id="result5"></span></p>
+    </div>
+    <div id="debug">
+        <ul>
+            <li>Focus node: <span id="focus-node"></span></li>
+            <li>Focus offset: <span id="focus-offset"></span></li>
+            <li>Selected content: <span id="selected-content"></span></li>
+        </ul>
+    </div>
+</body>
+</html>
index 9c032c8..35f018f 100644 (file)
@@ -1,3 +1,49 @@
+2013-11-11  Javier Fernandez  <jfernandez@igalia.com>
+
+        [CSS Regions] Selection focusNode set to the "region" block, instead of the "source" block
+        https://bugs.webkit.org/show_bug.cgi?id=120769
+
+        Reviewed by David Hyatt.
+
+        When a point hits a Region block, current positionForPoint algorithm determines its
+        position in the DOM and returns either the start or end offset for such block, since
+        Region blocks have no children in the DOM.
+
+        It's necessary to map the point into Flow Thread coordinates in order to determine
+        the DOM position of the specific element rendered by the Region.
+
+        Top margin, padding and border points should be mapped to the beginning of the Region
+        block, while bottom points are mapped to the block end. The Left coordinate its just
+        adjusted to fit in the Flow Thread boundaries, since its not affected by the Flow
+        direction.
+
+        Besides, when inspecting the Flow Thread blocks looking for the last candidate box,
+        the Region originally associated to the point might be taken into account. Only the
+        blocks/boxes rendered by the Region are potential candidates.
+
+        Tests: fast/regions/selection/position-for-point-1-vert-lr.html
+               fast/regions/selection/position-for-point-1-vert-rl.html
+               fast/regions/selection/position-for-point-1.html
+               fast/regions/selection/position-for-point-vert-lr.html
+               fast/regions/selection/position-for-point-vert-rl.html
+               fast/regions/selection/position-for-point.html
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::isChildHitTestCandidate):
+        (WebCore::RenderBlock::positionForPoint):
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::positionForPoint): Added.
+        It just redirects the call to the associated RenderNamedFlowFragment instance.
+        * rendering/RenderBlockFlow.h:
+        * rendering/RenderRegion.cpp:
+        (WebCore::RenderRegion::mapRegionPointIntoFlowThreadCoordinates): Added.
+        It performs the coordinates mapping.
+        (WebCore::RenderRegion::positionForPoint): Added.
+        It determines the corresponding LayoutPoint in the FlowThread the Region
+        is associated to, forwarding the call to the RenderBlock class using the
+        FlowThread's first child block and such new point.
+        * rendering/RenderRegion.h:
+
 2013-11-11  Gergo Balogh  <geryxyz@inf.u-szeged.hu>
 
         [curl] Remove unused includes.
index 76d02b2..89e6990 100644 (file)
@@ -55,6 +55,7 @@
 #include "RenderIterator.h"
 #include "RenderLayer.h"
 #include "RenderMarquee.h"
+#include "RenderNamedFlowFragment.h"
 #include "RenderNamedFlowThread.h"
 #include "RenderRegion.h"
 #include "RenderTableCell.h"
@@ -3465,11 +3466,22 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const LayoutPoin
     return VisiblePosition();
 }
 
-static inline bool isChildHitTestCandidate(RenderBox& box)
+static inline bool isChildHitTestCandidate(const RenderBox& box)
 {
     return box.height() && box.style().visibility() == VISIBLE && !box.isFloatingOrOutOfFlowPositioned();
 }
 
+// Valid candidates in a FlowThread must be rendered by the region.
+static inline bool isChildHitTestCandidate(const RenderBox& box, RenderRegion* region, const LayoutPoint& point)
+{
+    if (!isChildHitTestCandidate(box))
+        return false;
+    if (!region)
+        return true;
+    const RenderBlock& block = box.isRenderBlock() ? toRenderBlock(box) : *box.containingBlock();
+    return block.regionAtBlockOffset(point.y()) == region;
+}
+
 VisiblePosition RenderBlock::positionForPoint(const LayoutPoint& point)
 {
     if (isTable())
@@ -3495,8 +3507,9 @@ VisiblePosition RenderBlock::positionForPoint(const LayoutPoint& point)
     if (childrenInline())
         return positionForPointWithInlineChildren(pointInLogicalContents);
 
+    RenderRegion* region = regionAtBlockOffset(pointInLogicalContents.y());
     RenderBox* lastCandidateBox = lastChildBox();
-    while (lastCandidateBox && !isChildHitTestCandidate(*lastCandidateBox))
+    while (lastCandidateBox && !isChildHitTestCandidate(*lastCandidateBox, region, pointInLogicalContents))
         lastCandidateBox = lastCandidateBox->previousSiblingBox();
 
     bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
@@ -3506,11 +3519,11 @@ VisiblePosition RenderBlock::positionForPoint(const LayoutPoint& point)
             return positionForPointRespectingEditingBoundaries(*this, *lastCandidateBox, pointInContents);
 
         for (auto childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
-            if (!isChildHitTestCandidate(*childBox))
+            if (!isChildHitTestCandidate(*childBox, region, pointInLogicalContents))
                 continue;
             LayoutUnit childLogicalBottom = logicalTopForChild(*childBox) + logicalHeightForChild(*childBox);
             // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
-            if (isChildHitTestCandidate(*childBox) && (pointInLogicalContents.y() < childLogicalBottom
+            if (isChildHitTestCandidate(*childBox, region, pointInLogicalContents) && (pointInLogicalContents.y() < childLogicalBottom
                 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
                 return positionForPointRespectingEditingBoundaries(*this, *childBox, pointInContents);
         }
index bd192a5..5b4e8a0 100644 (file)
@@ -3052,6 +3052,14 @@ VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const Layout
     return createVisiblePosition(0, DOWNSTREAM);
 }
 
+VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point)
+{
+    if (auto fragment = renderNamedFlowFragment())
+        return fragment->positionForPoint(point);
+    return RenderBlock::positionForPoint(point);
+}
+
+
 void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
 {
     ASSERT(childrenInline());
index 58c0a7e..3caa97e 100644 (file)
@@ -259,6 +259,7 @@ public:
 
     virtual void deleteLines() OVERRIDE;
     virtual void computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats = false) OVERRIDE;
+    virtual VisiblePosition positionForPoint(const LayoutPoint&) OVERRIDE;
 
     void removeFloatingObjects();
     void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = nullptr, bool inLayout = true);
index c5ce8da..5dca338 100644 (file)
@@ -71,6 +71,54 @@ RenderRegion::RenderRegion(Document& document, PassRef<RenderStyle> style, Rende
 {
 }
 
+LayoutPoint RenderRegion::mapRegionPointIntoFlowThreadCoordinates(const LayoutPoint& point)
+{
+    // Assuming the point is relative to the region block, 3 cases will be considered:
+    // a) top margin, padding or border.
+    // b) bottom margin, padding or border.
+    // c) non-content region area.
+
+    LayoutUnit pointLogicalTop(isHorizontalWritingMode() ? point.y() : point.x());
+    LayoutUnit pointLogicalLeft(isHorizontalWritingMode() ? point.x() : point.y());
+    LayoutUnit flowThreadLogicalTop(isHorizontalWritingMode() ? m_flowThreadPortionRect.y() : m_flowThreadPortionRect.x());
+    LayoutUnit flowThreadLogicalLeft(isHorizontalWritingMode() ? m_flowThreadPortionRect.x() : m_flowThreadPortionRect.y());
+    LayoutUnit flowThreadPortionTopBound(isHorizontalWritingMode() ? m_flowThreadPortionRect.height() : m_flowThreadPortionRect.width());
+    LayoutUnit flowThreadPortionLeftBound(isHorizontalWritingMode() ? m_flowThreadPortionRect.width() : m_flowThreadPortionRect.height());
+    LayoutUnit flowThreadPortionTopMax(isHorizontalWritingMode() ? m_flowThreadPortionRect.maxY() : m_flowThreadPortionRect.maxX());
+    LayoutUnit flowThreadPortionLeftMax(isHorizontalWritingMode() ? m_flowThreadPortionRect.maxX() : m_flowThreadPortionRect.maxY());
+    LayoutUnit effectiveFixedPointDenominator;
+    effectiveFixedPointDenominator.setRawValue(1);
+
+    if (pointLogicalTop < 0) {
+        LayoutPoint pointInThread(0, flowThreadLogicalTop);
+        return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
+    }
+
+    if (pointLogicalTop >= flowThreadPortionTopBound) {
+        LayoutPoint pointInThread(flowThreadPortionLeftBound, flowThreadPortionTopMax - effectiveFixedPointDenominator);
+        return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
+    }
+
+    if (pointLogicalLeft < 0) {
+        LayoutPoint pointInThread(flowThreadLogicalLeft, pointLogicalTop + flowThreadLogicalTop);
+        return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
+    }
+    if (pointLogicalLeft >= flowThreadPortionLeftBound) {
+        LayoutPoint pointInThread(flowThreadPortionLeftMax - effectiveFixedPointDenominator, pointLogicalTop + flowThreadLogicalTop);
+        return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
+    }
+    LayoutPoint pointInThread(pointLogicalLeft + flowThreadLogicalLeft, pointLogicalTop + flowThreadLogicalTop);
+    return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
+}
+
+VisiblePosition RenderRegion::positionForPoint(const LayoutPoint& point)
+{
+    if (!m_flowThread->firstChild()) // checking for empty region blocks.
+        return RenderBlock::positionForPoint(point);
+
+    return toRenderBlock(m_flowThread->firstChild())->positionForPoint(mapRegionPointIntoFlowThreadCoordinates(point));
+}
+
 LayoutUnit RenderRegion::pageLogicalWidth() const
 {
     ASSERT(m_flowThread);
index 9355331..1768646 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "RenderBlockFlow.h"
 #include "StyleInheritedData.h"
+#include "VisiblePosition.h"
 
 namespace WebCore {
 
@@ -151,6 +152,7 @@ public:
 
     virtual bool canHaveChildren() const OVERRIDE { return false; }
     virtual bool canHaveGeneratedChildren() const OVERRIDE { return true; }
+    virtual VisiblePosition positionForPoint(const LayoutPoint&) OVERRIDE;
 
 protected:
     RenderRegion(Element&, PassRef<RenderStyle>, RenderFlowThread*);
@@ -198,6 +200,8 @@ private:
     void incrementAutoLogicalHeightCount();
     void decrementAutoLogicalHeightCount();
 
+    LayoutPoint mapRegionPointIntoFlowThreadCoordinates(const LayoutPoint&);
+
 protected:
     RenderFlowThread* m_flowThread;