Reviewed by John
authorkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Mar 2005 16:30:14 +0000 (16:30 +0000)
committerkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Mar 2005 16:30:14 +0000 (16:30 +0000)
        Fix for these bugs:

        <rdar://problem/4045511> Copying and pasting end-of-paragraph selection puts insertion point in wrong place
        <rdar://problem/4045513> Copying and pasting selection starting at end of paragraph can incorrectly remove line break

        The copy/paste code before this patch had no notion of a "logical newline" at the start of the selection. We have
        had a similar notion for "logical newline" at the end of the selection for quite some time. To fix these bugs, we
        need to introduce the same idea for selection starts.

        * khtml/editing/htmlediting.cpp:
        (khtml::ReplacementFragment::ReplacementFragment): Process the "logical newline" at start as we write it out
        in markup. Set the bit we added to this object to signify we have such a newline.
        (khtml::ReplaceSelectionCommand::doApply): Many, many changes to introduce the new "logical newline" at start concept.
        I also tried to simply the code that sets the start position for inserting content to be pasted. I also improved a
        weakness in the smart-paste code. Now, we check before and after the paste for whether we need to add a leading or
        trailing space. The code previous to this patch only did a "before" check, with the result that we sometimes added
        a second space. In other words, the code did not realize that DOM changes done by pasting could cause formerly
        unrendered whitespace to become rendered. Also moved line placeholder clean up code to its own function.
        (khtml::ReplaceSelectionCommand::removeLinePlaceholderIfNeeded): New helper that further refines the notion
        of when we can remove a line placeholder. The definition is now, "If a line placeholder is at the visible start
        and visible end of its line, keep it; otherwise remove it".
        * khtml/editing/htmlediting.h: Declare new functions. Rework inlines in ReplacementFragment class to account for
        addition of new "logical newline" at start concept.
        (khtml::ReplacementFragment::hasInterchangeNewlineAtStart): New accessor.
        (khtml::ReplacementFragment::hasInterchangeNewlineAtEnd): Renamed from hasInterchangeNewline(), since before we
        only had a bit for the end, hence we did not need to distinguish it from the start.
        * khtml/editing/markup.cpp:
        (khtml::createMarkup): Added code to detect and write out markup for cases where we have a "logical newline" at start.
        * khtml/xml/dom2_rangeimpl.cpp:
        (DOM::RangeImpl::startPosition): New helper.
        (DOM::RangeImpl::endPosition): Ditto.
        * khtml/xml/dom2_rangeimpl.h: Declare new helpers.

        New tests:
        * layout-tests/editing/pasteboard/paste-line-endings-001-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-001.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-002-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-002.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-003-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-003.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-004-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-004.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-005-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-005.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-006-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-006.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-007-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-007.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-008-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-008.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-009-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-009.html: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-010-expected.txt: Added.
        * layout-tests/editing/pasteboard/paste-line-endings-010.html: Added.

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

26 files changed:
LayoutTests/editing/pasteboard/paste-line-endings-001-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-001.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-002-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-002.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-003-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-003.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-004-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-004.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-005-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-005.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-006-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-006.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-007-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-007.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-008-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-008.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-009-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-009.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-010-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-line-endings-010.html [new file with mode: 0644]
WebCore/ChangeLog-2005-08-23
WebCore/khtml/editing/htmlediting.cpp
WebCore/khtml/editing/htmlediting.h
WebCore/khtml/editing/markup.cpp
WebCore/khtml/xml/dom2_rangeimpl.cpp
WebCore/khtml/xml/dom2_rangeimpl.h

diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-001-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-001-expected.txt
new file mode 100644 (file)
index 0000000..63f7342
--- /dev/null
@@ -0,0 +1,36 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x212 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045511>"
+          RenderText {TEXT} at (422,28) size 705x56
+            text run at (422,28) width 283: " Copying and pasting end-of-"
+            text run at (0,56) width 533: "paragraph selection puts insertion point in wrong place"
+        RenderBlock {DIV} at (14,114) size 756x84
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 715x56
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 715: "one\" and \"line two\". The insertion point must be at the start of \"line two\"."
+      RenderBlock {DIV} at (0,236) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderText {TEXT} at (2,2) size 78x28
+            text run at (2,2) width 78: "line one"
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (2,30) size 79x28
+            text run at (2,30) width 79: "line two"
+selection is CARET:
+start:      position 0 of child 3 {TEXT} of child 1 {DIV} of root {DIV}
+upstream:   position 1 of child 2 {BR} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 3 {TEXT} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-001.html b/LayoutTests/editing/pasteboard/paste-line-endings-001.html
new file mode 100644 (file)
index 0000000..9a6ba3c
--- /dev/null
@@ -0,0 +1,63 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045511">&lt;rdar://problem/4045511&gt;</a> Copying and pasting end-of-paragraph selection puts insertion point in wrong place
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be at the start of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+line one<br>line two
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-002-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-002-expected.txt
new file mode 100644 (file)
index 0000000..1e1bb37
--- /dev/null
@@ -0,0 +1,37 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x212 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045511>"
+          RenderText {TEXT} at (422,28) size 705x56
+            text run at (422,28) width 283: " Copying and pasting end-of-"
+            text run at (0,56) width 533: "paragraph selection puts insertion point in wrong place"
+        RenderBlock {DIV} at (14,114) size 756x84
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 715x56
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 715: "one\" and \"line two\". The insertion point must be at the start of \"line two\"."
+      RenderBlock {DIV} at (0,236) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock (anonymous) at (2,2) size 780x28
+            RenderText {TEXT} at (0,0) size 78x28
+              text run at (0,0) width 78: "line one"
+          RenderBlock {DIV} at (2,30) size 780x28
+            RenderText {TEXT} at (0,0) size 79x28
+              text run at (0,0) width 79: "line two"
+selection is CARET:
+start:      position 0 of child 1 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 0 of child 2 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 1 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-002.html b/LayoutTests/editing/pasteboard/paste-line-endings-002.html
new file mode 100644 (file)
index 0000000..456d6a2
--- /dev/null
@@ -0,0 +1,63 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045511">&lt;rdar://problem/4045511&gt;</a> Copying and pasting end-of-paragraph selection puts insertion point in wrong place
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be at the start of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+line one<div>line two</div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-003-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-003-expected.txt
new file mode 100644 (file)
index 0000000..64e65c6
--- /dev/null
@@ -0,0 +1,37 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x212 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045511>"
+          RenderText {TEXT} at (422,28) size 705x56
+            text run at (422,28) width 283: " Copying and pasting end-of-"
+            text run at (0,56) width 533: "paragraph selection puts insertion point in wrong place"
+        RenderBlock {DIV} at (14,114) size 756x84
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 715x56
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 715: "one\" and \"line two\". The insertion point must be at the start of \"line two\"."
+      RenderBlock {DIV} at (0,236) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock {DIV} at (2,2) size 780x28
+            RenderText {TEXT} at (0,0) size 78x28
+              text run at (0,0) width 78: "line one"
+          RenderBlock {DIV} at (2,30) size 780x28
+            RenderText {TEXT} at (0,0) size 79x28
+              text run at (0,0) width 79: "line two"
+selection is CARET:
+start:      position 0 of child 1 {TEXT} of child 3 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 0 of child 3 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 1 {TEXT} of child 3 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-003.html b/LayoutTests/editing/pasteboard/paste-line-endings-003.html
new file mode 100644 (file)
index 0000000..d18c9d6
--- /dev/null
@@ -0,0 +1,63 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045511">&lt;rdar://problem/4045511&gt;</a> Copying and pasting end-of-paragraph selection puts insertion point in wrong place
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be at the start of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+<div>line one</div><div>line two</div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-004-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-004-expected.txt
new file mode 100644 (file)
index 0000000..4c13bff
--- /dev/null
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x212 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045511>"
+          RenderText {TEXT} at (422,28) size 705x56
+            text run at (422,28) width 283: " Copying and pasting end-of-"
+            text run at (0,56) width 533: "paragraph selection puts insertion point in wrong place"
+        RenderBlock {DIV} at (14,114) size 756x84
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 715x56
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 715: "one\" and \"line two\". The insertion point must be at the start of \"line two\"."
+      RenderBlock {DIV} at (0,236) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock {DIV} at (2,2) size 780x56
+            RenderBlock (anonymous) at (0,0) size 780x28
+              RenderText {TEXT} at (0,0) size 78x28
+                text run at (0,0) width 78: "line one"
+            RenderBlock {DIV} at (0,28) size 780x28
+              RenderText {TEXT} at (0,0) size 79x28
+                text run at (0,0) width 79: "line two"
+selection is CARET:
+start:      position 0 of child 1 {TEXT} of child 2 {DIV} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 0 of child 2 {DIV} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 1 {TEXT} of child 2 {DIV} of child 2 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-004.html b/LayoutTests/editing/pasteboard/paste-line-endings-004.html
new file mode 100644 (file)
index 0000000..926eddc
--- /dev/null
@@ -0,0 +1,63 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045511">&lt;rdar://problem/4045511&gt;</a> Copying and pasting end-of-paragraph selection puts insertion point in wrong place
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be at the start of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+<div>line one<div>line two</div></div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-005-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-005-expected.txt
new file mode 100644 (file)
index 0000000..78eb35f
--- /dev/null
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x212 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045511>"
+          RenderText {TEXT} at (422,28) size 705x56
+            text run at (422,28) width 283: " Copying and pasting end-of-"
+            text run at (0,56) width 533: "paragraph selection puts insertion point in wrong place"
+        RenderBlock {DIV} at (14,114) size 756x84
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 715x56
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 715: "one\" and \"line two\". The insertion point must be at the start of \"line two\"."
+      RenderBlock {DIV} at (0,236) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock {DIV} at (2,2) size 780x56
+            RenderBlock {DIV} at (0,0) size 780x28
+              RenderText {TEXT} at (0,0) size 78x28
+                text run at (0,0) width 78: "line one"
+            RenderBlock (anonymous) at (0,28) size 780x28
+              RenderText {TEXT} at (0,0) size 79x28
+                text run at (0,0) width 79: "line two"
+selection is CARET:
+start:      position 0 of child 2 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 0 of child 2 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 2 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-005.html b/LayoutTests/editing/pasteboard/paste-line-endings-005.html
new file mode 100644 (file)
index 0000000..ec3e7a3
--- /dev/null
@@ -0,0 +1,63 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045511">&lt;rdar://problem/4045511&gt;</a> Copying and pasting end-of-paragraph selection puts insertion point in wrong place
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be at the start of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+<div><div>line one</div>line two</div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-006-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-006-expected.txt
new file mode 100644 (file)
index 0000000..5b6d214
--- /dev/null
@@ -0,0 +1,39 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x240 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045513>"
+          RenderText {TEXT} at (422,28) size 721x56
+            text run at (422,28) width 299: " Copying and pasting selection"
+            text run at (0,56) width 601: "starting at end of paragraph can incorrectly remove line break"
+        RenderBlock {DIV} at (14,114) size 756x112
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 747x84
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 747: "one\" and \"line two\". The insertion point must be after the first character (\"l\")"
+            text run at (0,84) width 131: "of \"line two\"."
+      RenderBlock {DIV} at (0,264) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderText {TEXT} at (2,2) size 78x28
+            text run at (2,2) width 78: "line one"
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (2,30) size 7x28
+            text run at (2,30) width 7: "l"
+          RenderText {TEXT} at (9,30) size 72x28
+            text run at (9,30) width 72: "ine two"
+selection is CARET:
+start:      position 1 of child 3 {TEXT} of child 1 {DIV} of root {DIV}
+upstream:   position 1 of child 3 {TEXT} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 4 {TEXT} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-006.html b/LayoutTests/editing/pasteboard/paste-line-endings-006.html
new file mode 100644 (file)
index 0000000..7483b6f
--- /dev/null
@@ -0,0 +1,64 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    for (i = 0; i < 2; i++)
+        extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045513">&lt;rdar://problem/4045513&gt;</a> Copying and pasting selection starting at end of paragraph can incorrectly remove line break
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be after the first character ("l") of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+line one<br>line two
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-007-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-007-expected.txt
new file mode 100644 (file)
index 0000000..7c79bb3
--- /dev/null
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x240 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045513>"
+          RenderText {TEXT} at (422,28) size 721x56
+            text run at (422,28) width 299: " Copying and pasting selection"
+            text run at (0,56) width 601: "starting at end of paragraph can incorrectly remove line break"
+        RenderBlock {DIV} at (14,114) size 756x112
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 747x84
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 747: "one\" and \"line two\". The insertion point must be after the first character (\"l\")"
+            text run at (0,84) width 131: "of \"line two\"."
+      RenderBlock {DIV} at (0,264) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock (anonymous) at (2,2) size 780x28
+            RenderText {TEXT} at (0,0) size 78x28
+              text run at (0,0) width 78: "line one"
+          RenderBlock {DIV} at (2,30) size 780x28
+            RenderText {TEXT} at (0,0) size 7x28
+              text run at (0,0) width 7: "l"
+            RenderText {TEXT} at (7,0) size 72x28
+              text run at (7,0) width 72: "ine two"
+selection is CARET:
+start:      position 1 of child 1 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 1 of child 1 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 2 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-007.html b/LayoutTests/editing/pasteboard/paste-line-endings-007.html
new file mode 100644 (file)
index 0000000..f2bf3cd
--- /dev/null
@@ -0,0 +1,64 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    for (i = 0; i < 2; i++)
+        extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045513">&lt;rdar://problem/4045513&gt;</a> Copying and pasting selection starting at end of paragraph can incorrectly remove line break
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be after the first character ("l") of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+line one<div>line two</div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-008-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-008-expected.txt
new file mode 100644 (file)
index 0000000..5fdbe04
--- /dev/null
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x240 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045513>"
+          RenderText {TEXT} at (422,28) size 721x56
+            text run at (422,28) width 299: " Copying and pasting selection"
+            text run at (0,56) width 601: "starting at end of paragraph can incorrectly remove line break"
+        RenderBlock {DIV} at (14,114) size 756x112
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 747x84
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 747: "one\" and \"line two\". The insertion point must be after the first character (\"l\")"
+            text run at (0,84) width 131: "of \"line two\"."
+      RenderBlock {DIV} at (0,264) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock {DIV} at (2,2) size 780x28
+            RenderText {TEXT} at (0,0) size 78x28
+              text run at (0,0) width 78: "line one"
+          RenderBlock {DIV} at (2,30) size 780x28
+            RenderText {TEXT} at (0,0) size 7x28
+              text run at (0,0) width 7: "l"
+            RenderText {TEXT} at (7,0) size 72x28
+              text run at (7,0) width 72: "ine two"
+selection is CARET:
+start:      position 1 of child 1 {TEXT} of child 3 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 1 of child 1 {TEXT} of child 3 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 2 {TEXT} of child 3 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-008.html b/LayoutTests/editing/pasteboard/paste-line-endings-008.html
new file mode 100644 (file)
index 0000000..843f8e8
--- /dev/null
@@ -0,0 +1,64 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    for (i = 0; i < 2; i++)
+        extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045513">&lt;rdar://problem/4045513&gt;</a> Copying and pasting selection starting at end of paragraph can incorrectly remove line break
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be after the first character ("l") of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+<div>line one</div><div>line two</div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-009-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-009-expected.txt
new file mode 100644 (file)
index 0000000..caa3827
--- /dev/null
@@ -0,0 +1,41 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x240 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045513>"
+          RenderText {TEXT} at (422,28) size 721x56
+            text run at (422,28) width 299: " Copying and pasting selection"
+            text run at (0,56) width 601: "starting at end of paragraph can incorrectly remove line break"
+        RenderBlock {DIV} at (14,114) size 756x112
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 747x84
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 747: "one\" and \"line two\". The insertion point must be after the first character (\"l\")"
+            text run at (0,84) width 131: "of \"line two\"."
+      RenderBlock {DIV} at (0,264) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock {DIV} at (2,2) size 780x56
+            RenderBlock (anonymous) at (0,0) size 780x28
+              RenderText {TEXT} at (0,0) size 78x28
+                text run at (0,0) width 78: "line one"
+            RenderBlock {DIV} at (0,28) size 780x28
+              RenderText {TEXT} at (0,0) size 7x28
+                text run at (0,0) width 7: "l"
+              RenderText {TEXT} at (7,0) size 72x28
+                text run at (7,0) width 72: "ine two"
+selection is CARET:
+start:      position 1 of child 1 {TEXT} of child 2 {DIV} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 1 of child 1 {TEXT} of child 2 {DIV} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 2 {TEXT} of child 2 {DIV} of child 2 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-009.html b/LayoutTests/editing/pasteboard/paste-line-endings-009.html
new file mode 100644 (file)
index 0000000..feb0242
--- /dev/null
@@ -0,0 +1,64 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    for (i = 0; i < 2; i++)
+        extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045513">&lt;rdar://problem/4045513&gt;</a> Copying and pasting selection starting at end of paragraph can incorrectly remove line break
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be after the first character ("l") of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+<div>line one<div>line two</div></div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-010-expected.txt b/LayoutTests/editing/pasteboard/paste-line-endings-010-expected.txt
new file mode 100644 (file)
index 0000000..1c72917
--- /dev/null
@@ -0,0 +1,41 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (0,0) size 784x240 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x84
+          RenderText {TEXT} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 162x28
+            text run at (0,28) width 162: "Fix for this bug: "
+          RenderInline {A} at (0,0) size 260x28 [color=#0000EE]
+            RenderText {TEXT} at (162,28) size 260x28
+              text run at (162,28) width 260: "<rdar://problem/4045513>"
+          RenderText {TEXT} at (422,28) size 721x56
+            text run at (422,28) width 299: " Copying and pasting selection"
+            text run at (0,56) width 601: "starting at end of paragraph can incorrectly remove line break"
+        RenderBlock {DIV} at (14,114) size 756x112
+          RenderText {TEXT} at (0,0) size 189x28
+            text run at (0,0) width 189: "Expected Results: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {TEXT} at (0,28) size 747x84
+            text run at (0,28) width 708: "Should see two lines of text below, self-documenting themselves as \"line"
+            text run at (0,56) width 747: "one\" and \"line two\". The insertion point must be after the first character (\"l\")"
+            text run at (0,84) width 131: "of \"line two\"."
+      RenderBlock {DIV} at (0,264) size 784x60
+        RenderBlock {DIV} at (0,0) size 784x60 [border: (2px solid #FF0000)]
+          RenderBlock {DIV} at (2,2) size 780x56
+            RenderBlock {DIV} at (0,0) size 780x28
+              RenderText {TEXT} at (0,0) size 78x28
+                text run at (0,0) width 78: "line one"
+            RenderBlock (anonymous) at (0,28) size 780x28
+              RenderText {TEXT} at (0,0) size 7x28
+                text run at (0,0) width 7: "l"
+              RenderText {TEXT} at (7,0) size 72x28
+                text run at (7,0) width 72: "ine two"
+selection is CARET:
+start:      position 1 of child 2 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+upstream:   position 1 of child 2 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
+downstream: position 0 of child 3 {TEXT} of child 2 {DIV} of child 1 {DIV} of root {DIV}
diff --git a/LayoutTests/editing/pasteboard/paste-line-endings-010.html b/LayoutTests/editing/pasteboard/paste-line-endings-010.html
new file mode 100644 (file)
index 0000000..cbaf20c
--- /dev/null
@@ -0,0 +1,64 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    font-size: 24px; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    for (i = 0; i < 8; i++)
+        moveSelectionForwardByCharacterCommand();
+    for (i = 0; i < 2; i++)
+        extendSelectionForwardByCharacterCommand();
+    copyCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Fix for this bug: 
+<a href="rdar://problem/4045513">&lt;rdar://problem/4045513&gt;</a> Copying and pasting selection starting at end of paragraph can incorrectly remove line break
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see two lines of text below, self-documenting themselves as "line one" and "line two". The insertion point must
+be after the first character ("l") of "line two".
+</div>
+</div>
+
+<div contenteditable id="root" style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
+<div id="test" class="editing">
+<div><div>line one</div>line two</div>
+</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
index 6565461a5f6db2be52fb388a9db2cd34dc790898..2e4f89259dbb6b44be5d2169a36ca8b9ec96d76d 100644 (file)
@@ -1,3 +1,62 @@
+2005-03-10  Ken Kocienda  <kocienda@apple.com>
+
+        Reviewed by John
+
+        Fix for these bugs:
+        
+        <rdar://problem/4045511> Copying and pasting end-of-paragraph selection puts insertion point in wrong place
+        <rdar://problem/4045513> Copying and pasting selection starting at end of paragraph can incorrectly remove line break
+
+        The copy/paste code before this patch had no notion of a "logical newline" at the start of the selection. We have
+        had a similar notion for "logical newline" at the end of the selection for quite some time. To fix these bugs, we
+        need to introduce the same idea for selection starts.
+
+        * khtml/editing/htmlediting.cpp:
+        (khtml::ReplacementFragment::ReplacementFragment): Process the "logical newline" at start as we write it out
+        in markup. Set the bit we added to this object to signify we have such a newline.
+        (khtml::ReplaceSelectionCommand::doApply): Many, many changes to introduce the new "logical newline" at start concept.
+        I also tried to simply the code that sets the start position for inserting content to be pasted. I also improved a
+        weakness in the smart-paste code. Now, we check before and after the paste for whether we need to add a leading or
+        trailing space. The code previous to this patch only did a "before" check, with the result that we sometimes added
+        a second space. In other words, the code did not realize that DOM changes done by pasting could cause formerly
+        unrendered whitespace to become rendered. Also moved line placeholder clean up code to its own function.
+        (khtml::ReplaceSelectionCommand::removeLinePlaceholderIfNeeded): New helper that further refines the notion
+        of when we can remove a line placeholder. The definition is now, "If a line placeholder is at the visible start
+        and visible end of its line, keep it; otherwise remove it".
+        * khtml/editing/htmlediting.h: Declare new functions. Rework inlines in ReplacementFragment class to account for
+        addition of new "logical newline" at start concept.
+        (khtml::ReplacementFragment::hasInterchangeNewlineAtStart): New accessor.
+        (khtml::ReplacementFragment::hasInterchangeNewlineAtEnd): Renamed from hasInterchangeNewline(), since before we
+        only had a bit for the end, hence we did not need to distinguish it from the start.
+        * khtml/editing/markup.cpp:
+        (khtml::createMarkup): Added code to detect and write out markup for cases where we have a "logical newline" at start.
+        * khtml/xml/dom2_rangeimpl.cpp:
+        (DOM::RangeImpl::startPosition): New helper.
+        (DOM::RangeImpl::endPosition): Ditto.
+        * khtml/xml/dom2_rangeimpl.h: Declare new helpers.
+        
+        New tests:
+        * layout-tests/editing/pasteboard/paste-line-endings-001-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-001.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-002-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-002.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-003-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-003.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-004-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-004.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-005-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-005.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-006-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-006.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-007-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-007.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-008-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-008.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-009-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-009.html: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-010-expected.txt: Added.
+        * layout-tests/editing/pasteboard/paste-line-endings-010.html: Added.
+
 2005-03-10  Darin Adler  <darin@apple.com>
 
         Reviewed by Richard.
index e1743a564fe709e97c38280d1ceb7f284932c482..cd872025c9bc9fffb9f7b04b4574065c685e4935 100644 (file)
@@ -4101,7 +4101,12 @@ void RemoveNodePreservingChildrenCommand::doApply()
 // ReplaceSelectionCommand
 
 ReplacementFragment::ReplacementFragment(DocumentImpl *document, DocumentFragmentImpl *fragment, bool matchStyle)
-    : m_document(document), m_fragment(fragment), m_matchStyle(matchStyle), m_hasInterchangeNewline(false), m_hasMoreThanOneBlock(false)
+    : m_document(document), 
+      m_fragment(fragment), 
+      m_matchStyle(matchStyle), 
+      m_hasInterchangeNewlineAtStart(false), 
+      m_hasInterchangeNewlineAtEnd(false), 
+      m_hasMoreThanOneBlock(false)
 {
     if (!m_document)
         return;
@@ -4130,12 +4135,19 @@ ReplacementFragment::ReplacementFragment(DocumentImpl *document, DocumentFragmen
     m_type = TreeFragment;
 
     NodeImpl *node = m_fragment->firstChild();
-    NodeImpl *nodeToDelete = 0;
+    NodeImpl *newlineAtStartNode = 0;
+    NodeImpl *newlineAtEndNode = 0;
     while (node) {
         NodeImpl *next = node->traverseNextNode();
         if (isInterchangeNewlineNode(node)) {
-            m_hasInterchangeNewline = true;
-            nodeToDelete = node;
+            if (next || node == m_fragment->firstChild()) {
+                m_hasInterchangeNewlineAtStart = true;
+                newlineAtStartNode = node;
+            }
+            else {
+                m_hasInterchangeNewlineAtEnd = true;
+                newlineAtEndNode = node;
+            }
         }
         else if (isInterchangeConvertedSpaceSpan(node)) {
             NodeImpl *n = 0;
@@ -4152,9 +4164,10 @@ ReplacementFragment::ReplacementFragment(DocumentImpl *document, DocumentFragmen
         node = next;
     }
 
-    if (nodeToDelete)
-        removeNode(nodeToDelete);
-
+    if (newlineAtStartNode)
+        removeNode(newlineAtStartNode);
+    if (newlineAtEndNode)
+        removeNode(newlineAtEndNode);
     
     NodeImpl *holder = insertFragmentForTestRendering();
     holder->ref();
@@ -4498,7 +4511,8 @@ void ReplaceSelectionCommand::doApply()
         mergeStart = true;
     } else {
         // merge if current selection starts inside a paragraph, or there is only one block and no interchange newline to add
-        mergeStart = !isStartOfParagraph(visibleStart) || (!m_fragment.hasInterchangeNewline() && !m_fragment.hasMoreThanOneBlock());
+        mergeStart = !m_fragment.hasInterchangeNewlineAtStart() && 
+            (!isStartOfParagraph(visibleStart) || (!m_fragment.hasInterchangeNewlineAtEnd() && !m_fragment.hasMoreThanOneBlock()));
         
         // This is a workaround for this bug:
         // <rdar://problem/4013642> REGRESSION (Mail): Copied quoted word does not paste as a quote if pasted at the start of a line
@@ -4510,41 +4524,55 @@ void ReplaceSelectionCommand::doApply()
     
     // decide whether to later append nodes to the end
     NodeImpl *beyondEndNode = 0;
-    if (!isEndOfParagraph(visibleEnd)) {
+    if (!isEndOfParagraph(visibleEnd) && !m_fragment.hasInterchangeNewlineAtEnd()) {
         beyondEndNode = selection.end().downstream(StayInBlock).node();
     }
-    bool moveNodesAfterEnd = beyondEndNode && !m_fragment.hasInterchangeNewline() && (startBlock != endBlock || m_fragment.hasMoreThanOneBlock());
-    
-    Position startPos = Position(selection.start().node()->enclosingBlockFlowElement(), 0);
-    Position endPos; 
-    EStayInBlock upstreamStayInBlock = StayInBlock;
+    bool moveNodesAfterEnd = beyondEndNode && (startBlock != endBlock || m_fragment.hasMoreThanOneBlock());
 
+    Position startPos = selection.start();
+    
     // delete the current range selection, or insert paragraph for caret selection, as needed
     if (selection.isRange()) {
-        deleteSelection(false, !(m_fragment.hasInterchangeNewline() || m_fragment.hasMoreThanOneBlock()));
-    } else if (selection.isCaret() && !startAtBlockBoundary &&
-             !m_fragment.hasInterchangeNewline() && m_fragment.hasMoreThanOneBlock() && !isEndOfParagraph(visibleEnd)) {
-        // The start and the end need to wind up in separate blocks.
-        // Insert a paragraph separator to make that happen.
-        insertParagraphSeparator();
-        upstreamStayInBlock = DoNotStayInBlock;
-    }
-    
-    // calculate the start and end of the resulting selection
-    selection = endingSelection();
-    if (m_matchStyle) {
-        startPos = selection.start();
-    } else {
-        if (startAtStartOfBlock && startBlock->inDocument()) {
-            startPos = Position(startBlock, 0);
-        } else if (startAtEndOfBlock) {
-            startPos = selection.start().downstream(StayInBlock);
-        } else {
-            startPos = selection.start().upstream(upstreamStayInBlock);
+        deleteSelection(false, !(m_fragment.hasInterchangeNewlineAtStart() || m_fragment.hasInterchangeNewlineAtEnd() || m_fragment.hasMoreThanOneBlock()));
+        document()->updateLayout();
+        visibleStart = VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY);
+        if (m_fragment.hasInterchangeNewlineAtStart()) {
+            if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
+                if (!isEndOfDocument(visibleStart))
+                    setEndingSelection(visibleStart.next());
+            }
+            else {
+                insertParagraphSeparator();
+                setEndingSelection(VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY));
+            }
+        }
+        startPos = endingSelection().start();
+    } 
+    else {
+        ASSERT(selection.isCaret());
+        if (m_fragment.hasInterchangeNewlineAtStart()) {
+            if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
+                if (!isEndOfDocument(visibleStart))
+                    setEndingSelection(visibleStart.next());
+            }
+            else {
+                insertParagraphSeparator();
+                setEndingSelection(VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY));
+            }
+        }
+        if (!m_fragment.hasInterchangeNewlineAtEnd() && m_fragment.hasMoreThanOneBlock() && 
+            !startAtBlockBoundary && !isEndOfParagraph(visibleEnd)) {
+            // The start and the end need to wind up in separate blocks.
+            // Insert a paragraph separator to make that happen.
+            insertParagraphSeparator();
+            setEndingSelection(VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY).previous());
         }
+        startPos = endingSelection().start();
     }
-    endPos = selection.end().downstream(); 
-    
+
+    if (startAtStartOfBlock && startBlock->inDocument())
+        startPos = Position(startBlock, 0);
+
     KHTMLPart *part = document()->part();
     if (m_matchStyle) {
         m_insertionStyle = styleAtPosition(startPos);
@@ -4560,14 +4588,13 @@ void ReplaceSelectionCommand::doApply()
     if (!m_fragment.firstChild())
         return;
     
-    // now that we are about to add content, check whether a placeholder element can be removed
-    // if so, do it and update startPos and endPos
+    // check for a line placeholder, and store it away for possible removal later.
     NodeImpl *block = startPos.node()->enclosingBlockFlowElement();
     NodeImpl *linePlaceholder = findBlockPlaceholder(block);
     if (!linePlaceholder) {
         Position downstream = startPos.downstream(StayInBlock);
         if (downstream.node()->id() == ID_BR && downstream.offset() == 0 && 
-            m_fragment.hasInterchangeNewline() &&
+            m_fragment.hasInterchangeNewlineAtEnd() &&
             isFirstVisiblePositionOnLine(VisiblePosition(downstream, VP_DEFAULT_AFFINITY)))
             linePlaceholder = downstream.node();
     }
@@ -4658,32 +4685,44 @@ void ReplaceSelectionCommand::doApply()
 
     // step 3 : handle "smart replace" whitespace
     if (addTrailingSpace && m_lastNodeInserted) {
-        if (m_lastNodeInserted->isTextNode()) {
-            TextImpl *text = static_cast<TextImpl *>(m_lastNodeInserted);
-            insertTextIntoNode(text, text->length(), nonBreakingSpaceString());
-            insertionPos = Position(text, text->length());
-        }
-        else {
-            NodeImpl *node = document()->createEditingTextNode(nonBreakingSpaceString());
-            insertNodeAfterAndUpdateNodesInserted(node, m_lastNodeInserted);
-            insertionPos = Position(node, 1);
+        document()->updateLayout();
+        Position pos(m_lastNodeInserted, m_lastNodeInserted->caretMaxOffset());
+        bool needsTrailingSpace = pos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull();
+        if (needsTrailingSpace) {
+            if (m_lastNodeInserted->isTextNode()) {
+                TextImpl *text = static_cast<TextImpl *>(m_lastNodeInserted);
+                insertTextIntoNode(text, text->length(), nonBreakingSpaceString());
+                insertionPos = Position(text, text->length());
+            }
+            else {
+                NodeImpl *node = document()->createEditingTextNode(nonBreakingSpaceString());
+                insertNodeAfterAndUpdateNodesInserted(node, m_lastNodeInserted);
+                insertionPos = Position(node, 1);
+            }
         }
     }
 
     if (addLeadingSpace && m_firstNodeInserted) {
-        if (m_firstNodeInserted->isTextNode()) {
-            TextImpl *text = static_cast<TextImpl *>(m_firstNodeInserted);
-            insertTextIntoNode(text, 0, nonBreakingSpaceString());
-        } else {
-            NodeImpl *node = document()->createEditingTextNode(nonBreakingSpaceString());
-            insertNodeBeforeAndUpdateNodesInserted(node, m_firstNodeInserted);
+        document()->updateLayout();
+        Position pos(m_firstNodeInserted, 0);
+        bool needsLeadingSpace = pos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull();
+        if (needsLeadingSpace) {
+            if (m_firstNodeInserted->isTextNode()) {
+                TextImpl *text = static_cast<TextImpl *>(m_firstNodeInserted);
+                insertTextIntoNode(text, 0, nonBreakingSpaceString());
+            } else {
+                NodeImpl *node = document()->createEditingTextNode(nonBreakingSpaceString());
+                insertNodeBeforeAndUpdateNodesInserted(node, m_firstNodeInserted);
+            }
         }
     }
     
     Position lastPositionToSelect;
 
     // step 4 : handle trailing newline
-    if (m_fragment.hasInterchangeNewline()) {
+    if (m_fragment.hasInterchangeNewlineAtEnd()) {
+        removeLinePlaceholderIfNeeded(linePlaceholder);
+
         if (!m_lastNodeInserted) {
             lastPositionToSelect = endingSelection().end().downstream();
         }
@@ -4764,29 +4803,24 @@ void ReplaceSelectionCommand::doApply()
     completeHTMLReplacement(lastPositionToSelect);
     
     // step 5 : mop up
-    if (linePlaceholder) {
-        document()->updateLayout();
-        if (linePlaceholder->inDocument()) {
-            // remove the placeholder if it seems to have no effect
-            // FIXME: cannot rely on height() alone, tho, because it is zero for a BR on a line
-            // that has only non-text in it (e.g. replaced elements).  See <rdar://problem/4040358>.
-            bool dumpIt = (!linePlaceholder->renderer() || linePlaceholder->renderer()->height() == 0);
-            if (dumpIt) {
-                // start workaround for <rdar://problem/4040358>
-                VisiblePosition placeholderPos(linePlaceholder, linePlaceholder->renderer()->caretMinOffset(), DOWNSTREAM);
-                dumpIt = placeholderPos.next().isNull() || isFirstVisiblePositionOnLine(placeholderPos);
-                // end workaround for <rdar://problem/4040358>
-            }
-            
-            if (dumpIt) {
-                removeNode(linePlaceholder);
-            } else if (!mergeStart && !m_fragment.hasInterchangeNewline()) {
-                NodeImpl *block = linePlaceholder->enclosingBlockFlowElement();
-                removeNode(linePlaceholder);
-                document()->updateLayout();
-                if (!block->renderer() || block->renderer()->height() == 0)
-                    removeNode(block);
-            }
+    removeLinePlaceholderIfNeeded(linePlaceholder);
+}
+
+void ReplaceSelectionCommand::removeLinePlaceholderIfNeeded(NodeImpl *linePlaceholder)
+{
+    if (!linePlaceholder)
+        return;
+        
+    document()->updateLayout();
+    if (linePlaceholder->inDocument()) {
+        VisiblePosition placeholderPos(linePlaceholder, linePlaceholder->renderer()->caretMinOffset(), DOWNSTREAM);
+        if (placeholderPos.next().isNull() ||
+            !(isFirstVisiblePositionOnLine(placeholderPos) && isLastVisiblePositionOnLine(placeholderPos))) {
+            NodeImpl *block = linePlaceholder->enclosingBlockFlowElement();
+            removeNode(linePlaceholder);
+            document()->updateLayout();
+            if (!block->renderer() || block->renderer()->height() == 0)
+                removeNode(block);
         }
     }
 }
index 024d7cf469865b85822e7f9041c12a010cc31eb9..31e441d3a1c17d498185d2bfc50472425f33b79b 100644 (file)
@@ -716,7 +716,8 @@ public:
     bool isTreeFragment() const { return m_type == TreeFragment; }
 
     bool hasMoreThanOneBlock() const { return m_hasMoreThanOneBlock; }
-    bool hasInterchangeNewline() const { return m_hasInterchangeNewline; }
+    bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAtStart; }
+    bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEnd; }
 
 private:
     // no copy construction or assignment
@@ -744,7 +745,8 @@ private:
     DOM::DocumentFragmentImpl *m_fragment;
     QValueList<NodeDesiredStyle> m_styles;
     bool m_matchStyle;
-    bool m_hasInterchangeNewline;
+    bool m_hasInterchangeNewlineAtStart;
+    bool m_hasInterchangeNewlineAtEnd;
     bool m_hasMoreThanOneBlock;
 };
 
@@ -766,6 +768,7 @@ private:
 
     void updateNodesInserted(DOM::NodeImpl *);
     void fixupNodeStyles(const QValueList<NodeDesiredStyle> &);
+    void removeLinePlaceholderIfNeeded(DOM::NodeImpl *);
 
     ReplacementFragment m_fragment;
     DOM::NodeImpl *m_firstNodeInserted;
index bfe8b101a0d4968a0b68ca9c3317e7954f8cc65e..b7312db04892319c05dbc3459905fd84200edd86 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "css/css_computedstyle.h"
 #include "css/css_valueimpl.h"
+#include "editing/visible_position.h"
+#include "editing/visible_units.h"
 #include "html/html_elementimpl.h"
 #include "xml/dom_position.h"
 #include "xml/dom2_rangeimpl.h"
@@ -301,6 +303,8 @@ QString createMarkup(const RangeImpl *range, QPtrList<NodeImpl> *nodes, EAnnotat
     if (!range || range->isDetached())
         return QString();
 
+    static const QString interchangeNewlineString = QString("<br class=\"") + AppleInterchangeNewline + "\">";
+
     int exceptionCode = 0;
     NodeImpl *commonAncestor = range->commonAncestorContainer(exceptionCode);
     ASSERT(exceptionCode == 0);
@@ -326,9 +330,19 @@ QString createMarkup(const RangeImpl *range, QPtrList<NodeImpl> *nodes, EAnnotat
     CSSMutableStyleDeclarationImpl *defaultStyle = pos.computedStyle()->copyInheritableProperties();
     defaultStyle->ref();
     
+    NodeImpl *startNode = range->startNode();
+    VisiblePosition visibleStart(range->startPosition(), VP_DEFAULT_AFFINITY);
+    VisiblePosition visibleEnd(range->endPosition(), VP_DEFAULT_AFFINITY);
+    if (isEndOfBlock(visibleStart)) {
+        if (visibleStart == visibleEnd.previous())
+            return interchangeNewlineString;
+        markups.append(interchangeNewlineString);
+        startNode = startNode->traverseNextNode();
+    }
+    
     // Iterate through the nodes of the range.
     NodeImpl *next;
-    for (NodeImpl *n = range->startNode(); n != pastEnd; n = next) {
+    for (NodeImpl *n = startNode; n != pastEnd; n = next) {
         next = n->traverseNextNode();
 
         if (n->isBlockFlow() && next == pastEnd) {
@@ -424,7 +438,6 @@ QString createMarkup(const RangeImpl *range, QPtrList<NodeImpl> *nodes, EAnnotat
         NodeImpl *block = pos.node()->enclosingBlockFlowElement();
         NodeImpl *upstreamBlock = pos.upstream().node()->enclosingBlockFlowElement();
         if (block != upstreamBlock) {
-            static const QString interchangeNewlineString = QString("<br class=\"") + AppleInterchangeNewline + "\">";
             markups.append(interchangeNewlineString);
         }
     }
index 1f69498b6800d18b3045e3256ed0795f68be5b93..72c6cb816fadeb3d9b76bb0d73d497088fceeed0 100644 (file)
@@ -1278,6 +1278,16 @@ bool RangeImpl::containedByReadOnly() const
     return false;
 }
 
+Position RangeImpl::startPosition() const
+{
+    return Position(m_startContainer, m_startOffset);
+}
+
+Position RangeImpl::endPosition() const
+{
+    return Position(m_endContainer, m_endOffset);
+}
+
 NodeImpl *RangeImpl::startNode() const
 {
     if (!m_startContainer)
index dac4639a4035eecb61bd576a63474346a9262b77..878b2bda113e67b6eb95d7c231977cca638579fa 100644 (file)
@@ -93,6 +93,9 @@ public:
     };
     DocumentFragmentImpl *processContents ( ActionType action, int &exceptioncode );
 
+    Position startPosition() const;
+    Position endPosition() const;
+
     NodeImpl *startNode() const;
     NodeImpl *pastEndNode() const;