Reviewed by Hyatt
authorkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Apr 2004 22:13:49 +0000 (22:13 +0000)
committerkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Apr 2004 22:13:49 +0000 (22:13 +0000)
        * khtml/editing/htmlediting_impl.cpp:
        (DeleteSelectionCommandImpl::containsOnlyWhitespace): New helper.
        (DeleteSelectionCommandImpl::doApply): Fix deleting collapsed whitespace at the end of a line
        where text has flowed to the next line and the caret is at the beginning of the next line.
        * khtml/editing/htmlediting_impl.h: Updated for new helper.
        * layout-tests/editing/deleting/delete-line-end-ws-001-expected.txt: Added.
        * layout-tests/editing/deleting/delete-line-end-ws-001.html: Added.
        * layout-tests/editing/deleting/delete-line-end-ws-002-expected.txt: Added.
        * layout-tests/editing/deleting/delete-line-end-ws-002.html: Added.

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

LayoutTests/editing/deleting/delete-line-end-ws-001-expected.txt [new file with mode: 0644]
LayoutTests/editing/deleting/delete-line-end-ws-001.html [new file with mode: 0644]
LayoutTests/editing/deleting/delete-line-end-ws-002-expected.txt [new file with mode: 0644]
LayoutTests/editing/deleting/delete-line-end-ws-002.html [new file with mode: 0644]
WebCore/ChangeLog-2005-08-23
WebCore/khtml/editing/htmlediting_impl.cpp
WebCore/khtml/editing/htmlediting_impl.h

diff --git a/LayoutTests/editing/deleting/delete-line-end-ws-001-expected.txt b/LayoutTests/editing/deleting/delete-line-end-ws-001-expected.txt
new file mode 100644 (file)
index 0000000..1e5e595
--- /dev/null
@@ -0,0 +1,15 @@
+layer at (0,0) size 820x585
+  RenderCanvas at (0,0) size 800x585
+layer at (0,0) size 820x372
+  RenderBlock {HTML} at (0,0) size 800x372
+    RenderBody {BODY} at (8,64) size 784x244
+      RenderBlock {DIV} at (64,0) size 748x244 [border: (50px solid #FF0000)]
+        RenderInline {SPAN} at (0,0) size 540x76
+          RenderText {TEXT} at (74,84) size 540x96
+            text run at (74,84) width 540: "Fourscore and seven years ago our fathers brought forth"
+            text run at (74,132) width 304: "onthis continent a new nation..."
+        RenderText {TEXT} at (0,0) size 0x0
+selection is CARET:
+start:      position 58 of child 1 {TEXT} of child 2 {SPAN} of root {DIV}
+upstream:   position 58 of child 1 {TEXT} of child 2 {SPAN} of root {DIV}
+downstream: position 58 of child 1 {TEXT} of child 2 {SPAN} of root {DIV}
diff --git a/LayoutTests/editing/deleting/delete-line-end-ws-001.html b/LayoutTests/editing/deleting/delete-line-end-ws-001.html
new file mode 100644 (file)
index 0000000..473985e
--- /dev/null
@@ -0,0 +1,39 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: solid red 50px;
+    font-size: 24px; 
+    line-height: 48px; 
+    padding: 24px; 
+    margin: 64px;
+    width: 600px; 
+}
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 59; i++) {
+        moveSelectionForwardByCharacterCommand();    
+    }
+    deleteCommand(); 
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+<div contenteditable id="root" class="editing">
+<span id="test">Fourscore and seven years ago our fathers brought forth on this continent a new nation...</span>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/deleting/delete-line-end-ws-002-expected.txt b/LayoutTests/editing/deleting/delete-line-end-ws-002-expected.txt
new file mode 100644 (file)
index 0000000..1e5e595
--- /dev/null
@@ -0,0 +1,15 @@
+layer at (0,0) size 820x585
+  RenderCanvas at (0,0) size 800x585
+layer at (0,0) size 820x372
+  RenderBlock {HTML} at (0,0) size 800x372
+    RenderBody {BODY} at (8,64) size 784x244
+      RenderBlock {DIV} at (64,0) size 748x244 [border: (50px solid #FF0000)]
+        RenderInline {SPAN} at (0,0) size 540x76
+          RenderText {TEXT} at (74,84) size 540x96
+            text run at (74,84) width 540: "Fourscore and seven years ago our fathers brought forth"
+            text run at (74,132) width 304: "onthis continent a new nation..."
+        RenderText {TEXT} at (0,0) size 0x0
+selection is CARET:
+start:      position 58 of child 1 {TEXT} of child 2 {SPAN} of root {DIV}
+upstream:   position 58 of child 1 {TEXT} of child 2 {SPAN} of root {DIV}
+downstream: position 58 of child 1 {TEXT} of child 2 {SPAN} of root {DIV}
diff --git a/LayoutTests/editing/deleting/delete-line-end-ws-002.html b/LayoutTests/editing/deleting/delete-line-end-ws-002.html
new file mode 100644 (file)
index 0000000..2e94548
--- /dev/null
@@ -0,0 +1,42 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: solid red 50px;
+    font-size: 24px; 
+    line-height: 48px; 
+    padding: 24px; 
+    margin: 64px;
+    width: 600px; 
+}
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 59; i++) {
+        moveSelectionForwardByCharacterCommand();    
+    }
+    deleteCommand(); 
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+<div contenteditable id="root" class="editing">
+<span id="test">Fourscore and seven years ago our fathers brought forth on     
+
+
+this continent a new nation...</span>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
index 0dce54d26f3f8c752bd6e68a7c717ff657184937..6df38f9d1e9d367aaa3f6ca35a79a524611068e4 100644 (file)
@@ -1,3 +1,17 @@
+2004-04-16  Ken Kocienda  <kocienda@apple.com>
+
+        Reviewed by Hyatt
+
+        * khtml/editing/htmlediting_impl.cpp:
+        (DeleteSelectionCommandImpl::containsOnlyWhitespace): New helper.
+        (DeleteSelectionCommandImpl::doApply): Fix deleting collapsed whitespace at the end of a line
+        where text has flowed to the next line and the caret is at the beginning of the next line.
+        * khtml/editing/htmlediting_impl.h: Updated for new helper.
+        * layout-tests/editing/deleting/delete-line-end-ws-001-expected.txt: Added.
+        * layout-tests/editing/deleting/delete-line-end-ws-001.html: Added.
+        * layout-tests/editing/deleting/delete-line-end-ws-002-expected.txt: Added.
+        * layout-tests/editing/deleting/delete-line-end-ws-002.html: Added.
+
 2004-04-16  Richard Williamson   <rjw@apple.com>
 
        Added an SPI to allow ObjC instances to be easily bound to 
index 29940a74e97d3ef54dba57293109f214c69e706d..1dfc336ae83289be3fa8cb84994958f148b1e977 100644 (file)
@@ -811,6 +811,27 @@ void DeleteSelectionCommandImpl::joinTextNodesWithSameStyle()
     }
 }
 
+bool DeleteSelectionCommandImpl::containsOnlyWhitespace(const DOMPosition &start, const DOMPosition &end)
+{
+    // Returns whether the range contains only whitespace characters.
+    // This is inclusive of the start, but not of the end.
+    EditIterator it(start);
+    while (!it.atEnd()) {
+        if (!it.current().node()->isTextNode())
+            return false;
+        const DOMString &text = static_cast<TextImpl *>(it.current().node())->data();
+        // EDIT FIXME: signed/unsigned mismatch
+        if (text.length() > INT_MAX)
+            return false;
+        if (it.current().offset() < (int)text.length() && !isWS(text[it.current().offset()]))
+            return false;
+        it.next();
+        if (it.current() == end)
+            break;
+    }
+    return true;
+}
+
 void DeleteSelectionCommandImpl::doApply()
 {
     if (m_selectionToDelete.state() != KHTMLSelection::RANGE)
@@ -827,15 +848,17 @@ void DeleteSelectionCommandImpl::doApply()
     DOMPosition upstreamEnd = selection.endPosition().equivalentUpstreamPosition();
     DOMPosition downstreamEnd = selection.endPosition().equivalentDownstreamPosition();
 
-    bool startCompletelySelected = 
-        downstreamStart.offset() <= downstreamStart.node()->caretMinOffset() &&
+    bool onlyWhitespace = containsOnlyWhitespace(upstreamStart, downstreamEnd);
+    bool startCompletelySelected = !onlyWhitespace &&
+        (downstreamStart.offset() <= downstreamStart.node()->caretMinOffset() &&
         ((downstreamStart.node() != upstreamEnd.node()) ||
-         (upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset()));
+         (upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset())));
 
-    bool endCompletelySelected = 
-        upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset() &&
+    bool endCompletelySelected = !onlyWhitespace &&
+        (upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset() &&
         ((downstreamStart.node() != upstreamEnd.node()) ||
-         (downstreamStart.offset() <= downstreamStart.node()->caretMinOffset()));
+         (downstreamStart.offset() <= downstreamStart.node()->caretMinOffset())));
 
     unsigned long startRenderedOffset = downstreamStart.renderedOffset();
     
@@ -852,6 +875,7 @@ void DeleteSelectionCommandImpl::doApply()
     LOG(Editing,  "at start block:      %s", startAtStartOfBlock ? "YES" : "NO");
     LOG(Editing,  "at start root block: %s", startAtStartOfRootEditableBlock ? "YES" : "NO");
     LOG(Editing,  "at end block:        %s", endAtEndOfBlock ? "YES" : "NO");
+    LOG(Editing,  "only whitespace:     %s", onlyWhitespace ? "YES" : "NO");
 
     // Start is not completely selected
     if (startAtStartOfBlock) {
@@ -916,9 +940,23 @@ void DeleteSelectionCommandImpl::doApply()
 
     // work on start node
     if (startCompletelySelected) {
+        LOG(Editing,  "start node delete case 1");
         removeNodeAndPrune(downstreamStart.node());
     }
+    else if (onlyWhitespace) {
+        // Selection only contains whitespace. This is really a special-case to 
+        // handle significant whitespace that is collapsed at the end of a line,
+        // but also handles deleting a space in mid-line.
+        LOG(Editing,  "start node delete case 2");
+        ASSERT(upstreamStart.node()->isTextNode());
+        TextImpl *text = static_cast<TextImpl *>(upstreamStart.node());
+        int length = downstreamStart.node() == upstreamStart.node() ? 
+            kMax(downstreamStart.offset() - upstreamStart.offset(), 1L) : 
+            text->length() - upstreamStart.offset();
+        deleteText(text, upstreamStart.offset(), length);
+    }
     else if (downstreamStart.node()->isTextNode()) {
+        LOG(Editing,  "start node delete case 3");
         TextImpl *text = static_cast<TextImpl *>(downstreamStart.node());
         int endOffset = text == upstreamEnd.node() ? upstreamEnd.offset() : text->length();
         if (endOffset > downstreamStart.offset()) {
@@ -928,10 +966,11 @@ void DeleteSelectionCommandImpl::doApply()
     else {
         // we have clipped the end of a non-text element
         // the offset must be 1 here. if it is, do nothing and move on.
+        LOG(Editing,  "start node delete case 4");
         ASSERT(downstreamStart.offset() == 1);
     }
 
-    if (downstreamStart.node() != upstreamEnd.node()) {
+    if (!onlyWhitespace && downstreamStart.node() != upstreamEnd.node()) {
         // work on intermediate nodes
         while (n != upstreamEnd.node()) {
             NodeImpl *d = n;
index 10bd78b6d2fced3e64bbcfba8ea0c9ee7a773498..5d20e3946ba6ee093f7efbae7b5c8d8020f2af02 100644 (file)
@@ -197,6 +197,7 @@ public:
     
 private:
     void deleteDownstreamWS(const DOM::DOMPosition &start);
+    bool containsOnlyWhitespace(const DOM::DOMPosition &start, const DOM::DOMPosition &end);
     void joinTextNodesWithSameStyle();
 
     KHTMLSelection m_selectionToDelete;