LayoutTests:
authorjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Jun 2006 22:26:22 +0000 (22:26 +0000)
committerjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Jun 2006 22:26:22 +0000 (22:26 +0000)
        Reviewed by levi

        <rdar://problem/4599735> Clicking out of a table at the extremes of an editable document doesn't appear to work

        Added:
        * editing/selection/click-before-and-after-table-expected.txt: Added.
        * editing/selection/click-before-and-after-table.html: Added.
        Updated to reflect fix:
        * editing/selection/move-by-line-001-expected.checksum:
        * editing/selection/move-by-line-001-expected.png:

WebCore:

        Reviewed by levi

        <rdar://problem/4599735> Clicking out of a table at the extremes of an editable document doesn't appear to work

        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::positionForCoordinates): In the fall through case,
        where we can't find a child block that contains (x, y), pass to RenderFlow
        instead of the last visible child block.
        * rendering/RenderContainer.cpp:
        (WebCore::RenderContainer::positionForCoordinates): Don't pass to the closest
        child renderer if this is a table and (x, y) is outside the table.  Return
        a VisiblePosition before or after the table.
        Fixed the code that finds the closest child renderer.

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

LayoutTests/ChangeLog
LayoutTests/editing/selection/click-before-and-after-table-expected.txt [new file with mode: 0644]
LayoutTests/editing/selection/click-before-and-after-table.html [new file with mode: 0644]
LayoutTests/editing/selection/move-by-line-001-expected.checksum
LayoutTests/editing/selection/move-by-line-001-expected.png
WebCore/ChangeLog
WebCore/rendering/RenderBlock.cpp
WebCore/rendering/RenderContainer.cpp

index b5746ebccd86618fb8e8ef8c7f96dcae760a736c..4538183d326dedd918a806eb3fe6e8f5e0fb9605 100644 (file)
@@ -1,3 +1,16 @@
+2006-06-27  Justin Garcia  <justin.garcia@apple.com>
+        
+        Reviewed by levi
+        
+        <rdar://problem/4599735> Clicking out of a table at the extremes of an editable document doesn't appear to work
+        
+        Added:
+        * editing/selection/click-before-and-after-table-expected.txt: Added.
+        * editing/selection/click-before-and-after-table.html: Added.
+        Updated to reflect fix:
+        * editing/selection/move-by-line-001-expected.checksum:
+        * editing/selection/move-by-line-001-expected.png:
+
 2006-06-27  Anders Carlsson  <acarlsson@apple.com>
 
         Reviewed by Geoff.
diff --git a/LayoutTests/editing/selection/click-before-and-after-table-expected.txt b/LayoutTests/editing/selection/click-before-and-after-table-expected.txt
new file mode 100644 (file)
index 0000000..4baa382
--- /dev/null
@@ -0,0 +1,12 @@
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of BODY > HTML > #document to 6 of BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 2 of TABLE > BODY > HTML > #document to 2 of TABLE > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of TABLE > BODY > HTML > #document to 2 of TABLE > BODY > HTML > #document toDOMRange:range from 8 of #text > TD > TR > TBODY > TABLE > BODY > HTML > #document to 8 of #text > TD > TR > TBODY > TABLE > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 8 of #text > TD > TR > TBODY > TABLE > BODY > HTML > #document to 8 of #text > TD > TR > TBODY > TABLE > BODY > HTML > #document toDOMRange:range from 0 of TABLE > BODY > HTML > #document to 0 of TABLE > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of TABLE > BODY > HTML > #document to 0 of TABLE > BODY > HTML > #document toDOMRange:range from 0 of TD > TR > TBODY > TABLE > BODY > HTML > #document to 0 of TD > TR > TBODY > TABLE > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+cell one       cell two
+
diff --git a/LayoutTests/editing/selection/click-before-and-after-table.html b/LayoutTests/editing/selection/click-before-and-after-table.html
new file mode 100644 (file)
index 0000000..ee5e7b7
--- /dev/null
@@ -0,0 +1,72 @@
+<style>
+td {
+    border: 1px solid #aaa;
+}
+</style>
+
+<body style="border: 1px solid red;" contenteditable="true">
+<table id="table" style="margin: 25px; border:10px solid #ccc; padding: 10px;">
+<tr><td>cell one</td><td>cell two</td></tr>
+</table>
+<ul id="console"></ul>
+<script>
+function log(message) {
+    var console = document.getElementById("console");
+    var li = document.createElement("li");
+    var text = document.createTextNode(message);
+    
+    console.appendChild(li);
+    li.appendChild(text);
+}
+if (!window.layoutTestController)
+    log("This test uses the eventSender to do mouse clicks.  To run it manually, click after the table, the caret should appear there (and not inside the table).  Then click inside the table.  The caret should appear inside it.");
+else {
+    window.layoutTestController.dumpAsText();
+    var s, x, y, e, top, bottom, left, right;
+    table = document.getElementById("table");
+    top = table.offsetParent.offsetTop + table.offsetTop;
+    bottom = top + table.offsetHeight;
+    left = table.offsetParent.offsetLeft + table.offsetLeft;
+    right = left + table.offsetWidth;
+    
+    x = right + 5;
+    y = (top + bottom) / 2;
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    s = window.getSelection();
+    if (s.anchorNode != table || s.anchorOffset != table.childNodes.length)
+        log("Failure: Clicking after the table didn't put the caret after it.");
+    
+    x = right - 5;
+    y = (top + bottom) / 2;
+    eventSender.leapForward(1000);
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    s = window.getSelection();
+    if (s.anchorNode == table)
+        log("Failure: Clicking inside the table put the caret before or after it.");
+        
+    x = left - 5;
+    y = (top + bottom) / 2;
+    eventSender.leapForward(1000);
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    s = window.getSelection();
+    if (s.anchorNode != table || s.anchorOffset != 0)
+        log("Failure: Clicking before the table should be the caret before it.");
+        
+    x = left + 5;
+    y = (top + bottom) / 2;
+    eventSender.leapForward(1000);
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    s = window.getSelection();
+    if (s.anchorNode == table)
+        log("Failure: Clicking inside the table put the caret before or after it.");
+}
+</script>
+</body>
\ No newline at end of file
index 0e614fd4ada2ac55f160b0594ab5bc29fb8d5c36..1584207fa473cdfd96dce4bd8738bfb65b78b5aa 100644 (file)
@@ -1 +1 @@
-575e5b6f144b78e296d44fc73872e002
\ No newline at end of file
+29bc74bb11961bfae622a9ecdbfa5197
\ No newline at end of file
index 1691808b247148ec7470963405137e9916e60407..42308fa51043508cc3e495a714c130cbf4310350 100644 (file)
Binary files a/LayoutTests/editing/selection/move-by-line-001-expected.png and b/LayoutTests/editing/selection/move-by-line-001-expected.png differ
index be1594c0b3a7a87b90f83739c16b6fb9eabe96d8..3b45786cbcd7b32d1ee6fdfd1c450b11b53cd2c0 100644 (file)
@@ -1,3 +1,19 @@
+2006-06-27  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by levi
+        
+        <rdar://problem/4599735> Clicking out of a table at the extremes of an editable document doesn't appear to work
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::positionForCoordinates): In the fall through case,
+        where we can't find a child block that contains (x, y), pass to RenderFlow
+        instead of the last visible child block.
+        * rendering/RenderContainer.cpp:
+        (WebCore::RenderContainer::positionForCoordinates): Don't pass to the closest 
+        child renderer if this is a table and (x, y) is outside the table.  Return
+        a VisiblePosition before or after the table.
+        Fixed the code that finds the closest child renderer.
+
 2006-06-27  David Hyatt  <hyatt@apple.com>
 
         Preserve entity text in view source mode.  This patch doesn't highlight the
index cd8f6546b2c78d64164a5d558b5dc7d331cd016e..2b5d35d819618fe5a9f2c94e28d8fe560304114e 100644 (file)
@@ -2701,13 +2701,8 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y)
             return renderer->positionForCoordinates(x, y);
         lastVisibleChild = renderer;
     }
-
-    // pass along to the last child we saw that had a height and is visible.
-    if (lastVisibleChild)
-        return lastVisibleChild->positionForCoordinates(x, y);
     
-    // still no luck...return this render object's element and offset 0
-    return VisiblePosition(n, 0, DOWNSTREAM);
+    return RenderFlow::positionForCoordinates(x, y);
 }
 
 void RenderBlock::calcMinMaxWidth()
index 21e61d8c7efc9d79da569ad3ac908e707c28dbc0..a9625d6dc45c68969a8f4ace0626dbf26a47a02e 100644 (file)
@@ -25,8 +25,8 @@
  */
 
 #include "config.h"
+#include "htmlediting.h"
 #include "RenderContainer.h"
-
 #include "RenderListItem.h"
 #include "RenderTable.h"
 #include "RenderTextFragment.h"
@@ -464,17 +464,35 @@ void RenderContainer::removeLeftoverAnonymousBoxes()
         parent()->removeLeftoverAnonymousBoxes();
 }
 
-VisiblePosition RenderContainer::positionForCoordinates(int _x, int _y)
+VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
 {
     // no children...return this render object's element, if there is one, and offset 0
     if (!firstChild())
         return VisiblePosition(element(), 0, DOWNSTREAM);
+        
+    if (isTable()) {
+        int absx, absy;
+        absolutePositionForContent(absx, absy);
+        
+        int left = absx;
+        int right = left + contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
+        int top = absy;
+        int bottom = top + contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
+        
+        if (x < left || x > right || y < top || y > bottom) {
+            if (x <= (left + right) / 2)
+                return VisiblePosition(Position(element(), 0));
+            else
+                return VisiblePosition(Position(element(), maxDeepOffset(element())));
+        }
+    }
 
-    // look for the geometrically-closest child and pass off to that child
-    int min = INT_MAX;
+    // Pass off to the closest child.
+    int minDist = INT_MAX;
     RenderObject* closestRenderer = 0;
     for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
-        if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow())
+        if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow() 
+            || renderer->height() == 0 || renderer->style()->visibility() != VISIBLE)
             continue;
 
         int absx, absy;
@@ -485,15 +503,45 @@ VisiblePosition RenderContainer::positionForCoordinates(int _x, int _y)
         int left = absx + borderLeft() + paddingLeft();
         int right = left + renderer->contentWidth();
         
-        int cmp;
-        cmp = abs(_y - top);    if (cmp < min) { closestRenderer = renderer; min = cmp; }
-        cmp = abs(_y - bottom); if (cmp < min) { closestRenderer = renderer; min = cmp; }
-        cmp = abs(_x - left);   if (cmp < min) { closestRenderer = renderer; min = cmp; }
-        cmp = abs(_x - right);  if (cmp < min) { closestRenderer = renderer; min = cmp; }
+        if (x <= right && x >= left && y <= top && y >= bottom)
+            return renderer->positionForCoordinates(x, y);
+        
+        // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
+        // and use a different compare depending on which piece (x, y) is in.
+        IntPoint cmp;
+        if (x > right) {
+            if (y < top)
+                cmp = IntPoint(right, top);
+            else if (y > bottom)
+                cmp = IntPoint(right, bottom);
+            else
+                cmp = IntPoint(right, y);
+        } else if (x < left) {
+            if (y < top)
+                cmp = IntPoint(left, top);
+            else if (y > bottom)
+                cmp = IntPoint(left, bottom);
+            else
+                cmp = IntPoint(left, y);
+        } else {
+            if (y < top)
+                cmp = IntPoint(x, top);
+            else
+                cmp = IntPoint(x, bottom);
+        }
+        
+        int x1minusx2 = cmp.x() - x;
+        int y1minusy2 = cmp.y() - y;
+        
+        int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
+        if (dist < minDist) {
+            closestRenderer = renderer;
+            minDist = dist;
+        }
     }
     
     if (closestRenderer)
-        return closestRenderer->positionForCoordinates(_x, _y);
+        return closestRenderer->positionForCoordinates(x, y);
     
     return VisiblePosition(element(), 0, DOWNSTREAM);
 }