LayoutTests:
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jul 2006 04:39:25 +0000 (04:39 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jul 2006 04:39:25 +0000 (04:39 +0000)
        Reviewed by Adele and Justin.

        - test for http://bugzilla.opendarwin.org/show_bug.cgi?id=9630
          REGRESSION: some spaces typed in <textarea> are posted as non-breaking spaces

        * fast/forms/textarea-type-spaces-expected.txt: Added.
        * fast/forms/textarea-type-spaces.html: Added.

        - test for http://bugzilla.opendarwin.org/show_bug.cgi?id=9939
          REGRESSION: Pasting text into native text area with newline at end does not preserve newline

        * fast/forms/textarea-paste-newline-expected.txt: Added.
        * fast/forms/textarea-paste-newline.html: Added.

        - updated tests affected by above changes, results are equivalent or better

        * editing/pasteboard/4641033-expected.checksum:
        * editing/pasteboard/4641033-expected.png:
        * editing/pasteboard/4641033-expected.txt:
        * editing/pasteboard/paste-table-003-expected.checksum:
        * editing/pasteboard/paste-table-003-expected.png:
        * editing/pasteboard/paste-table-003-expected.txt:
        * editing/pasteboard/paste-text-016-expected.txt:
        * editing/pasteboard/quirks-mode-br-1-expected.txt:
        * editing/pasteboard/quirks-mode-br-2-expected.txt:
        * fast/forms/textarea-scrolled-type-expected.checksum:
        * fast/forms/textarea-scrolled-type-expected.png:
        * fast/forms/textarea-scrolled-type-expected.txt:

        - changed a test to be a "dump as text" test

        * fast/forms/paste-into-textarea-expected.txt:
        * fast/forms/paste-into-textarea.html:
        * fast/forms/paste-into-textarea-expected.checksum: Removed.
        * fast/forms/paste-into-textarea-expected.png: Removed.

        - changed a test to be a "dump as text" test, improved test a bit and also checked in new results

        * fast/forms/textarea-scrolled-endline-caret-expected.txt:
        * fast/forms/textarea-scrolled-endline-caret.html:

        - fixed a test that was raising an exception every time it ran

        * fast/forms/attributed-strings-expected.txt:
        * fast/forms/attributed-strings.html:

        - corrected checksums on a bunch of tests (pngs were right, but checksums wrong, apparently)

        * editing/deleting/delete-to-select-table-expected.checksum:
        * editing/selection/3690719-expected.checksum:
        * editing/selection/clear-selection-expected.checksum:
        * editing/undo/undo-misspellings-expected.checksum:

        - added some missing pixel test results

        * editing/pasteboard/nested-blocks-with-text-area-expected.checksum: Added.
        * editing/pasteboard/nested-blocks-with-text-area-expected.png: Added.
        * editing/pasteboard/nested-blocks-with-text-field-expected.checksum: Added.
        * editing/pasteboard/nested-blocks-with-text-field-expected.png: Added.

WebCore:

        Reviewed by Adele and Justin.

        - fix <rdar://problem/4613616> REGRESSION: some spaces typed in <textarea> are posted as non-breaking spaces (9630)
          http://bugzilla.opendarwin.org/show_bug.cgi?id=9630
        - also fixes http://bugzilla.opendarwin.org/show_bug.cgi?id=9939
          REGRESSION: Pasting text into native text area with newline at end does not preserve newline
        - removed some uses of DeprecatedPtrList in the markup code

        Test: fast/forms/textarea-type-spaces.html
        Test: fast/forms/textarea-paste-newline.html

        * bindings/objc/DOMHTML.mm: (-[DOMHTMLDocument createDocumentFragmentWithText:]):
        Updated call to pass a range -- in this case it is the range of the entire document,
        so this will not handle the whitespace properly.

        * bridge/mac/WebCoreFrameBridge.h: Added range context parameter to the
        documentFragmentWithText: method, so we can handle whitespace properly.
        * bridge/mac/WebCoreFrameBridge.mm:
        (-[WebCoreFrameBridge nodesFromList:]): Changed from DeprecatedPtrList to Vector.
        (-[WebCoreFrameBridge markupStringFromNode:nodes:]): Ditto.
        (-[WebCoreFrameBridge markupStringFromRange:nodes:]): Ditto.
        (-[WebCoreFrameBridge documentFragmentWithText:inContext:]): Added range context
        parameter -- pass it on to createFragmentFromText.
        (-[WebCoreFrameBridge documentFragmentWithNodesAsParagraphs:]): Changed from
        DeprecatedPtrList to Vector.
        (-[WebCoreFrameBridge replaceSelectionWithText:selectReplacement:smartReplace:]):
        Pass the range of the current selection as context when creating the fragment.

        * dom/Position.cpp: (WebCore::Position::inRenderedText): Replace range check with
        a call to the new containsCaretOffset function -- helps make the caret work right when
        it is past the end of the last line in a textarea.

        * editing/CompositeEditCommand.cpp:
        (WebCore::CompositeEditCommand::rebalanceWhitespaceAt): Don't do anything if the
        style does not call for collapsing whitespace.
        (WebCore::CompositeEditCommand::rebalanceWhitespace): Call replaceWhitespaceAt
        to share code, including the new logic mentioned above.

        * editing/InsertLineBreakCommand.cpp: (WebCore::InsertLineBreakCommand::doApply):
        Use a text node instead of a break element when inserting and the style is preserveNewline.

        * editing/JSEditor.cpp: (WebCore::execRemoveFormat): Pass the selection range
        to createFragmentFromText.

        * editing/RebalanceWhitespaceCommand.cpp: (WebCore::RebalanceWhitespaceCommand::doApply):
        Assert that we're in a style that collapses whitespace. It's the caller's responsibility
        not to call otherwise.

        * editing/ReplaceSelectionCommand.h: Removed unused destructor, type, isSingleTextNode,
        isTreeFragment, m_type, and added a context parameter to inertFragmentForTestRendering.
        Also changed the constructor to take a selection rather than a pointer to the root
        editable element, replaced removeEndBRIfNeeded with shouldRemoveEndBR and removed an
        unused parameter from shouldMergeEnd.
        * editing/ReplaceSelectionCommand.cpp:
        (WebCore::ReplacementFragment::ReplacementFragment): Removed code to set up m_type.
        Compute root editable element from passed-in selection. Used the start of the selection
        as a base node for style purposes for the test rendering. Removed the special case
        "single text node" alternative to createFragmentFromText in the plain text case, since
        createFragmentFromText now handles that correctly.
        (WebCore::ReplacementFragment::insertFragmentForTestRendering): Copy the whitespace
        property from the source location when creating a temporary element for test rendering.
        (WebCore::ReplacementFragment::shouldMergeEnd): Removed unneeded boolean
        parameter fragmentHadInterchangeNewlineAtEnd, which is always false.
        (WebCore::ReplaceSelectionCommand::doApply): Update for ReplacementFragment changes,
        change code to not remove end BR when it can be re-used instead, don't call the
        paragraph separator insertion when the position is at the start of a paragraph already,
        removed redundant computation of identical "next" value, removed unneeded boolean
        parameter to shouldMergeEnd, add case for merging when all we need to do is to delete
        a newline character, removed unneeded code to set insertionPos after all code that uses
        it, and  use spaces instead of non-breaking spaces when doing smart paste if the
        context is one where we do not collapse white space.
        (WebCore::ReplaceSelectionCommand::shouldRemoveEndBR): Renamed and changed to return
        a boolean instead of doing the removal.

        * editing/markup.h: Use Vector instead of DeprecatedPtrList. Change the
        createFragmentFromText function to take a range for context instead of a document.
        * editing/markup.cpp:
        (WebCore::markup): Use Vector instead of DeprecatedPtrList.
        (WebCore::createMarkup): Ditto.
        (WebCore::createParagraphContentsFromString): Remove unneeded document parameter
        and changed a couple places to use isEmpty instead of comparing with "".
        (WebCore::createFragmentFromText): Given the new context parameter, if the context
        is one that preserves newlines, then use "\n" instead of <br> elements.
        (WebCore::createFragmentFromNodes): Use Vector instead of DeprecatedPtrList.

        * html/HTMLElement.cpp: (WebCore::HTMLElement::setInnerText): Do not use <br>
        elements if the context of this node is one where we preserve newlines.

        * rendering/InlineTextBox.h:
        * rendering/InlineTextBox.cpp: (WebCore::InlineTextBox::containsCaretOffset):
        Added. Implements the appropriate rule for determining if a caret position is
        in this line or not. Returns true for both one line and the next in cases where
        affinity must be considered to determine which line the caret is on.

        * rendering/RenderText.h: Make atLineWrap no longer be a member function.
        * rendering/RenderText.cpp:
        (WebCore::atLineWrap): Remove special rule about preserveNewline and isLineBreak,
        which will no longer apply due to the new containsCaretOffset function logic.
        (WebCore::RenderText::caretRect): Use containsCaretOffset.
        (WebCore::RenderText::inlineBox): Ditto.

        * rendering/RenderTextControl.cpp:
        (WebCore::RenderTextControl::updateFromElement): Make a placeholder <br> element
        after calling setInnerText so that the last newline in the string has the effect
        we expect outside the HTML world (an additional line).
        (WebCore::RenderTextControl::setSelectionRange): Set granularity of the selection
        too. The layout tests caught this problem, which needs a better solution long term.
        (WebCore::RenderTextControl::text): Call textContent with the parameter false
        so it will not include newlines for <br> elements. Now the only <br> element
        that will ever be in the shadow DOM tree is the one to prevent collapsing, and
        that one should not show up in the text value.

        * rendering/bidi.cpp: (WebCore::RenderBlock::findNextLineBreak): Took a rule
        that specifically called out the pre whitespace mode and made it work for all
        the modes that preserve newlines. This makes sure we get a last line box for
        text after the last "\n" even in cases where there is no <br> afterward.

        * editing/DeleteSelectionCommand.cpp:
        (WebCore::DeleteSelectionCommand::fixupWhitespace):
        * editing/InsertParagraphSeparatorCommand.cpp:
        (WebCore::InsertParagraphSeparatorCommand::doApply):
        Added assertions to make sure we don't do anything when we're not collapsing
        whitespace.

        * html/HTMLTextAreaElement.cpp: (WebCore::HTMLTextAreaElement::setDefaultValue):
        Changed to use Vector instead of DeprecatedPtrList.

        * editing/HTMLInterchange.cpp: Removed obsolete comment.

        * loader/Cache.h: Removed a stray include.

WebKit:

        Reviewed by Adele and Justin.

        - update for change to require context when creating fragments from text
          (needed to handle whitespace properly)

        * WebView/WebHTMLView.m:
        (-[WebHTMLView _documentFragmentFromPasteboard:inContext:allowPlainText:chosePlainText:]):
        Added context parameter, pass through to bridge.
        (-[WebHTMLView _pasteWithPasteboard:allowPlainText:]): Pass selection range as context
        when calling above method.
        (-[WebHTMLView concludeDragForDraggingInfo:actionMask:]): Pass drag caret as context when
        calling above method.

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

60 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/deleting/delete-to-select-table-expected.checksum
LayoutTests/editing/pasteboard/4641033-expected.checksum
LayoutTests/editing/pasteboard/4641033-expected.png
LayoutTests/editing/pasteboard/4641033-expected.txt
LayoutTests/editing/pasteboard/nested-blocks-with-text-area-expected.checksum [new file with mode: 0644]
LayoutTests/editing/pasteboard/nested-blocks-with-text-area-expected.png [new file with mode: 0644]
LayoutTests/editing/pasteboard/nested-blocks-with-text-field-expected.checksum [new file with mode: 0644]
LayoutTests/editing/pasteboard/nested-blocks-with-text-field-expected.png [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-table-003-expected.checksum
LayoutTests/editing/pasteboard/paste-table-003-expected.png
LayoutTests/editing/pasteboard/paste-table-003-expected.txt
LayoutTests/editing/pasteboard/paste-text-016-expected.txt
LayoutTests/editing/pasteboard/quirks-mode-br-1-expected.txt
LayoutTests/editing/pasteboard/quirks-mode-br-2-expected.txt
LayoutTests/editing/selection/3690719-expected.checksum
LayoutTests/editing/selection/clear-selection-expected.checksum
LayoutTests/editing/undo/undo-misspellings-expected.checksum
LayoutTests/fast/forms/attributed-strings-expected.txt
LayoutTests/fast/forms/attributed-strings.html
LayoutTests/fast/forms/paste-into-textarea-expected.checksum [deleted file]
LayoutTests/fast/forms/paste-into-textarea-expected.png [deleted file]
LayoutTests/fast/forms/paste-into-textarea-expected.txt
LayoutTests/fast/forms/paste-into-textarea.html
LayoutTests/fast/forms/textarea-paste-newline-expected.txt [new file with mode: 0644]
LayoutTests/fast/forms/textarea-paste-newline.html [new file with mode: 0644]
LayoutTests/fast/forms/textarea-scrolled-endline-caret-expected.txt
LayoutTests/fast/forms/textarea-scrolled-endline-caret.html
LayoutTests/fast/forms/textarea-scrolled-type-expected.checksum
LayoutTests/fast/forms/textarea-scrolled-type-expected.png
LayoutTests/fast/forms/textarea-scrolled-type-expected.txt
LayoutTests/fast/forms/textarea-type-spaces-expected.txt [new file with mode: 0644]
LayoutTests/fast/forms/textarea-type-spaces.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/bindings/objc/DOMHTML.mm
WebCore/bridge/mac/WebCoreFrameBridge.h
WebCore/bridge/mac/WebCoreFrameBridge.mm
WebCore/dom/Position.cpp
WebCore/editing/CompositeEditCommand.cpp
WebCore/editing/DeleteSelectionCommand.cpp
WebCore/editing/HTMLInterchange.cpp
WebCore/editing/InsertLineBreakCommand.cpp
WebCore/editing/InsertParagraphSeparatorCommand.cpp
WebCore/editing/JSEditor.cpp
WebCore/editing/RebalanceWhitespaceCommand.cpp
WebCore/editing/ReplaceSelectionCommand.cpp
WebCore/editing/ReplaceSelectionCommand.h
WebCore/editing/markup.cpp
WebCore/editing/markup.h
WebCore/html/HTMLElement.cpp
WebCore/html/HTMLTextAreaElement.cpp
WebCore/loader/Cache.h
WebCore/rendering/InlineTextBox.cpp
WebCore/rendering/InlineTextBox.h
WebCore/rendering/RenderText.cpp
WebCore/rendering/RenderText.h
WebCore/rendering/RenderTextControl.cpp
WebCore/rendering/bidi.cpp
WebKit/ChangeLog
WebKit/WebView/WebHTMLView.m

index 15e928d..13e567c 100644 (file)
@@ -1,3 +1,65 @@
+2006-07-24  Darin Adler  <darin@apple.com>
+
+        Reviewed by Adele and Justin.
+
+        - test for http://bugzilla.opendarwin.org/show_bug.cgi?id=9630
+          REGRESSION: some spaces typed in <textarea> are posted as non-breaking spaces
+
+        * fast/forms/textarea-type-spaces-expected.txt: Added.
+        * fast/forms/textarea-type-spaces.html: Added.
+
+        - test for http://bugzilla.opendarwin.org/show_bug.cgi?id=9939
+          REGRESSION: Pasting text into native text area with newline at end does not preserve newline
+
+        * fast/forms/textarea-paste-newline-expected.txt: Added.
+        * fast/forms/textarea-paste-newline.html: Added.
+
+        - updated tests affected by above changes, results are equivalent or better
+
+        * editing/pasteboard/4641033-expected.checksum:
+        * editing/pasteboard/4641033-expected.png:
+        * editing/pasteboard/4641033-expected.txt:
+        * editing/pasteboard/paste-table-003-expected.checksum:
+        * editing/pasteboard/paste-table-003-expected.png:
+        * editing/pasteboard/paste-table-003-expected.txt:
+        * editing/pasteboard/paste-text-016-expected.txt:
+        * editing/pasteboard/quirks-mode-br-1-expected.txt:
+        * editing/pasteboard/quirks-mode-br-2-expected.txt:
+        * fast/forms/textarea-scrolled-type-expected.checksum:
+        * fast/forms/textarea-scrolled-type-expected.png:
+        * fast/forms/textarea-scrolled-type-expected.txt:
+
+        - changed a test to be a "dump as text" test
+
+        * fast/forms/paste-into-textarea-expected.txt:
+        * fast/forms/paste-into-textarea.html:
+        * fast/forms/paste-into-textarea-expected.checksum: Removed.
+        * fast/forms/paste-into-textarea-expected.png: Removed.
+
+        - changed a test to be a "dump as text" test, improved test a bit and also checked in new results
+
+        * fast/forms/textarea-scrolled-endline-caret-expected.txt:
+        * fast/forms/textarea-scrolled-endline-caret.html:
+
+        - fixed a test that was raising an exception every time it ran
+
+        * fast/forms/attributed-strings-expected.txt:
+        * fast/forms/attributed-strings.html:
+
+        - corrected checksums on a bunch of tests (pngs were right, but checksums wrong, apparently)
+
+        * editing/deleting/delete-to-select-table-expected.checksum:
+        * editing/selection/3690719-expected.checksum:
+        * editing/selection/clear-selection-expected.checksum:
+        * editing/undo/undo-misspellings-expected.checksum:
+
+        - added some missing pixel test results
+
+        * editing/pasteboard/nested-blocks-with-text-area-expected.checksum: Added.
+        * editing/pasteboard/nested-blocks-with-text-area-expected.png: Added.
+        * editing/pasteboard/nested-blocks-with-text-field-expected.checksum: Added.
+        * editing/pasteboard/nested-blocks-with-text-field-expected.png: Added.
+
 2006-07-24  Adele Peterson  <adele@apple.com>
 
         Reviewed by Justin.
index 526ae74..5b42d56 100644 (file)
@@ -1 +1 @@
-827eed3249a8431338e7c6ea96dc90d8
\ No newline at end of file
+9a95881ba32b5b25fa40bd8cf30fa1d4
\ No newline at end of file
index 9368572..7a2c011 100644 (file)
Binary files a/LayoutTests/editing/pasteboard/4641033-expected.png and b/LayoutTests/editing/pasteboard/4641033-expected.png differ
index a80ab16..ae1f2d0 100644 (file)
@@ -3,7 +3,7 @@ EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML
 EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document toDOMRange:range from 0 of DIV > DIV > BODY > HTML > #document to 0 of DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document toDOMRange:range from 3 of DIV > BODY > HTML > #document to 3 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
@@ -27,15 +27,12 @@ layer at (0,0) size 800x600
             text run at (251,0) width 384: " Copy/paste of a select element fails to include the options"
           RenderText {#text} at (635,0) size 4x18
             text run at (635,0) width 4: "."
-      RenderBlock {DIV} at (0,86) size 784x128
-        RenderBlock (anonymous) at (0,0) size 784x110
-          RenderImage {IMG} at (0,0) size 76x103
-          RenderText {#text} at (76,89) size 4x18
-            text run at (76,89) width 4: " "
-          RenderMenuList {SELECT} at (82,90) size 36x18
-        RenderBlock {DIV} at (0,110) size 784x18
-          RenderBR {BR} at (0,0) size 0x18
-      RenderBlock (anonymous) at (0,214) size 784x110
+      RenderBlock {DIV} at (0,86) size 784x110
+        RenderImage {IMG} at (0,0) size 76x103
+        RenderText {#text} at (76,89) size 4x18
+          text run at (76,89) width 4: " "
+        RenderMenuList {SELECT} at (82,90) size 36x18
+      RenderBlock (anonymous) at (0,196) size 784x110
         RenderImage {IMG} at (0,0) size 76x103
         RenderText {#text} at (76,89) size 4x18
           text run at (76,89) width 4: " "
@@ -45,4 +42,4 @@ layer at (0,0) size 800x600
               text run at (0,0) width 19: "    1"
         RenderText {#text} at (0,0) size 0x0
         RenderText {#text} at (0,0) size 0x0
-caret: position 0 of child 0 {BR} of child 3 {DIV} of child 4 {DIV} of child 0 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 2 {SELECT} of child 4 {DIV} of child 0 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/pasteboard/nested-blocks-with-text-area-expected.checksum b/LayoutTests/editing/pasteboard/nested-blocks-with-text-area-expected.checksum
new file mode 100644 (file)
index 0000000..b6b26ca
--- /dev/null
@@ -0,0 +1 @@
+fd30caa739fed6b0a841c8fc21115434
\ No newline at end of file
diff --git a/LayoutTests/editing/pasteboard/nested-blocks-with-text-area-expected.png b/LayoutTests/editing/pasteboard/nested-blocks-with-text-area-expected.png
new file mode 100644 (file)
index 0000000..a277ead
Binary files /dev/null and b/LayoutTests/editing/pasteboard/nested-blocks-with-text-area-expected.png differ
diff --git a/LayoutTests/editing/pasteboard/nested-blocks-with-text-field-expected.checksum b/LayoutTests/editing/pasteboard/nested-blocks-with-text-field-expected.checksum
new file mode 100644 (file)
index 0000000..8bcf5a6
--- /dev/null
@@ -0,0 +1 @@
+81191b6afbb0d57245c89090b4228287
\ No newline at end of file
diff --git a/LayoutTests/editing/pasteboard/nested-blocks-with-text-field-expected.png b/LayoutTests/editing/pasteboard/nested-blocks-with-text-field-expected.png
new file mode 100644 (file)
index 0000000..dad4ff9
Binary files /dev/null and b/LayoutTests/editing/pasteboard/nested-blocks-with-text-field-expected.png differ
index e4d0b8f..0e18a97 100644 (file)
@@ -1 +1 @@
-00eb248dca688216f1341399284e4d66
\ No newline at end of file
+9697e5aa6aff2be0a6d9c1e2098d3c89
\ No newline at end of file
index b66d014..d2e1b29 100644 (file)
Binary files a/LayoutTests/editing/pasteboard/paste-table-003-expected.png and b/LayoutTests/editing/pasteboard/paste-table-003-expected.png differ
index d298b90..798fb3b 100644 (file)
@@ -4,7 +4,7 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 9 of #text > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 2 of TD > TR > TBODY > TABLE > DIV > BODY > HTML > #document to 2 of TD > TR > TBODY > TABLE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
@@ -21,18 +21,18 @@ layer at (0,0) size 800x600
             RenderTableCell {TD} at (29,2) size 26x20 [r=0 c=1 rs=1 cs=1]
               RenderText {#text} at (1,1) size 24x18
                 text run at (1,1) width 24: "two"
-      RenderBlock {DIV} at (0,24) size 784x60
-        RenderTable {TABLE} at (0,0) size 57x42
-          RenderTableSection {TBODY} at (0,0) size 57x42
-            RenderTableRow {TR} at (0,2) size 57x38
-              RenderTableCell {TD} at (2,11) size 25x20 [r=0 c=0 rs=1 cs=1]
+      RenderBlock {DIV} at (0,24) size 784x42
+        RenderTable {TABLE} at (0,0) size 57x24
+          RenderTableSection {TBODY} at (0,0) size 57x24
+            RenderTableRow {TR} at (0,2) size 57x20
+              RenderTableCell {TD} at (2,2) size 25x20 [r=0 c=0 rs=1 cs=1]
                 RenderText {#text} at (1,1) size 23x18
                   text run at (1,1) width 23: "one"
-              RenderTableCell {TD} at (29,2) size 26x38 [r=0 c=1 rs=1 cs=1]
+              RenderTableCell {TD} at (29,2) size 26x20 [r=0 c=1 rs=1 cs=1]
                 RenderText {#text} at (1,1) size 24x18
                   text run at (1,1) width 24: "two"
-                RenderBR {BR} at (25,15) size 0x0
-                RenderBR {BR} at (1,19) size 0x18
-        RenderBlock (anonymous) at (0,42) size 784x18
+        RenderBlock (anonymous) at (0,24) size 784x18
           RenderBR {BR} at (0,0) size 0x18
-caret: position 0 of child 2 {BR} of child 1 {TD} of child 0 {TR} of child 0 {TBODY} of child 0 {TABLE} of child 2 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+      RenderBlock {DIV} at (0,66) size 784x18
+        RenderBR {BR} at (0,0) size 0x18
+caret: position 0 of child 0 {BR} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index 4deab4b..928d6c0 100644 (file)
@@ -18,8 +18,7 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 2 of P > DIV > DIV > BODY > HTML > #document to 2 of P > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of P > P > DIV > DIV > BODY > HTML > #document to 0 of P > P > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 3 of P > DIV > DIV > BODY > HTML > #document to 3 of P > DIV > DIV > BODY > HTML > #document toDOMRange:range from 3 of P > DIV > DIV > BODY > HTML > #document to 3 of P > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
@@ -48,11 +47,10 @@ layer at (0,0) size 800x600
             RenderBlock {P} at (0,28) size 756x28
               RenderText {#text} at (0,0) size 130x28
                 text run at (0,0) width 130: "***TEST***"
-            RenderBlock {P} at (0,56) size 756x28
+            RenderBlock (anonymous) at (0,56) size 756x56
               RenderBR {BR} at (0,0) size 0x28
-            RenderBlock (anonymous) at (0,84) size 756x28
-              RenderText {#text} at (0,0) size 128x28
-                text run at (0,0) width 128: "Another line."
+              RenderText {#text} at (0,28) size 128x28
+                text run at (0,28) width 128: "Another line."
           RenderBlock {P} at (14,126) size 756x0
           RenderBlock (anonymous) at (14,126) size 756x28
             RenderText {#text} at (0,0) size 6x28
@@ -63,4 +61,4 @@ layer at (0,0) size 800x600
               text run at (0,0) width 6: " "
           RenderBlock {P} at (14,182) size 756x28
             RenderBR {BR} at (0,0) size 0x28
-caret: position 0 of child 0 {BR} of child 3 {P} of child 0 {P} of child 1 {DIV} of child 7 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 0 of child 3 {BR} of child 0 {P} of child 1 {DIV} of child 7 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index 27847d9..5770781 100644 (file)
@@ -20,6 +20,6 @@ layer at (0,0) size 800x600
           RenderText {#text} at (0,0) size 370x18
             text run at (0,0) width 370: "The test should add a single blank line after this paragraph."
           RenderBR {BR} at (370,14) size 0x0
-          RenderBR {BR} at (0,18) size 0x18
           RenderInline {SPAN} at (0,0) size 0x0
-caret: position 0 of child 2 {BR} of child 0 {DIV} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
+          RenderBR {BR} at (0,18) size 0x18
+caret: position 0 of child 3 {BR} of child 0 {DIV} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
index 55f4263..71774ba 100644 (file)
@@ -1,8 +1,7 @@
 EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
 EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document toDOMRange:range from 1 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
index 8c677d0..a3d2b01 100644 (file)
@@ -1 +1 @@
-2762a21712500c513288a4796e7c6f0d
\ No newline at end of file
+e93d8592f6229d3c0681c600617c9f4d
\ No newline at end of file
index af80ca4..8c5435e 100644 (file)
@@ -1 +1 @@
-675958ca1760e67d565768737724a7ed
\ No newline at end of file
+b6430b633335a2e5a40c5bae7d791546
\ No newline at end of file
index b09182d..3d34f8d 100644 (file)
@@ -1 +1 @@
-2a251ca75a4ee28206fbc9f203a921e3
\ No newline at end of file
+8a9b3e46242b36500276135ba1c29d62
\ No newline at end of file
index e4f7955..76df351 100644 (file)
@@ -17,7 +17,6 @@ NSForegroundColor,NSToolTip,NSFont,NSObliqueness
 NSToolTip,NSForegroundColor,NSFont
 0.5
 undefined
-undefined
 NSDeviceRGBColorSpace 1 0.5 1 0.5
 
 
index d30232d..671471e 100644 (file)
@@ -49,7 +49,6 @@ body { margin: 0; padding: 0 }
 
                        log(attrString.getAttributeValueAtIndex("NSObliqueness", 0));
                        log(attrString.getAttributeValueAtIndex("NSObliqueness", 3));
-                       log(attrString.getAttributeValueAtIndex("NSObliqueness", 10));
 
                        log(attrString.getAttributeValueAtIndex("NSForegroundColor", 1));
                        
diff --git a/LayoutTests/fast/forms/paste-into-textarea-expected.checksum b/LayoutTests/fast/forms/paste-into-textarea-expected.checksum
deleted file mode 100644 (file)
index a5599cf..0000000
+++ /dev/null
@@ -1 +0,0 @@
-2dd265383d1c568785c1c7ae84dfdaf6
\ No newline at end of file
diff --git a/LayoutTests/fast/forms/paste-into-textarea-expected.png b/LayoutTests/fast/forms/paste-into-textarea-expected.png
deleted file mode 100644 (file)
index 8029a83..0000000
Binary files a/LayoutTests/fast/forms/paste-into-textarea-expected.png and /dev/null differ
index 13d907d..3d24a5f 100644 (file)
@@ -1,26 +1,9 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 57 of #text > DIV to 57 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > DIV to 1 of #text > DIV toDOMRange:range from 57 of #text > DIV to 57 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  RenderView 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 {P} at (0,0) size 784x18
-        RenderText {#text} at (0,0) size 757x18
-          text run at (0,0) width 757: "This tests for a bug where text pasted into a textarea would appear one character before the position where it was pasted."
-      RenderBlock (anonymous) at (0,34) size 784x71
-        RenderTextField {TEXTAREA} at (2,2) size 163x67 [bgcolor=#FFFFFF] [border: (1px solid #000000)]
-        RenderText {#text} at (0,0) size 0x0
-layer at (11,45) size 161x65
-  RenderBlock {DIV} at (1,1) size 161x65
-    RenderText {#text} at (3,0) size 7x13
-      text run at (3,0) width 7: "x"
-    RenderText {#text} at (10,0) size 140x39
-      text run at (10,0) width 133: "(There should be one 'x' "
-      text run at (3,13) width 112: "before and after this "
-      text run at (3,26) width 55: "sentence.)"
-    RenderText {#text} at (58,26) size 7x13
-      text run at (58,26) width 7: "x"
-caret: position 57 of child 1 {#text} of child 0 {DIV} of child 2 {TEXTAREA} of child 0 {BODY} of child 0 {HTML} of document
+This tests for a bug where text pasted into a textarea would appear one character before the position where it was pasted.
+
+Hooray, test succeeded.
+
+
index 2483b7a..4f72001 100644 (file)
@@ -1,9 +1,13 @@
 <p>This tests for a bug where text pasted into a textarea would appear one character before the position where it was pasted.</p>
 <textarea rows=5 id="test">xx</textarea>
-
 <script>
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
 var e = document.getElementById("test");
 e.setSelectionRange(1, 1);
-
 document.execCommand("InsertHTML", false, "(There should be one 'x' before and after this sentence.)");
-</script>
\ No newline at end of file
+if (e.value == "x(There should be one 'x' before and after this sentence.)x")
+    document.write("<p>Hooray, test succeeded.</p>");
+else
+    document.write("<p>Test failed, value is '" + e.value + "'.</p>");
+</script>
diff --git a/LayoutTests/fast/forms/textarea-paste-newline-expected.txt b/LayoutTests/fast/forms/textarea-paste-newline-expected.txt
new file mode 100644 (file)
index 0000000..166df79
--- /dev/null
@@ -0,0 +1,16 @@
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldDeleteDOMRange:range from 0 of #text > DIV to 4 of #text > DIV
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV to 0 of DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldInsertText:abc
+ replacingDOMRange:range from 0 of DIV to 0 of DIV givenAction:WebViewInsertActionPasted
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 4 of #text > DIV to 4 of #text > DIV toDOMRange:range from 4 of #text > DIV to 4 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldInsertText:abc
+ replacingDOMRange:range from 0 of #text > DIV to 0 of #text > DIV givenAction:WebViewInsertActionPasted
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 4 of #text > DIV to 4 of #text > DIV toDOMRange:range from 4 of #text > DIV to 4 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+Hooray, the test was successful!
diff --git a/LayoutTests/fast/forms/textarea-paste-newline.html b/LayoutTests/fast/forms/textarea-paste-newline.html
new file mode 100644 (file)
index 0000000..cc8204e
--- /dev/null
@@ -0,0 +1,26 @@
+<script>
+function test()
+{
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+    var ta = document.getElementById("ta");
+    ta.value = "abc\n";
+    ta.focus();
+    ta.setSelectionRange(0, 4);
+    document.execCommand("cut");
+    document.execCommand("paste");
+    var result1 = ta.value;
+    ta.setSelectionRange(0, 0);
+    document.execCommand("paste");
+    var result2 = ta.value;
+
+    if (result1 == "abc\n" && result2 == "abc\nabc\n")
+        document.write("<p>Hooray, the test was successful!</p>");
+    else if (result1 == "")
+        document.write("<p>The test failed; doesn't work in release builds of Safari because paste is not allowed.</p>");
+    else
+        document.write("<p>The test failed, result 1 was '" + result1.replace("\n", "\\n") + "' and result 2 was '" + result2.replace("\n", "\\n") + "'.</p>");
+}
+</script>
+<body onload="test()">
+<p><textarea id="ta"></textarea></p>
index ee06033..d3e7463 100644 (file)
@@ -1,4 +1,5 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > DIV to 2 of #text > DIV toDOMRange:range from 1 of #text > DIV to 1 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 20 of #text > DIV to 20 of #text > DIV toDOMRange:range from 17 of #text > DIV to 17 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 Test Succeeded
+
index 9beb219..947c17d 100644 (file)
@@ -2,20 +2,24 @@
 <script>
 function test()
 {
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
     var ta = document.getElementById('ta')
+    var res = document.getElementById('res');
     ta.focus();
     // click
-    if (window.layoutTestController) {
-        layoutTestController.dumpAsText();
+    if (window.eventSender) {
         eventSender.mouseMoveTo(90, 20);
         eventSender.mouseDown();
         eventSender.mouseUp();
+        if (ta.selectionEnd == 17)
+            res.innerHTML = "Test Succeeded";
+        else
+            res.innerHTML = "Test Failed: caret is at " + ta.selectionEnd;
+    } else {
+        res.innerHTML = "Test can't run without event sender (part of DumpRenderTree). "
+            + "To test manually, click at the middle of the line marked 9 and check that the caret appears after the 9.";
     }
-    var res = document.getElementById('res');
-    if (ta.selectionEnd == 17)
-        res.innerHTML = "Test Succeeded";
-    else
-        res.innerHTML = "Test Failed: caret is at " + ta.selectionEnd;
 }
 </script>
 </head>
@@ -30,6 +34,6 @@ function test()
 7
 8
 9
-10
-</textarea>
-<div id="res"></div>
\ No newline at end of file
+10</textarea>
+<div id="res"></div>
+</body>
index 6098b26..6c97c5b 100644 (file)
@@ -1 +1 @@
-7f38cf2e654f194ce1a95e256537fbfe
\ No newline at end of file
+bb1e86fd2232a0b2c6bda501f303b1de
\ No newline at end of file
index 74f36b5..7a7d8c3 100644 (file)
Binary files a/LayoutTests/fast/forms/textarea-scrolled-type-expected.png and b/LayoutTests/fast/forms/textarea-scrolled-type-expected.png differ
index b382958..6345c5a 100644 (file)
@@ -1,18 +1,18 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > DIV to 2 of #text > DIV toDOMRange:range from 3 of #text > DIV to 3 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 44 of #text > DIV to 44 of #text > DIV toDOMRange:range from 45 of #text > DIV to 45 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 3 of #text > DIV to 3 of #text > DIV toDOMRange:range from 4 of #text > DIV to 4 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 45 of #text > DIV to 45 of #text > DIV toDOMRange:range from 46 of #text > DIV to 46 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 4 of #text > DIV to 4 of #text > DIV toDOMRange:range from 5 of #text > DIV to 5 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 46 of #text > DIV to 46 of #text > DIV toDOMRange:range from 47 of #text > DIV to 47 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 5 of #text > DIV to 5 of #text > DIV toDOMRange:range from 6 of #text > DIV to 6 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 47 of #text > DIV to 47 of #text > DIV toDOMRange:range from 48 of #text > DIV to 48 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 6 of #text > DIV to 6 of #text > DIV toDOMRange:range from 7 of #text > DIV to 7 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 48 of #text > DIV to 48 of #text > DIV toDOMRange:range from 49 of #text > DIV to 49 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
@@ -29,66 +29,48 @@ layer at (0,0) size 800x600
           text run at (167,101) width 4: " "
         RenderBR {BR} at (171,115) size 0x0
       RenderBlock {DIV} at (0,119) size 784x0
-layer at (11,29) size 161x91 clip at (11,29) size 146x91 scrollY 169 scrollHeight 260
+layer at (11,29) size 161x91 clip at (11,29) size 146x91 scrollY 182 scrollHeight 273
   RenderBlock {DIV} at (1,1) size 161x91
-    RenderText {#text} at (3,0) size 7x13
+    RenderText {#text} at (3,0) size 41x260
       text run at (3,0) width 7: "1"
-    RenderBR {BR} at (10,11) size 0x0
-    RenderText {#text} at (3,13) size 7x13
+      text run at (10,0) width 0: " "
       text run at (3,13) width 7: "2"
-    RenderBR {BR} at (10,24) size 0x0
-    RenderText {#text} at (3,26) size 7x13
+      text run at (10,13) width 0: " "
       text run at (3,26) width 7: "3"
-    RenderBR {BR} at (10,37) size 0x0
-    RenderText {#text} at (3,39) size 7x13
+      text run at (10,26) width 0: " "
       text run at (3,39) width 7: "4"
-    RenderBR {BR} at (10,50) size 0x0
-    RenderText {#text} at (3,52) size 7x13
+      text run at (10,39) width 0: " "
       text run at (3,52) width 7: "5"
-    RenderBR {BR} at (10,63) size 0x0
-    RenderText {#text} at (3,65) size 7x13
+      text run at (10,52) width 0: " "
       text run at (3,65) width 7: "6"
-    RenderBR {BR} at (10,76) size 0x0
-    RenderText {#text} at (3,78) size 7x13
+      text run at (10,65) width 0: " "
       text run at (3,78) width 7: "7"
-    RenderBR {BR} at (10,89) size 0x0
-    RenderText {#text} at (3,91) size 7x13
+      text run at (10,78) width 0: " "
       text run at (3,91) width 7: "8"
-    RenderBR {BR} at (10,102) size 0x0
-    RenderText {#text} at (3,104) size 7x13
+      text run at (10,91) width 0: " "
       text run at (3,104) width 7: "9"
-    RenderBR {BR} at (10,115) size 0x0
-    RenderText {#text} at (3,117) size 14x13
+      text run at (10,104) width 0: " "
       text run at (3,117) width 14: "10"
-    RenderBR {BR} at (17,128) size 0x0
-    RenderText {#text} at (3,130) size 14x13
+      text run at (17,117) width 0: " "
       text run at (3,130) width 14: "11"
-    RenderBR {BR} at (17,141) size 0x0
-    RenderText {#text} at (3,143) size 14x13
+      text run at (17,130) width 0: " "
       text run at (3,143) width 14: "12"
-    RenderBR {BR} at (17,154) size 0x0
-    RenderText {#text} at (3,156) size 14x13
+      text run at (17,143) width 0: " "
       text run at (3,156) width 14: "13"
-    RenderBR {BR} at (17,167) size 0x0
-    RenderText {#text} at (3,169) size 14x13
+      text run at (17,156) width 0: " "
       text run at (3,169) width 14: "14"
-    RenderBR {BR} at (17,180) size 0x0
-    RenderText {#text} at (3,182) size 14x13
+      text run at (17,169) width 0: " "
       text run at (3,182) width 14: "15"
-    RenderBR {BR} at (17,193) size 0x0
-    RenderText {#text} at (3,195) size 14x13
+      text run at (17,182) width 0: " "
       text run at (3,195) width 14: "16"
-    RenderBR {BR} at (17,206) size 0x0
-    RenderText {#text} at (3,208) size 14x13
+      text run at (17,195) width 0: " "
       text run at (3,208) width 14: "17"
-    RenderBR {BR} at (17,219) size 0x0
-    RenderText {#text} at (3,221) size 41x13
+      text run at (17,208) width 0: " "
       text run at (3,221) width 41: "18 Pass"
-    RenderBR {BR} at (44,232) size 0x0
-    RenderText {#text} at (3,234) size 14x13
+      text run at (44,221) width 0: " "
       text run at (3,234) width 14: "19"
-    RenderBR {BR} at (17,245) size 0x0
-    RenderText {#text} at (3,247) size 14x13
+      text run at (17,234) width 0: " "
       text run at (3,247) width 14: "20"
-    RenderBR {BR} at (17,258) size 0x0
-caret: position 7 of child 34 {#text} of child 0 {DIV} of child 3 {TEXTAREA} of child 1 {BODY} of child 0 {HTML} of document
+      text run at (17,247) width 0: " "
+    RenderBR {BR} at (3,260) size 0x13
+caret: position 49 of child 0 {#text} of child 0 {DIV} of child 3 {TEXTAREA} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/fast/forms/textarea-type-spaces-expected.txt b/LayoutTests/fast/forms/textarea-type-spaces-expected.txt
new file mode 100644 (file)
index 0000000..e6d5993
--- /dev/null
@@ -0,0 +1,20 @@
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldInsertText:  replacingDOMRange:range from 0 of DIV to 0 of DIV givenAction:WebViewInsertActionTyped
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV to 0 of DIV toDOMRange:range from 1 of #text > DIV to 1 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldInsertText:  replacingDOMRange:range from 1 of #text > DIV to 1 of #text > DIV givenAction:WebViewInsertActionTyped
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > DIV to 1 of #text > DIV toDOMRange:range from 2 of #text > DIV to 2 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldInsertText:  replacingDOMRange:range from 2 of #text > DIV to 2 of #text > DIV givenAction:WebViewInsertActionTyped
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > DIV to 2 of #text > DIV toDOMRange:range from 3 of #text > DIV to 3 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldInsertText:  replacingDOMRange:range from 3 of #text > DIV to 3 of #text > DIV givenAction:WebViewInsertActionTyped
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 3 of #text > DIV to 3 of #text > DIV toDOMRange:range from 4 of #text > DIV to 4 of #text > DIV affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+Hooray, test worked!
+
+
diff --git a/LayoutTests/fast/forms/textarea-type-spaces.html b/LayoutTests/fast/forms/textarea-type-spaces.html
new file mode 100644 (file)
index 0000000..91db322
--- /dev/null
@@ -0,0 +1,20 @@
+<p><textarea id="ta"></textarea></p>
+<script>
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+var ta = document.getElementById("ta");
+ta.focus();
+if (window.eventSender) {
+    eventSender.keyDown(' ', new Array());
+    eventSender.keyDown(' ', new Array());
+    eventSender.keyDown(' ', new Array());
+    eventSender.keyDown(' ', new Array());
+    var result = ta.value;
+    if (result == "    ")
+        document.write("<p>Hooray, test worked!</p>");
+    else
+        document.write("<pre>Test failed, result was '" + result + "'.</pre>");
+} else {
+    document.write("<p>Test can't run without event sender, part of DumpRenderTree.</p>");
+}
+</script>
index bde451f..811e1c4 100644 (file)
@@ -1,3 +1,136 @@
+2006-07-24  Darin Adler  <darin@apple.com>
+
+        Reviewed by Adele and Justin.
+
+        - fix <rdar://problem/4613616> REGRESSION: some spaces typed in <textarea> are posted as non-breaking spaces (9630)
+          http://bugzilla.opendarwin.org/show_bug.cgi?id=9630
+        - also fixes http://bugzilla.opendarwin.org/show_bug.cgi?id=9939
+          REGRESSION: Pasting text into native text area with newline at end does not preserve newline
+        - removed some uses of DeprecatedPtrList in the markup code
+
+        Test: fast/forms/textarea-type-spaces.html
+        Test: fast/forms/textarea-paste-newline.html
+
+        * bindings/objc/DOMHTML.mm: (-[DOMHTMLDocument createDocumentFragmentWithText:]):
+        Updated call to pass a range -- in this case it is the range of the entire document,
+        so this will not handle the whitespace properly.
+
+        * bridge/mac/WebCoreFrameBridge.h: Added range context parameter to the
+        documentFragmentWithText: method, so we can handle whitespace properly.
+        * bridge/mac/WebCoreFrameBridge.mm:
+        (-[WebCoreFrameBridge nodesFromList:]): Changed from DeprecatedPtrList to Vector.
+        (-[WebCoreFrameBridge markupStringFromNode:nodes:]): Ditto.
+        (-[WebCoreFrameBridge markupStringFromRange:nodes:]): Ditto.
+        (-[WebCoreFrameBridge documentFragmentWithText:inContext:]): Added range context
+        parameter -- pass it on to createFragmentFromText.
+        (-[WebCoreFrameBridge documentFragmentWithNodesAsParagraphs:]): Changed from
+        DeprecatedPtrList to Vector.
+        (-[WebCoreFrameBridge replaceSelectionWithText:selectReplacement:smartReplace:]):
+        Pass the range of the current selection as context when creating the fragment.
+
+        * dom/Position.cpp: (WebCore::Position::inRenderedText): Replace range check with
+        a call to the new containsCaretOffset function -- helps make the caret work right when
+        it is past the end of the last line in a textarea.
+
+        * editing/CompositeEditCommand.cpp:
+        (WebCore::CompositeEditCommand::rebalanceWhitespaceAt): Don't do anything if the
+        style does not call for collapsing whitespace.
+        (WebCore::CompositeEditCommand::rebalanceWhitespace): Call replaceWhitespaceAt
+        to share code, including the new logic mentioned above.
+
+        * editing/InsertLineBreakCommand.cpp: (WebCore::InsertLineBreakCommand::doApply):
+        Use a text node instead of a break element when inserting and the style is preserveNewline.
+
+        * editing/JSEditor.cpp: (WebCore::execRemoveFormat): Pass the selection range
+        to createFragmentFromText.
+
+        * editing/RebalanceWhitespaceCommand.cpp: (WebCore::RebalanceWhitespaceCommand::doApply):
+        Assert that we're in a style that collapses whitespace. It's the caller's responsibility
+        not to call otherwise.
+
+        * editing/ReplaceSelectionCommand.h: Removed unused destructor, type, isSingleTextNode,
+        isTreeFragment, m_type, and added a context parameter to inertFragmentForTestRendering.
+        Also changed the constructor to take a selection rather than a pointer to the root
+        editable element, replaced removeEndBRIfNeeded with shouldRemoveEndBR and removed an
+        unused parameter from shouldMergeEnd.
+        * editing/ReplaceSelectionCommand.cpp:
+        (WebCore::ReplacementFragment::ReplacementFragment): Removed code to set up m_type.
+        Compute root editable element from passed-in selection. Used the start of the selection
+        as a base node for style purposes for the test rendering. Removed the special case
+        "single text node" alternative to createFragmentFromText in the plain text case, since
+        createFragmentFromText now handles that correctly.
+        (WebCore::ReplacementFragment::insertFragmentForTestRendering): Copy the whitespace
+        property from the source location when creating a temporary element for test rendering.
+        (WebCore::ReplacementFragment::shouldMergeEnd): Removed unneeded boolean
+        parameter fragmentHadInterchangeNewlineAtEnd, which is always false.
+        (WebCore::ReplaceSelectionCommand::doApply): Update for ReplacementFragment changes,
+        change code to not remove end BR when it can be re-used instead, don't call the
+        paragraph separator insertion when the position is at the start of a paragraph already,
+        removed redundant computation of identical "next" value, removed unneeded boolean
+        parameter to shouldMergeEnd, add case for merging when all we need to do is to delete
+        a newline character, removed unneeded code to set insertionPos after all code that uses
+        it, and  use spaces instead of non-breaking spaces when doing smart paste if the
+        context is one where we do not collapse white space.
+        (WebCore::ReplaceSelectionCommand::shouldRemoveEndBR): Renamed and changed to return
+        a boolean instead of doing the removal.
+
+        * editing/markup.h: Use Vector instead of DeprecatedPtrList. Change the
+        createFragmentFromText function to take a range for context instead of a document.
+        * editing/markup.cpp:
+        (WebCore::markup): Use Vector instead of DeprecatedPtrList.
+        (WebCore::createMarkup): Ditto.
+        (WebCore::createParagraphContentsFromString): Remove unneeded document parameter
+        and changed a couple places to use isEmpty instead of comparing with "".
+        (WebCore::createFragmentFromText): Given the new context parameter, if the context
+        is one that preserves newlines, then use "\n" instead of <br> elements.
+        (WebCore::createFragmentFromNodes): Use Vector instead of DeprecatedPtrList.
+
+        * html/HTMLElement.cpp: (WebCore::HTMLElement::setInnerText): Do not use <br>
+        elements if the context of this node is one where we preserve newlines.
+
+        * rendering/InlineTextBox.h:
+        * rendering/InlineTextBox.cpp: (WebCore::InlineTextBox::containsCaretOffset):
+        Added. Implements the appropriate rule for determining if a caret position is
+        in this line or not. Returns true for both one line and the next in cases where
+        affinity must be considered to determine which line the caret is on.
+
+        * rendering/RenderText.h: Make atLineWrap no longer be a member function.
+        * rendering/RenderText.cpp:
+        (WebCore::atLineWrap): Remove special rule about preserveNewline and isLineBreak,
+        which will no longer apply due to the new containsCaretOffset function logic.
+        (WebCore::RenderText::caretRect): Use containsCaretOffset.
+        (WebCore::RenderText::inlineBox): Ditto.
+
+        * rendering/RenderTextControl.cpp:
+        (WebCore::RenderTextControl::updateFromElement): Make a placeholder <br> element
+        after calling setInnerText so that the last newline in the string has the effect
+        we expect outside the HTML world (an additional line).
+        (WebCore::RenderTextControl::setSelectionRange): Set granularity of the selection
+        too. The layout tests caught this problem, which needs a better solution long term.
+        (WebCore::RenderTextControl::text): Call textContent with the parameter false
+        so it will not include newlines for <br> elements. Now the only <br> element
+        that will ever be in the shadow DOM tree is the one to prevent collapsing, and
+        that one should not show up in the text value.
+
+        * rendering/bidi.cpp: (WebCore::RenderBlock::findNextLineBreak): Took a rule
+        that specifically called out the pre whitespace mode and made it work for all
+        the modes that preserve newlines. This makes sure we get a last line box for
+        text after the last "\n" even in cases where there is no <br> afterward.
+
+        * editing/DeleteSelectionCommand.cpp:
+        (WebCore::DeleteSelectionCommand::fixupWhitespace):
+        * editing/InsertParagraphSeparatorCommand.cpp:
+        (WebCore::InsertParagraphSeparatorCommand::doApply):
+        Added assertions to make sure we don't do anything when we're not collapsing
+        whitespace.
+
+        * html/HTMLTextAreaElement.cpp: (WebCore::HTMLTextAreaElement::setDefaultValue):
+        Changed to use Vector instead of DeprecatedPtrList.
+
+        * editing/HTMLInterchange.cpp: Removed obsolete comment.
+
+        * loader/Cache.h: Removed a stray include.
+
 2006-07-24  Adele Peterson  <adele@apple.com>
 
         Reviewed by Justin.
index a06352b..57bd2c2 100644 (file)
 #import "config.h"
 #import "DOMHTML.h"
 
+#import "DOMExtensions.h"
 #import "DOMHTMLInternal.h"
 #import "DOMInternal.h"
 #import "DOMPrivate.h"
-#import "DOMExtensions.h"
 #import "DocumentFragment.h"
 #import "FoundationExtras.h"
+#import "FrameView.h"
 #import "HTMLAppletElement.h"
 #import "HTMLAreaElement.h"
+#import "HTMLBRElement.h"
 #import "HTMLBaseElement.h"
 #import "HTMLBaseFontElement.h"
 #import "HTMLBodyElement.h"
-#import "HTMLBRElement.h"
 #import "HTMLButtonElement.h"
+#import "HTMLDListElement.h"
 #import "HTMLDirectoryElement.h"
 #import "HTMLDivElement.h"
-#import "HTMLDListElement.h"
 #import "HTMLDocument.h"
 #import "HTMLEmbedElement.h"
 #import "HTMLFieldSetElement.h"
 #import "HTMLFormCollection.h"
 #import "HTMLFormElement.h"
 #import "HTMLFrameSetElement.h"
+#import "HTMLHRElement.h"
 #import "HTMLHeadElement.h"
 #import "HTMLHeadingElement.h"
-#import "HTMLHRElement.h"
 #import "HTMLHtmlElement.h"
 #import "HTMLIFrameElement.h"
 #import "HTMLImageElement.h"
 #import "HTMLIsIndexElement.h"
+#import "HTMLLIElement.h"
 #import "HTMLLabelElement.h"
 #import "HTMLLegendElement.h"
-#import "HTMLLIElement.h"
 #import "HTMLLinkElement.h"
 #import "HTMLMapElement.h"
 #import "HTMLMenuElement.h"
 #import "HTMLMetaElement.h"
 #import "HTMLNames.h"
-#import "HTMLObjectElement.h"
 #import "HTMLOListElement.h"
+#import "HTMLObjectElement.h"
 #import "HTMLOptGroupElement.h"
 #import "HTMLOptionElement.h"
 #import "HTMLOptionsCollection.h"
-#import "HTMLParamElement.h"
 #import "HTMLParagraphElement.h"
+#import "HTMLParamElement.h"
 #import "HTMLPreElement.h"
 #import "HTMLScriptElement.h"
 #import "HTMLSelectElement.h"
 #import "HTMLStyleElement.h"
-#import "HTMLTableElement.h"
 #import "HTMLTableCaptionElement.h"
 #import "HTMLTableCellElement.h"
 #import "HTMLTableColElement.h"
+#import "HTMLTableElement.h"
 #import "HTMLTableRowElement.h"
 #import "HTMLTableSectionElement.h"
 #import "HTMLTextAreaElement.h"
 #import "HTMLTitleElement.h"
 #import "HTMLUListElement.h"
+#import "KURL.h"
 #import "NameNodeList.h"
-#import "markup.h"
+#import "Range.h"
 #import "RenderTextControl.h"
-#import "FrameView.h"
 #import "csshelper.h"
-#import "KURL.h"
+#import "markup.h"
 
 using namespace WebCore;
 using namespace HTMLNames;
@@ -605,7 +606,8 @@ using namespace HTMLNames;
 
 - (DOMDocumentFragment *)createDocumentFragmentWithText:(NSString *)text
 {
-    return [DOMDocumentFragment _documentFragmentWith:createFragmentFromText([self _document], DeprecatedString::fromNSString(text)).get()];
+    // FIXME: Since this is not a contextual fragment, it won't handle whitespace properly.
+    return [DOMDocumentFragment _documentFragmentWith:createFragmentFromText([self _document]->createRange().get(), text).get()];
 }
 
 @end
index 399e46c..6d56ec9 100644 (file)
@@ -418,7 +418,7 @@ typedef enum {
 - (NSRange)convertDOMRangeToNSRange:(DOMRange *)range;
 
 - (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString;
-- (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text;
+- (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text inContext:(DOMRange *)context;
 - (DOMDocumentFragment *)documentFragmentWithNodesAsParagraphs:(NSArray *)nodes;
 
 - (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle;
index 200c576..12bd2b4 100644 (file)
@@ -771,19 +771,19 @@ static inline WebCoreFrameBridge *bridge(Frame *frame)
     return m_frame->documentTypeString() + markupString;
 }
 
-- (NSArray *)nodesFromList:(DeprecatedPtrList<Node> *)nodeList
+- (NSArray *)nodesFromList:(Vector<Node*> *)nodesVector
 {
-    NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:nodeList->count()];
-    for (DeprecatedPtrListIterator<Node> i(*nodeList); i.current(); ++i)
-        [nodes addObject:[DOMNode _nodeWith:i.current()]];
-
+    size_t size = nodesVector->size();
+    NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size];
+    for (size_t i = 0; i < size; ++i)
+        [nodes addObject:[DOMNode _nodeWith:(*nodesVector)[i]]];
     return nodes;
 }
 
 - (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes
 {
     // FIXME: This is never "for interchange". Is that right? See the next method.
-    DeprecatedPtrList<Node> nodeList;
+    Vector<Node*> nodeList;
     NSString *markupString = createMarkup([node _node], IncludeNode, nodes ? &nodeList : 0).getNSString();
     if (nodes)
         *nodes = [self nodesFromList:&nodeList];
@@ -794,7 +794,7 @@ static inline WebCoreFrameBridge *bridge(Frame *frame)
 - (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
 {
     // FIXME: This is always "for interchange". Is that right? See the previous method.
-    DeprecatedPtrList<Node> nodeList;
+    Vector<Node*> nodeList;
     NSString *markupString = createMarkup([range _range], nodes ? &nodeList : 0, AnnotateForInterchange).getNSString();
     if (nodes)
         *nodes = [self nodesFromList:&nodeList];
@@ -1943,28 +1943,23 @@ static HTMLFormElement *formElementFromDOMElement(DOMElement *element)
         DeprecatedString::fromNSString(markupString), DeprecatedString::fromNSString(baseURLString)).get()];
 }
 
-- (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text
+- (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text inContext:(DOMRange *)context
 {
-    if (!m_frame || !m_frame->document() || !text)
-        return 0;
-    
-    return [DOMDocumentFragment _documentFragmentWith:createFragmentFromText(m_frame->document(), DeprecatedString::fromNSString(text)).get()];
+    return [DOMDocumentFragment _documentFragmentWith:createFragmentFromText([context _range], DeprecatedString::fromNSString(text)).get()];
 }
 
 - (DOMDocumentFragment *)documentFragmentWithNodesAsParagraphs:(NSArray *)nodes
 {
-    NSEnumerator *nodeEnum = [nodes objectEnumerator];
-    DOMNode *node;
-    DeprecatedPtrList<Node> nodeList;
-    
     if (!m_frame || !m_frame->document())
         return 0;
     
-    while ((node = [nodeEnum nextObject])) {
-        nodeList.append([node _node]);
-    }
+    NSEnumerator *nodeEnum = [nodes objectEnumerator];
+    Vector<Node*> nodesVector;
+    DOMNode *node;
+    while ((node = [nodeEnum nextObject]))
+        nodesVector.append([node _node]);
     
-    return [DOMDocumentFragment _documentFragmentWith:createFragmentFromNodeList(m_frame->document(), nodeList).get()];
+    return [DOMDocumentFragment _documentFragmentWith:createFragmentFromNodes(m_frame->document(), nodesVector).get()];
 }
 
 - (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle
@@ -1991,7 +1986,9 @@ static HTMLFormElement *formElementFromDOMElement(DOMElement *element)
 
 - (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
 {
-    [self replaceSelectionWithFragment:[self documentFragmentWithText:text] selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
+    [self replaceSelectionWithFragment:[self documentFragmentWithText:text
+        inContext:[DOMRange _rangeWith:m_frame->selection().toRange().get()]]
+        selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES];
 }
 
 - (bool)canIncreaseSelectionListLevel
index 8fd549e..0e9ac78 100644 (file)
@@ -482,7 +482,7 @@ bool Position::inRenderedText() const
             // not rendered. Return false.
             return false;
         }
-        if (offset() >= box->m_start && offset() <= box->m_start + box->m_len)
+        if (box->containsCaretOffset(offset()))
             // Return false for offsets inside composed characters.
             return offset() == 0 || offset() == textRenderer->nextOffset(textRenderer->previousOffset(offset()));
     }
index 8da332b..a357cdf 100644 (file)
@@ -372,8 +372,16 @@ void CompositeEditCommand::setNodeAttribute(Element *element, const QualifiedNam
     applyCommandToComposite(cmd);
 }
 
-void CompositeEditCommand::rebalanceWhitespaceAt(const Position &position)
+void CompositeEditCommand::rebalanceWhitespaceAt(const Positionposition)
 {
+    Node* textNode = position.node();
+    if (!textNode || !textNode->isTextNode())
+        return;
+    if (static_cast<Text*>(textNode)->length() == 0)
+        return;
+    RenderObject* renderer = textNode->renderer();
+    if (renderer && !renderer->style()->collapseWhiteSpace())
+        return;
     EditCommandPtr cmd(new RebalanceWhitespaceCommand(document(), position));
     applyCommandToComposite(cmd);    
 }
@@ -382,12 +390,9 @@ void CompositeEditCommand::rebalanceWhitespace()
 {
     Selection selection = endingSelection();
     if (selection.isCaretOrRange()) {
-        EditCommandPtr startCmd(new RebalanceWhitespaceCommand(document(), endingSelection().start()));
-        applyCommandToComposite(startCmd);
-        if (selection.isRange()) {
-            EditCommandPtr endCmd(new RebalanceWhitespaceCommand(document(), endingSelection().end()));
-            applyCommandToComposite(endCmd);
-        }
+        rebalanceWhitespaceAt(endingSelection().start());
+        if (selection.isRange())
+            rebalanceWhitespaceAt(endingSelection().end());
     }
 }
 
index 9000507..6eec0a6 100644 (file)
@@ -395,11 +395,13 @@ void DeleteSelectionCommand::fixupWhitespace()
     updateLayout();
     // FIXME: isRenderedCharacter should be removed, and we should use VisiblePosition::characterAfter and VisiblePosition::characterBefore
     if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharacter()) {
-        Text *textNode = static_cast<Text *>(m_leadingWhitespace.node());
+        Text* textNode = static_cast<Text*>(m_leadingWhitespace.node());
+        ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
         replaceTextInNode(textNode, m_leadingWhitespace.offset(), 1, nonBreakingSpaceString());
     }
     if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedCharacter()) {
-        Text *textNode = static_cast<Text *>(m_trailingWhitespace.node());
+        Text* textNode = static_cast<Text*>(m_trailingWhitespace.node());
+        ASSERT(!textNode->renderer() ||textNode->renderer()->style()->collapseWhiteSpace());
         replaceTextInNode(textNode, m_trailingWhitespace.offset(), 1, nonBreakingSpaceString());
     }
 }
index 9b8af1b..ea0ecf7 100644 (file)
@@ -48,7 +48,6 @@ DeprecatedString convertedSpaceString()
 
 } // end anonymous namespace
 
-// FIXME: convertHTMLTextToInterchangeFormat should probably be in the khtml namespace.
 // FIXME: Can't really do this work without taking whitespace mode into account.
 // This means that eventually this function needs to be eliminated or at least have
 // its parameters changed because it can't do its work on the string without knowing
index 584359d..a53422c 100644 (file)
@@ -85,41 +85,53 @@ void InsertLineBreakCommand::doApply()
     if (selection.isNone())
         return;
 
-    RefPtr<Element> breakNode = createBreakElement(document());
-    Node* nodeToInsert = breakNode.get();
-    
     Position pos(selection.start().upstream());
 
     pos = positionAvoidingSpecialElementBoundary(pos);
 
-    if (isTabSpanTextNode(pos.node())) {
-        insertNodeAtTabSpanPosition(nodeToInsert, pos);
+    Node* styleNode = pos.node();
+    bool isTabSpan = isTabSpanTextNode(styleNode);
+    if (isTabSpan)
+        styleNode = styleNode->parentNode()->parentNode();
+    RenderObject* styleRenderer = styleNode->renderer();
+    bool useBreakElement = !styleRenderer || !styleRenderer->style()->preserveNewline();
+
+    RefPtr<Node> nodeToInsert;
+    if (useBreakElement)
+        nodeToInsert = createBreakElement(document());
+    else
+        nodeToInsert = document()->createTextNode("\n");
+        // FIXME: Need to merge text nodes when inserting just after or before text.
+    
+    if (isTabSpan) {
+        insertNodeAtTabSpanPosition(nodeToInsert.get(), pos);
         setEndingSelection(Position(nodeToInsert->traverseNextNode(), 0), DOWNSTREAM);
     } else if (isEndOfBlock(VisiblePosition(pos, selection.affinity()))) {
-        
         Node* block = pos.node()->enclosingBlockFlowElement();
         
-        // Insert an extra br if the inserted one will collapsed because of quirks mode.
-        if (!document()->inStrictMode() && !(pos.downstream().node()->hasTagName(brTag) && pos.downstream().offset() == 0)) {
-            insertNodeAt(nodeToInsert, pos.node(), pos.offset());
-            insertNodeAfter(createBreakElement(document()).get(), nodeToInsert);
-        } else
-            insertNodeAt(nodeToInsert, pos.node(), pos.offset());
+        // Insert an extra break element so that there will be a blank line after the last
+        // inserted line break. In HTML, a line break at the end of a block ends the last
+        // line in the block, while in editable text, a line break at the end of block
+        // creates a last blank line. We need an extra break element to get HTML to act
+        // the way editable text would.
+        bool haveBreak = pos.downstream().node()->hasTagName(brTag) && pos.downstream().offset() == 0;
+        insertNodeAt(nodeToInsert.get(), pos.node(), pos.offset());
+        if (!haveBreak)
+            insertNodeAfter(createBreakElement(document()).get(), nodeToInsert.get());
             
         setEndingSelection(Position(block, maxDeepOffset(block)), DOWNSTREAM);
-    }
-    else if (pos.offset() <= pos.node()->caretMinOffset()) {
+    } else if (pos.offset() <= pos.node()->caretMinOffset()) {
         LOG(Editing, "input newline case 2");
         // Insert node before downstream position, and place caret there as well. 
         Position endingPosition = pos.downstream();
-        insertNodeBeforePosition(nodeToInsert, endingPosition);
+        insertNodeBeforePosition(nodeToInsert.get(), endingPosition);
         setEndingSelection(endingPosition, DOWNSTREAM);
     } else if (pos.offset() >= pos.node()->caretMaxOffset()) {
         LOG(Editing, "input newline case 3");
         // Insert BR after this node. Place caret in the position that is downstream
         // of the current position, reckoned before inserting the BR in between.
         Position endingPosition = pos.downstream();
-        insertNodeAfterPosition(nodeToInsert, pos);
+        insertNodeAfterPosition(nodeToInsert.get(), pos);
         setEndingSelection(endingPosition, DOWNSTREAM);
     } else {
         // Split a text node
@@ -132,7 +144,7 @@ void InsertLineBreakCommand::doApply()
         RefPtr<Text> textBeforeNode = document()->createTextNode(textNode->substringData(0, selection.start().offset(), ec));
         deleteTextFromNode(textNode, 0, pos.offset());
         insertNodeBefore(textBeforeNode.get(), textNode);
-        insertNodeBefore(nodeToInsert, textNode);
+        insertNodeBefore(nodeToInsert.get(), textNode);
         Position endingPosition = Position(textNode, 0);
         
         // Handle whitespace that occurs after the split
@@ -140,6 +152,7 @@ void InsertLineBreakCommand::doApply()
         if (!endingPosition.isRenderedCharacter()) {
             // Clear out all whitespace and insert one non-breaking space
             deleteInsignificantTextDownstream(endingPosition);
+            ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
             insertTextIntoNode(textNode, 0, nonBreakingSpaceString());
         }
         
@@ -154,7 +167,8 @@ void InsertLineBreakCommand::doApply()
     
     if (typingStyle && typingStyle->length() > 0) {
         Selection selectionBeforeStyle = endingSelection();
-        applyStyle(typingStyle, Position(nodeToInsert, 0), Position(nodeToInsert, maxDeepOffset(nodeToInsert)));
+        applyStyle(typingStyle, Position(nodeToInsert.get(), 0),
+            Position(nodeToInsert.get(), maxDeepOffset(nodeToInsert.get())));
         setEndingSelection(selectionBeforeStyle);
     }
 
index 1a63223..faf498e 100644 (file)
@@ -213,7 +213,8 @@ void InsertParagraphSeparatorCommand::doApply()
     // FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions
     // after the preserved newline, causing the newline to be turned into a nbsp.
     if (leadingWhitespace.isNotNull()) {
-        Text *textNode = static_cast<Text *>(leadingWhitespace.node());
+        Text* textNode = static_cast<Text*>(leadingWhitespace.node());
+        ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
         replaceTextInNode(textNode, leadingWhitespace.offset(), 1, nonBreakingSpaceString());
     }
     
@@ -284,9 +285,11 @@ void InsertParagraphSeparatorCommand::doApply()
         pos = Position(startNode, 0);
         if (!pos.isRenderedCharacter()) {
             // Clear out all whitespace and insert one non-breaking space
-            ASSERT(startNode && startNode->isTextNode());
+            ASSERT(startNode);
+            ASSERT(startNode->isTextNode());
+            ASSERT(!startNode->renderer() || startNode->renderer()->style()->collapseWhiteSpace());
             deleteInsignificantTextDownstream(pos);
-            insertTextIntoNode(static_cast<Text *>(startNode), 0, nonBreakingSpaceString());
+            insertTextIntoNode(static_cast<Text*>(startNode), 0, nonBreakingSpaceString());
         }
     }
 
index 2243b57..71af76e 100644 (file)
@@ -415,7 +415,7 @@ bool execRedo(Frame *frame, bool userInterface, const String &value)
 
 bool execRemoveFormat(Frame* frame, bool userInterface, const String& value)
 {
-    RefPtr<DocumentFragment> fragment = createFragmentFromText(frame->document(), frame->selection().toString().deprecatedString());
+    RefPtr<DocumentFragment> fragment = createFragmentFromText(frame->selection().toRange().get(), frame->selection().toString());
     EditCommandPtr(new ReplaceSelectionCommand(frame->document(), fragment.get(), false, false, false, false, EditActionUnspecified)).apply();
     return true;
 }
index ffa76f2..2f76465 100644 (file)
@@ -49,12 +49,12 @@ void RebalanceWhitespaceCommand::doApply()
 {
     if (m_position.isNull() || !m_position.node()->isTextNode())
         return;
-        
-    Text *textNode = static_cast<Text *>(m_position.node());
+
+    Text* textNode = static_cast<Text*>(m_position.node());
     String text = textNode->data();
-    if (text.length() == 0)
-        return;
-    
+    ASSERT(!text.isEmpty());
+    ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
+
     int offset = m_position.offset();
     // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
     if (!isWhitespace(text[offset])) {
@@ -102,4 +102,3 @@ bool RebalanceWhitespaceCommand::preservesTypingStyle() const
 }
 
 } // namespace WebCore
-
index 0be3878..8c90dc9 100644 (file)
@@ -48,7 +48,7 @@ namespace WebCore {
 
 using namespace HTMLNames;
 
-ReplacementFragment::ReplacementFragment(Document *document, DocumentFragment *fragment, bool matchStyle, Element* editableRoot)
+ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* fragment, bool matchStyle, const Selection& selection)
     : m_document(document),
       m_fragment(fragment),
       m_matchStyle(matchStyle), 
@@ -58,27 +58,19 @@ ReplacementFragment::ReplacementFragment(Document *document, DocumentFragment *f
 {
     if (!m_document)
         return;
-
-    if (!m_fragment) {
-        m_type = EmptyFragment;
+    if (!m_fragment)
         return;
-    }
-
     Node* firstChild = m_fragment->firstChild();
-    Node* lastChild = m_fragment->lastChild();
-
-    if (!firstChild) {
-        m_type = EmptyFragment;
+    if (!firstChild)
         return;
-    }
-    
-    m_type = firstChild == lastChild && firstChild->isTextNode() ? SingleTextNodeFragment : TreeFragment;
     
+    Element* editableRoot = selection.rootEditableElement();
     ASSERT(editableRoot);
     if (!editableRoot)
         return;
-            
-    RefPtr<Node> holder = insertFragmentForTestRendering();
+
+    Node* styleNode = selection.base().node();
+    RefPtr<Node> holder = insertFragmentForTestRendering(styleNode);
     
     RefPtr<Range> range = Selection::selectionFromContentsOfNode(holder.get()).toRange();
     String text = plainText(range.get());
@@ -88,21 +80,16 @@ ReplacementFragment::ReplacementFragment(Document *document, DocumentFragment *f
     editableRoot->dispatchEvent(evt, ec, true);
     ASSERT(ec == 0);
     if (text != evt->text() || !editableRoot->isContentRichlyEditable()) {
-        // If the root is in plain-text mode, and white-space shouldn't be collapsed, then contruct a fragment that contains one text node
-        if (!editableRoot->isContentRichlyEditable() && editableRoot->renderer() && !editableRoot->renderer()->style()->collapseWhiteSpace()) {
-            RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
-            fragment->appendChild(document->createTextNode(evt->text()), ec);
-            ASSERT(ec == 0);
-            m_fragment = fragment;
-        } else
-            m_fragment = createFragmentFromText(document, evt->text().deprecatedString());
-        firstChild = m_fragment->firstChild();
-        lastChild = m_fragment->firstChild();
-        
+        restoreTestRenderingNodesToFragment(holder.get());
         removeNode(holder);
-        holder = insertFragmentForTestRendering();
+
+        m_fragment = createFragmentFromText(selection.toRange().get(), evt->text());
+        firstChild = m_fragment->firstChild();
+        if (!firstChild)
+            return;
+        holder = insertFragmentForTestRendering(styleNode);
     }
-    
+
     Node *node = firstChild;
     Node *newlineAtStartNode = 0;
     Node *newlineAtEndNode = 0;
@@ -144,8 +131,9 @@ ReplacementFragment::ReplacementFragment(Document *document, DocumentFragment *f
     removeStyleNodes();
 }
 
-ReplacementFragment::~ReplacementFragment()
+bool ReplacementFragment::isEmpty() const
 {
+    return (!m_fragment || !m_fragment->firstChild()) && !m_hasInterchangeNewlineAtStart && !m_hasInterchangeNewlineAtEnd;
 }
 
 Node *ReplacementFragment::firstChild() const 
@@ -232,15 +220,27 @@ void ReplacementFragment::insertNodeBefore(Node *node, Node *refNode)
     ASSERT(ec == 0);
 }
 
-PassRefPtr<Node> ReplacementFragment::insertFragmentForTestRendering()
+PassRefPtr<Node> ReplacementFragment::insertFragmentForTestRendering(Node* context)
 {
-    Node *body = m_document->body();
+    Nodebody = m_document->body();
     if (!body)
         return 0;
 
-    RefPtr<Node> holder = createDefaultParagraphElement(m_document.get());
+    RefPtr<StyledElement> holder = static_pointer_cast<StyledElement>(createDefaultParagraphElement(m_document.get()));
     
     ExceptionCode ec = 0;
+
+    // Copy the whitespace style from the context onto this element.
+    Node* n = context;
+    while (n && !n->isElementNode())
+        n = n->parentNode();
+    if (n) {
+        RefPtr<CSSComputedStyleDeclaration> contextStyle = new CSSComputedStyleDeclaration(static_cast<Element*>(n));
+        CSSStyleDeclaration* style = holder->style();
+        style->setProperty(CSS_PROP_WHITE_SPACE, contextStyle->getPropertyValue(CSS_PROP_WHITE_SPACE), false, ec);
+        ASSERT(ec == 0);
+    }
+    
     holder->appendChild(m_fragment, ec);
     ASSERT(ec == 0);
     
@@ -505,13 +505,12 @@ bool ReplaceSelectionCommand::shouldMergeStart(const ReplacementFragment& incomi
     return false;
 }
 
-bool ReplaceSelectionCommand::shouldMergeEnd(const VisiblePosition& endOfInsertedContent, bool fragmentHadInterchangeNewlineAtEnd, bool selectionEndWasEndOfParagraph)
+bool ReplaceSelectionCommand::shouldMergeEnd(const VisiblePosition& endOfInsertedContent, bool selectionEndWasEndOfParagraph)
 {
     Node* endNode = endOfInsertedContent.deepEquivalent().node();
     Node* nextNode = endOfInsertedContent.next().deepEquivalent().node();
     // FIXME: Unify the naming scheme for these enclosing element getters.
     return !selectionEndWasEndOfParagraph &&
-           !fragmentHadInterchangeNewlineAtEnd && 
            isEndOfParagraph(endOfInsertedContent) && 
            nearestMailBlockquote(endNode) == nearestMailBlockquote(nextNode) &&
            enclosingListChild(endNode) == enclosingListChild(nextNode) &&
@@ -532,9 +531,9 @@ void ReplaceSelectionCommand::doApply()
         m_matchStyle = true;
     
     Element* currentRoot = selection.rootEditableElement();
-    ReplacementFragment fragment(document(), m_documentFragment.get(), m_matchStyle, currentRoot);
+    ReplacementFragment fragment(document(), m_documentFragment.get(), m_matchStyle, selection);
     
-    if (fragment.type() == EmptyFragment)
+    if (fragment.isEmpty())
         return;
     
     if (m_matchStyle)
@@ -714,8 +713,21 @@ void ReplaceSelectionCommand::doApply()
         updateLayout();
         insertionPos = Position(m_lastNodeInserted.get(), m_lastNodeInserted->caretMaxOffset());
     }
+
+    Position lastPositionToSelect;
     
-    removeEndBRIfNeeded(endBR);
+    bool interchangeNewlineAtEnd = fragment.hasInterchangeNewlineAtEnd();
+    bool lastNodeInsertedWasBR = m_lastNodeInserted->hasTagName(brTag);
+
+    if (shouldRemoveEndBR(endBR)) {
+        if (interchangeNewlineAtEnd || lastNodeInsertedWasBR) {
+            interchangeNewlineAtEnd = false;
+            lastNodeInsertedWasBR = false;
+            m_lastNodeInserted = endBR;
+            lastPositionToSelect = VisiblePosition(Position(m_lastNodeInserted.get(), 0)).deepEquivalent();
+        } else
+            removeNodeAndPruneAncestors(endBR);
+    }
     
     // Styles were removed during the test insertion.  Restore them.
     if (!m_matchStyle)
@@ -724,26 +736,25 @@ void ReplaceSelectionCommand::doApply()
     VisiblePosition endOfInsertedContent(Position(m_lastNodeInserted.get(), maxDeepOffset(m_lastNodeInserted.get())));
     VisiblePosition startOfInsertedContent(Position(m_firstNodeInserted.get(), 0));    
     
-    Position lastPositionToSelect;
-    
-    if (fragment.hasInterchangeNewlineAtEnd()) {
+    if (interchangeNewlineAtEnd) {
         VisiblePosition pos(insertionPos);
         VisiblePosition next = pos.next();
-            
-        if (endWasEndOfParagraph || !isEndOfParagraph(pos) || next.isNull() || next.rootEditableElement() != currentRoot) {
-            setEndingSelection(insertionPos, DOWNSTREAM);
-            insertParagraphSeparator();
 
-            // Select up to the paragraph separator that was added.
-            lastPositionToSelect = endingSelection().visibleStart().deepEquivalent();
-            updateNodesInserted(lastPositionToSelect.node());
+        if (endWasEndOfParagraph || !isEndOfParagraph(pos) || next.rootEditableElement() != currentRoot) {
+            if (!isStartOfParagraph(pos)) {
+                setEndingSelection(pos.deepEquivalent().downstream(), DOWNSTREAM);
+                insertParagraphSeparator();
+
+                // Select up to the paragraph separator that was added.
+                lastPositionToSelect = endingSelection().visibleStart().deepEquivalent();
+                updateNodesInserted(lastPositionToSelect.node());
+            }
         } else {
             // Select up to the beginning of the next paragraph.
-            VisiblePosition next = pos.next();
             lastPositionToSelect = next.deepEquivalent().downstream();
         }
-        
-    } else if (m_lastNodeInserted->hasTagName(brTag)) {
+
+    } else if (lastNodeInsertedWasBR) {
         // We want to honor the last incoming line break, so, if it will collapse away because of quirks mode, 
         // add an extra one.
         // FIXME: This will expand a br inside a block: <div><br></div>
@@ -751,24 +762,37 @@ void ReplaceSelectionCommand::doApply()
         if (!document()->inStrictMode() && isEndOfBlock(VisiblePosition(Position(m_lastNodeInserted.get(), 0))))
             insertNodeBeforeAndUpdateNodesInserted(createBreakElement(document()).get(), m_lastNodeInserted.get());
             
-    } else if (shouldMergeEnd(endOfInsertedContent, fragment.hasInterchangeNewlineAtEnd(), endWasEndOfParagraph)) {
+    } else if (shouldMergeEnd(endOfInsertedContent, endWasEndOfParagraph)) {
         // Make sure that content after the end of the selection being pasted into is in the same paragraph as the 
         // last bit of content that was inserted.
         
-        // Merging two paragraphs will destroy the moved one's block styles.  Always move forward to preserve
-        // the block style of the paragraph already in the document, unless the paragraph to move would include the
-        // what was the start of the selection that was pasted into.
-        bool mergeForward = !inSameParagraph(startOfInsertedContent, endOfInsertedContent);
-        
-        VisiblePosition destination = mergeForward ? endOfInsertedContent.next() : endOfInsertedContent;
-        VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(endOfInsertedContent) : endOfInsertedContent.next();
-
-        moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
-        // Merging forward will remove m_lastNodeInserted from the document.
-        // FIXME: Maintain positions for the start and end of inserted content instead of keeping nodes.  The nodes are
-        // only ever used to create positions where inserted content starts/ends.
-        if (mergeForward)
-            m_lastNodeInserted = destination.previous().deepEquivalent().node();
+        Position downstreamEnd = endOfInsertedContent.deepEquivalent().downstream();
+        Position upstreamOnePastEnd = endOfInsertedContent.next().deepEquivalent().upstream();
+        Node* node = downstreamEnd.node();
+        int offset = downstreamEnd.offset();
+        if (node && node == upstreamOnePastEnd.node() && offset + 1 == upstreamOnePastEnd.offset() && node->isTextNode()) {
+            // Special case for removing a newline character.
+            Text* textNode = static_cast<Text*>(node);
+            if (textNode->length() == 1)
+                removeNodeAndPruneAncestors(textNode);
+            else
+                deleteTextFromNode(textNode, offset, 1);
+        } else {
+            // Merging two paragraphs will destroy the moved one's block styles.  Always move forward to preserve
+            // the block style of the paragraph already in the document, unless the paragraph to move would include the
+            // what was the start of the selection that was pasted into.
+            bool mergeForward = !inSameParagraph(startOfInsertedContent, endOfInsertedContent);
+            
+            VisiblePosition destination = mergeForward ? endOfInsertedContent.next() : endOfInsertedContent;
+            VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(endOfInsertedContent) : endOfInsertedContent.next();
+
+            moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
+            // Merging forward will remove m_lastNodeInserted from the document.
+            // FIXME: Maintain positions for the start and end of inserted content instead of keeping nodes.  The nodes are
+            // only ever used to create positions where inserted content starts/ends.
+            if (mergeForward)
+                m_lastNodeInserted = destination.previous().deepEquivalent().node();
+        }
     }
     
     endOfInsertedContent = VisiblePosition(Position(m_lastNodeInserted.get(), maxDeepOffset(m_lastNodeInserted.get())));
@@ -779,25 +803,27 @@ void ReplaceSelectionCommand::doApply()
         bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) &&
                                   !frame->isCharacterSmartReplaceExempt(endOfInsertedContent.characterAfter(), false);
         if (needsTrailingSpace) {
+            RenderObject* renderer = m_lastNodeInserted->renderer();
+            bool collapseWhiteSpace = !renderer || renderer->style()->collapseWhiteSpace();
             if (m_lastNodeInserted->isTextNode()) {
-                Text *text = static_cast<Text *>(m_lastNodeInserted.get());
-                insertTextIntoNode(text, text->length(), nonBreakingSpaceString());
-                insertionPos = Position(text, text->length());
+                Text* text = static_cast<Text*>(m_lastNodeInserted.get());
+                insertTextIntoNode(text, text->length(), collapseWhiteSpace ? nonBreakingSpaceString() : " ");
             } else {
-                RefPtr<Node> node = document()->createEditingTextNode(nonBreakingSpaceString());
+                RefPtr<Node> node = document()->createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
                 insertNodeAfterAndUpdateNodesInserted(node.get(), m_lastNodeInserted.get());
-                insertionPos = Position(node.get(), 1);
             }
         }
     
         bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) &&
                                  !frame->isCharacterSmartReplaceExempt(startOfInsertedContent.previous().characterAfter(), true);
         if (needsLeadingSpace) {
+            RenderObject* renderer = m_lastNodeInserted->renderer();
+            bool collapseWhiteSpace = !renderer || renderer->style()->collapseWhiteSpace();
             if (m_firstNodeInserted->isTextNode()) {
-                Text *text = static_cast<Text *>(m_firstNodeInserted.get());
-                insertTextIntoNode(text, 0, nonBreakingSpaceString());
+                Text* text = static_cast<Text*>(m_firstNodeInserted.get());
+                insertTextIntoNode(text, 0, collapseWhiteSpace ? nonBreakingSpaceString() : " ");
             } else {
-                RefPtr<Node> node = document()->createEditingTextNode(nonBreakingSpaceString());
+                RefPtr<Node> node = document()->createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
                 // Don't updateNodesInserted.  Doing so would set m_lastNodeInserted to be the node containing the 
                 // leading space, but m_lastNodeInserted is supposed to mark the end of pasted content.
                 insertNodeBefore(node.get(), m_firstNodeInserted.get());
@@ -810,19 +836,19 @@ void ReplaceSelectionCommand::doApply()
     completeHTMLReplacement(lastPositionToSelect);
 }
 
-void ReplaceSelectionCommand::removeEndBRIfNeeded(Node* endBR)
+bool ReplaceSelectionCommand::shouldRemoveEndBR(Node* endBR)
 {
     if (!endBR || !endBR->inDocument())
-        return;
+        return false;
         
     VisiblePosition visiblePos(Position(endBR, 0));
     
-    if (// The br is collapsed away and so is unnecessary.
+    return
+        // The br is collapsed away and so is unnecessary.
         !document()->inStrictMode() && isEndOfBlock(visiblePos) && !isStartOfParagraph(visiblePos) ||
         // A br that was originally holding a line open should be displaced by inserted content.
         // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder.
-        isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos))
-        removeNodeAndPruneAncestors(endBR);
+        isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos);
 }
 
 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositionToSelect)
index 0c1f096..c1d7d3f 100644 (file)
@@ -52,24 +52,20 @@ typedef HashMap<Node*, RefPtr<RenderingInfo> > RenderingInfoMap;
 
 // --- ReplacementFragment helper class
 
-class ReplacementFragment
+class ReplacementFragment : Noncopyable
 {
 public:
-    ReplacementFragment(Document*, DocumentFragment*, bool, Element*);
-    ~ReplacementFragment();
+    ReplacementFragment(Document*, DocumentFragment*, bool matchStyle, const Selection&);
 
-    Node *firstChild() const;
-    Node *lastChild() const;
+    NodefirstChild() const;
+    NodelastChild() const;
 
-    Node *mergeStartNode() const;
+    NodemergeStartNode() const;
 
     const RenderingInfoMap& renderingInfo() const { return m_renderingInfo; }
     const NodeVector& nodes() const { return m_nodes; }
 
-    EFragmentType type() const { return m_type; }
-    bool isEmpty() const { return m_type == EmptyFragment; }
-    bool isSingleTextNode() const { return m_type == SingleTextNodeFragment; }
-    bool isTreeFragment() const { return m_type == TreeFragment; }
+    bool isEmpty() const;
 
     bool hasMoreThanOneBlock() const { return m_hasMoreThanOneBlock; }
     bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAtStart; }
@@ -79,15 +75,11 @@ public:
     
     void removeNode(PassRefPtr<Node>);
 
-private:
-    // no copy construction or assignment
-    ReplacementFragment(const ReplacementFragment &);
-    ReplacementFragment &operator=(const ReplacementFragment &);
-    
-    static bool isInterchangeNewlineNode(const Node *);
-    static bool isInterchangeConvertedSpaceSpan(const Node *);
+private:    
+    static bool isInterchangeNewlineNode(const Node*);
+    static bool isInterchangeConvertedSpaceSpan(const Node*);
     
-    PassRefPtr<Node> insertFragmentForTestRendering();
+    PassRefPtr<Node> insertFragmentForTestRendering(Node* context);
     void saveRenderingInfo(Node*);
     void computeStylesUsingTestRendering(Node*);
     void removeUnrenderedNodes(Node*);
@@ -95,11 +87,10 @@ private:
     int renderedBlocks(Node*);
     void removeStyleNodes();
 
-    Node *enclosingBlock(Node *) const;
-    void removeNodePreservingChildren(Node *);
-    void insertNodeBefore(Node *node, Node *refNode);
+    Node* enclosingBlock(Node*) const;
+    void removeNodePreservingChildren(Node*);
+    void insertNodeBefore(Node* node, Node* refNode);
 
-    EFragmentType m_type;
     RefPtr<Document> m_document;
     RefPtr<DocumentFragment> m_fragment;
     RenderingInfoMap m_renderingInfo;
@@ -128,10 +119,10 @@ private:
 
     void updateNodesInserted(Node *);
     void fixupNodeStyles(const NodeVector&, const RenderingInfoMap&);
-    void removeEndBRIfNeeded(Node*);
+    bool shouldRemoveEndBR(Node*);
     
     bool shouldMergeStart(const ReplacementFragment&, const Selection&);
-    bool shouldMergeEnd(const VisiblePosition&, bool, bool);
+    bool shouldMergeEnd(const VisiblePosition&, bool selectionEndWasEndOfParagraph);
 
     RefPtr<Node> m_firstNodeInserted;
     RefPtr<Node> m_lastNodeInserted;
index c06b02a..1defa2b 100644 (file)
@@ -242,12 +242,12 @@ static DeprecatedString endMarkup(const Node *node)
     return "";
 }
 
-static DeprecatedString markup(const Node *startNode, bool onlyIncludeChildren, bool includeSiblings, DeprecatedPtrList<Node> *nodes)
+static DeprecatedString markup(Node* startNode, bool onlyIncludeChildren, bool includeSiblings, Vector<Node*> *nodes)
 {
     // Doesn't make sense to only include children and include siblings.
     ASSERT(!(onlyIncludeChildren && includeSiblings));
     DeprecatedString me = "";
-    for (const Node *current = startNode; current != NULL; current = includeSiblings ? current->nextSibling() : NULL) {
+    for (Node* current = startNode; current != NULL; current = includeSiblings ? current->nextSibling() : NULL) {
         if (!onlyIncludeChildren) {
             if (nodes)
                 nodes->append(current);
@@ -284,7 +284,7 @@ static void completeURLs(Node *node, const DeprecatedString &baseURL)
 
 // FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange? 
 // FIXME: At least, annotation and style info should probably not be included in range.markupString()
-DeprecatedString createMarkup(const Range *range, DeprecatedPtrList<Node> *nodes, EAnnotateForInterchange annotate)
+DeprecatedString createMarkup(const Range *range, Vector<Node*>* nodes, EAnnotateForInterchange annotate)
 {
     if (!range || range->isDetached())
         return DeprecatedString();
@@ -310,7 +310,7 @@ DeprecatedString createMarkup(const Range *range, DeprecatedPtrList<Node> *nodes
     DeprecatedStringList markups;
     Node *pastEnd = range->pastEndNode();
     Node *lastClosed = 0;
-    DeprecatedPtrList<Node> ancestorsToClose;
+    Vector<Node*> ancestorsToClose;
 
     // calculate the "default style" for this markup
     Position pos(doc->documentElement(), 0);
@@ -370,14 +370,15 @@ DeprecatedString createMarkup(const Range *range, DeprecatedPtrList<Node> *nodes
             if (n->nextSibling() == 0 || next == pastEnd) {
                 if (!ancestorsToClose.isEmpty()) {
                     // Close up the ancestors.
-                    while (Node *ancestor = ancestorsToClose.last()) {
+                    do {
+                        Node *ancestor = ancestorsToClose.last();
                         if (next != pastEnd && next->isAncestor(ancestor))
                             break;
                         // Not at the end of the range, close ancestors up to sibling of next node.
                         markups.append(endMarkup(ancestor));
                         lastClosed = ancestor;
                         ancestorsToClose.removeLast();
-                    }
+                    } while (!ancestorsToClose.isEmpty());
                 } else {
                     if (next != pastEnd) {
                         Node *nextParent = next->parentNode();
@@ -474,16 +475,18 @@ PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const
     return fragment.release();
 }
 
-DeprecatedString createMarkup(const Node *node, EChildrenOnly includeChildren,
-    DeprecatedPtrList<Node> *nodes, EAnnotateForInterchange annotate)
+DeprecatedString createMarkup(const Nodenode, EChildrenOnly includeChildren,
+    Vector<Node*>* nodes, EAnnotateForInterchange annotate)
 {
     ASSERT(annotate == DoNotAnnotateForInterchange); // annotation not yet implemented for this code path
     node->document()->updateLayoutIgnorePendingStylesheets();
-    return markup(node, includeChildren, false, nodes);
+    return markup(const_cast<Node*>(node), includeChildren, false, nodes);
 }
 
-static void createParagraphContentsFromString(Document *document, Element *paragraph, const DeprecatedString &string)
+static void createParagraphContentsFromString(Element* paragraph, const DeprecatedString& string)
 {
+    Document* document = paragraph->document();
+
     ExceptionCode ec = 0;
     if (string.isEmpty()) {
         paragraph->appendChild(createBlockPlaceholderElement(document), ec);
@@ -501,7 +504,7 @@ static void createParagraphContentsFromString(Document *document, Element *parag
 
         // append the non-tab textual part
         if (!s.isEmpty()) {
-            if (tabText != "") {
+            if (!tabText.isEmpty()) {
                 paragraph->appendChild(createTabSpanElement(document, tabText), ec);
                 ASSERT(ec == 0);
                 tabText = "";
@@ -514,52 +517,76 @@ static void createParagraphContentsFromString(Document *document, Element *parag
 
         // there is a tab after every entry, except the last entry
         // (if the last character is a tab, the list gets an extra empty entry)
-        if (!tabList.isEmpty()) {
+        if (!tabList.isEmpty())
             tabText += '\t';
-        } else if (tabText != "") {
+        else if (!tabText.isEmpty()) {
             paragraph->appendChild(createTabSpanElement(document, tabText), ec);
             ASSERT(ec == 0);
         }
     }
 }
 
-PassRefPtr<DocumentFragment> createFragmentFromText(Document *document, const DeprecatedString &text)
+PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text)
 {
-    if (!document)
+    if (!context)
         return 0;
 
+    Node* styleNode = context->startNode();
+    if (!styleNode) {
+        styleNode = context->startPosition().node();
+        if (!styleNode)
+            return 0;
+    }
+
+    Document* document = styleNode->document();
     RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
     
-    if (!text.isEmpty()) {
-        DeprecatedString string = text;
-
-        // Break string into paragraphs. Extra line breaks turn into empty paragraphs.
-        string.replace("\r\n", "\n");
-        string.replace('\r', '\n');
-        DeprecatedStringList list = DeprecatedStringList::split('\n', string, true); // true gets us empty strings in the list
-        while (!list.isEmpty()) {
-            DeprecatedString s = list.first();
-            list.pop_front();
-
-            ExceptionCode ec = 0;
+    if (text.isEmpty())
+        return fragment.release();
+
+    DeprecatedString string = text.deprecatedString();
+    string.replace("\r\n", "\n");
+    string.replace('\r', '\n');
+
+    ExceptionCode ec = 0;
+    RenderObject* renderer = styleNode->renderer();
+    if (renderer && renderer->style()->preserveNewline()) {
+        fragment->appendChild(document->createTextNode(string), ec);
+        ASSERT(ec == 0);
+        if (string.endsWith("\n")) {
             RefPtr<Element> element;
-            if (s.isEmpty() && list.isEmpty()) {
-                // For last line, use the "magic BR" rather than a P.
-                element = document->createElementNS(xhtmlNamespaceURI, "br", ec);
-                ASSERT(ec == 0);
-                element->setAttribute(classAttr, AppleInterchangeNewline);            
-            } else {
-                element = createDefaultParagraphElement(document);
-                createParagraphContentsFromString(document, element.get(), s);
-            }
-            fragment->appendChild(element.get(), ec);
+            element = document->createElementNS(xhtmlNamespaceURI, "br", ec);
+            ASSERT(ec == 0);
+            element->setAttribute(classAttr, AppleInterchangeNewline);            
+            fragment->appendChild(element.release(), ec);
             ASSERT(ec == 0);
         }
+        return fragment.release();
+    }
+
+    // Break string into paragraphs. Extra line breaks turn into empty paragraphs.
+    DeprecatedStringList list = DeprecatedStringList::split('\n', string, true); // true gets us empty strings in the list
+    while (!list.isEmpty()) {
+        DeprecatedString s = list.first();
+        list.pop_front();
+
+        RefPtr<Element> element;
+        if (s.isEmpty() && list.isEmpty()) {
+            // For last line, use the "magic BR" rather than a P.
+            element = document->createElementNS(xhtmlNamespaceURI, "br", ec);
+            ASSERT(ec == 0);
+            element->setAttribute(classAttr, AppleInterchangeNewline);            
+        } else {
+            element = createDefaultParagraphElement(document);
+            createParagraphContentsFromString(element.get(), s);
+        }
+        fragment->appendChild(element.release(), ec);
+        ASSERT(ec == 0);
     }
     return fragment.release();
 }
 
-PassRefPtr<DocumentFragment> createFragmentFromNodeList(Document *document, const DeprecatedPtrList<Node> &nodeList)
+PassRefPtr<DocumentFragment> createFragmentFromNodes(Document *document, const Vector<Node*>& nodes)
 {
     if (!document)
         return 0;
@@ -567,9 +594,10 @@ PassRefPtr<DocumentFragment> createFragmentFromNodeList(Document *document, cons
     RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
 
     ExceptionCode ec = 0;
-    for (DeprecatedPtrListIterator<Node> i(nodeList); i.current(); ++i) {
+    size_t size = nodes.size();
+    for (size_t i = 0; i < size; ++i) {
         RefPtr<Element> element = createDefaultParagraphElement(document);
-        element->appendChild(i.current(), ec);
+        element->appendChild(nodes[i], ec);
         ASSERT(ec == 0);
         fragment->appendChild(element.release(), ec);
         ASSERT(ec == 0);
index 8eb256f..1482bac 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "HTMLInterchange.h"
 #include <wtf/Forward.h>
+#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -37,18 +38,16 @@ namespace WebCore {
     class Range;
     class String;
 
-    template <class T> class DeprecatedPtrList;
-
     enum EChildrenOnly { IncludeNode, ChildrenOnly };
 
-    PassRefPtr<DocumentFragment> createFragmentFromText(Document*, const DeprecatedString &text);
-    PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document*, const String &markup, const String &baseURL);
-    PassRefPtr<DocumentFragment> createFragmentFromNodeList(Document*, const DeprecatedPtrList<Node> &nodeList);
+    PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text);
+    PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document*, const String& markup, const String& baseURL);
+    PassRefPtr<DocumentFragment> createFragmentFromNodes(Document*, const Vector<Node*>&);
 
-    DeprecatedString createMarkup(const Range *range,
-        DeprecatedPtrList<Node> *nodes = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange);
-    DeprecatedString createMarkup(const Node *node, EChildrenOnly = IncludeNode,
-        DeprecatedPtrList<Node> *nodes = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange);
+    DeprecatedString createMarkup(const Range*,
+        Vector<Node*>* = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange);
+    DeprecatedString createMarkup(const Node*, EChildrenOnly = IncludeNode,
+        Vector<Node*>* = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange);
 
 }
 
index ac48855..967b4e6 100644 (file)
@@ -300,6 +300,9 @@ void HTMLElement::setInnerHTML(const String &html, ExceptionCode& ec)
         return;
     }
 
+    // FIXME: Add special case for when we had one text child and we just want to set its text?
+    // FIXME: Add special case for cases where we can use replaceChild?
+
     removeChildren();
     appendChild(fragment.release(), ec);
 }
@@ -319,8 +322,8 @@ void HTMLElement::setOuterHTML(const String &html, ExceptionCode& ec)
         return;
     }
 
-    // FIXME: Why doesn't this have code to merge neighboring text nodes the
-    // way setOuterText does?
+    // FIXME: Add special case for when we had one text child and we just want to set its text?
+    // FIXME: Why doesn't this have code to merge neighboring text nodes the way setOuterText does?
     parent->replaceChild(fragment.release(), this, ec);
 }
 
@@ -339,36 +342,60 @@ void HTMLElement::setInnerText(const String& text, ExceptionCode& ec)
         return;
     }
 
+    // FIXME: This doesn't take whitespace collapsing into account at all.
+    // FIXME: Add special case for when we had one text child and we just want to set its text?
+    // FIXME: Add special case for cases where we can use replaceChild?
+
     removeChildren();
 
+    if (!text.contains('\n') && !text.contains('\r')) {
+        if (text.isEmpty())
+            return;
+        appendChild(new Text(document(), text), ec);
+        return;
+    }
+
+    // FIXME: Do we need to be able to detect preserveNewline style even when there's no renderer?
+    // FIXME: Can the renderer be out of date here? Do we need to call updateRendering?
+    // For example, for the contents of textarea elements that are display:none?
+    RenderObject* r = renderer();
+    if (r && r->style()->preserveNewline()) {
+        if (!text.contains('\r')) {
+            appendChild(new Text(document(), text), ec);
+            return;
+        }
+        // FIXME: Stick with String once it has a replace that can do this.
+        DeprecatedString textWithConsistentLineBreaks = text.deprecatedString();
+        textWithConsistentLineBreaks.replace("\r\n", "\n");
+        textWithConsistentLineBreaks.replace('\r', '\n');
+        appendChild(new Text(document(), textWithConsistentLineBreaks), ec);
+        return;
+    }
+
     // Add text nodes and <br> elements.
+    ec = 0;
+    int lineStart = 0;
+    UChar prev = 0;
     int length = text.length();
-    if (!text.contains('\n') && !text.contains('\r') && length)
-        appendChild(new Text(document(), text), ec);
-    else {
-        ec = 0;
-        int lineStart = 0;
-        UChar prev = 0;
-        for (int i = 0; i < length; ++i) {
-            UChar c = text[i];
-            if (c == '\n' || c == '\r') {
-                if (i > lineStart) {
-                    appendChild(new Text(document(), text.substring(lineStart, i - lineStart)), ec);
-                    if (ec)
-                        return;
-                }
-                if (!(c == '\n' && i != 0 && prev == '\r')) {
-                    appendChild(new HTMLBRElement(document()), ec);
-                    if (ec)
-                        return;
-                }
-                lineStart = i + 1;
+    for (int i = 0; i < length; ++i) {
+        UChar c = text[i];
+        if (c == '\n' || c == '\r') {
+            if (i > lineStart) {
+                appendChild(new Text(document(), text.substring(lineStart, i - lineStart)), ec);
+                if (ec)
+                    return;
+            }
+            if (!(c == '\n' && i != 0 && prev == '\r')) {
+                appendChild(new HTMLBRElement(document()), ec);
+                if (ec)
+                    return;
             }
-            prev = c;
+            lineStart = i + 1;
         }
-        if (length > lineStart)
-            appendChild(new Text(document(), text.substring(lineStart, length - lineStart)), ec);
+        prev = c;
     }
+    if (length > lineStart)
+        appendChild(new Text(document(), text.substring(lineStart, length - lineStart)), ec);
 }
 
 void HTMLElement::setOuterText(const String &text, ExceptionCode& ec)
index d3796d9..6688953 100644 (file)
@@ -259,13 +259,13 @@ String HTMLTextAreaElement::value() const
 
 void HTMLTextAreaElement::setValue(const String& value)
 {
-    DeprecatedString string = value.deprecatedString();
     // WebCoreTextArea normalizes line endings added by the user via the keyboard or pasting.
     // We must normalize line endings coming from JS.
-    string.replace("\r\n", "\n");
-    string.replace("\r", "\n");
+    DeprecatedString valueWithNormalizedLineEndings = value.deprecatedString();
+    valueWithNormalizedLineEndings.replace("\r\n", "\n");
+    valueWithNormalizedLineEndings.replace("\r", "\n");
     
-    m_value = String(string);
+    m_value = valueWithNormalizedLineEndings;
     setValueMatchesRenderer();
     if (renderer())
         renderer()->updateFromElement();
@@ -283,13 +283,14 @@ String HTMLTextAreaElement::defaultValue() const
 {
     String val = "";
 
-    // there may be comments - just grab the text nodes
+    // Since there may be comments, ignore nodes other than text nodes.
     for (Node* n = firstChild(); n; n = n->nextSibling())
         if (n->isTextNode())
             val += static_cast<Text*>(n)->data();
 
     // FIXME: We should only drop the first carriage return for the default
-    // value in the original source, not defaultValues set from JS.
+    // value in the original source, not defaultValues set from JS. This code
+    // will do both.
     if (val.length() >= 2 && val[0] == '\r' && val[1] == '\n')
         val.remove(0, 2);
     else if (val.length() >= 1 && (val[0] == '\r' || val[0] == '\n'))
@@ -300,18 +301,15 @@ String HTMLTextAreaElement::defaultValue() const
 
 void HTMLTextAreaElement::setDefaultValue(const String& defaultValue)
 {
-    // there may be comments - remove all the text nodes and replace them with one
-    DeprecatedPtrList<Node> toRemove;
-    Node *n;
-    for (n = firstChild(); n; n = n->nextSibling())
+    // To preserve comments, remove all the text nodes, then add a single one.
+    Vector<RefPtr<Node> > textNodes;
+    for (Node* n = firstChild(); n; n = n->nextSibling())
         if (n->isTextNode())
-            toRemove.append(n);
-    DeprecatedPtrListIterator<Node> it(toRemove);
+            textNodes.append(n);
     ExceptionCode ec = 0;
-    for (; it.current(); ++it) {
-        RefPtr<Node> n = it.current();
-        removeChild(n.get(), ec);
-    }
+    size_t size = textNodes.size();
+    for (size_t i = 0; i < size; ++i)
+        removeChild(textNodes[i].get(), ec);
     insertBefore(document()->createTextNode(defaultValue), firstChild(), ec);
     setValue(defaultValue);
 }
index f563d70..ff4a85d 100644 (file)
@@ -28,7 +28,6 @@
 #define Cache_h
 
 #include "CachePolicy.h"
-#include "DeprecatedPtrList.h"
 #include "PlatformString.h"
 #include <wtf/HashSet.h>
 
index 11053f5..1d06d8b 100644 (file)
@@ -735,4 +735,28 @@ int InlineTextBox::positionForOffset(int offset) const
                                                     IntPoint(m_x, 0), 0)).right();
 }
 
+bool InlineTextBox::containsCaretOffset(int offset) const
+{
+    // Offsets before the box are never "in".
+    if (offset < m_start)
+        return false;
+
+    int pastEnd = m_start + m_len;
+
+    // Offsets inside the box (not at either edge) are always "in".
+    if (offset < pastEnd)
+        return true;
+
+    // Offsets outside the box are always "out".
+    if (offset > pastEnd)
+        return false;
+
+    // Offsets at the end are "out" for line breaks (they are on the next line).
+    if (isLineBreak())
+        return false;
+
+    // Offsets at the end are "in" for normal boxes (but the caller has to check affinity).
+    return true;
+}
+
 }
index 54180da..e9a5563 100644 (file)
@@ -123,6 +123,8 @@ public:
     int textPos() const;
     int offsetForPosition(int _x, bool includePartialGlyphs = true) const;
     int positionForOffset(int offset) const;
+
+    bool containsCaretOffset(int offset) const; // false for offset after line break
     
     int m_start;
     unsigned short m_len;
index ced88aa..b472fa9 100644 (file)
@@ -358,14 +358,9 @@ static RenderObject *lastRendererOnPrevLine(InlineBox *box)
     return lastChild->object();
 }
 
-bool RenderText::atLineWrap(InlineTextBox *box, int offset)
+static inline bool atLineWrap(InlineTextBox* box, int offset)
 {
-    if (box->nextTextBox() && !box->nextOnLine() && offset == box->m_start + box->m_len) {
-        if (!style()->preserveNewline() || !box->isLineBreak())
-            return true;
-    }
-    
-    return false;
+    return box->nextTextBox() && !box->nextOnLine() && offset == box->m_start + box->m_len;
 }
 
 IntRect RenderText::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
@@ -376,7 +371,7 @@ IntRect RenderText::caretRect(int offset, EAffinity affinity, int *extraWidthToE
     // Find the text box for the given offset
     InlineTextBox *box = 0;
     for (box = firstTextBox(); box; box = box->nextTextBox()) {
-        if ((offset >= box->m_start) && (offset <= box->m_start + box->m_len)) {
+        if (box->containsCaretOffset(offset)) {
             // Check if downstream affinity would make us move to the next line.
             if (atLineWrap(box, offset) && affinity == DOWNSTREAM) {
                 // Use the next text box
@@ -1113,21 +1108,19 @@ unsigned RenderText::caretMaxRenderedOffset() const
     return l;
 }
 
-InlineBox *RenderText::inlineBox(int offset, EAffinity affinity)
+InlineBoxRenderText::inlineBox(int offset, EAffinity affinity)
 {
-    for (InlineTextBox *box = firstTextBox(); box; box = box->nextTextBox()) {
-        if (offset >= box->m_start && offset <= box->m_start + box->m_len) {
+    for (InlineTextBoxbox = firstTextBox(); box; box = box->nextTextBox()) {
+        if (box->containsCaretOffset(offset)) {
             if (atLineWrap(box, offset) && affinity == DOWNSTREAM)
                 return box->nextTextBox();
             return box;
         }
-        
-        if (offset < box->m_start) {
+        if (offset < box->m_start)
             // The offset we're looking for is before this node
             // this means the offset must be in content that is
             // not rendered.
             return box->prevTextBox() ? box->prevTextBox() : firstTextBox();
-        }
     }
     
     return 0;
index 7f3f2a0..54085cf 100644 (file)
@@ -149,11 +149,10 @@ public:
     virtual int caretMaxOffset() const;
     virtual unsigned caretMaxRenderedOffset() const;
 
-    virtual int previousOffset (int current) const;
-    virtual int nextOffset (int current) const;
+    virtual int previousOffset(int current) const;
+    virtual int nextOffset(int current) const;
     
-    bool atLineWrap(InlineTextBox *box, int offset);
-    bool containsReversedText() { return m_containsReversedText; }
+    bool containsReversedText() const { return m_containsReversedText; }
     
 public:
     InlineTextBox * findNextInlineTextBox( int offset, int &pos ) const;
index c827f18..59c09b1 100644 (file)
@@ -25,6 +25,7 @@
 #include "Event.h"
 #include "EventNames.h"
 #include "Frame.h"
+#include "HTMLBRElement.h"
 #include "HTMLInputElement.h"
 #include "HTMLNames.h"
 #include "HTMLTextAreaElement.h"
@@ -156,6 +157,8 @@ void RenderTextControl::updateFromElement()
         if (value != oldText || !m_div->hasChildNodes()) {
             ExceptionCode ec = 0;
             m_div->setInnerText(value, ec);
+            if (value.endsWith("\n") || value.endsWith("\r"))
+                m_div->appendChild(new HTMLBRElement(document()), ec);
             if (document()->frame())
                 document()->frame()->clearUndoRedoOperations();
             setEdited(false);
@@ -215,6 +218,9 @@ void RenderTextControl::setSelectionRange(int start, int end)
 
     SelectionController sel = SelectionController(startPosition, endPosition);
     document()->frame()->setSelection(sel);
+    // FIXME: Granularity is stored separately on the frame, but also in the selection controller.
+    // The granularity in the selection controller should be used, and then this line of code would not be needed.
+    document()->frame()->setSelectionGranularity(CharacterGranularity);
 }
 
 VisiblePosition RenderTextControl::visiblePositionForIndex(int index)
@@ -262,7 +268,7 @@ void RenderTextControl::subtreeHasChanged()
 String RenderTextControl::text()
 {
     if (m_div)
-        return m_div->textContent(true).replace('\\', backslashAsCurrencySymbol());
+        return m_div->textContent().replace('\\', backslashAsCurrencySymbol());
     return String();
 }
 
index 4200cb0..d23490e 100644 (file)
@@ -2474,7 +2474,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
 
     if (lBreak == start && !lBreak.obj->isBR()) {
         // we just add as much as possible
-        if (style()->whiteSpace() == PRE) {
+        if (style()->preserveNewline()) {
             // FIXME: Don't really understand this case.
             if (pos != 0) {
                 lBreak.obj = o;
index acf7a1b..6cda547 100644 (file)
@@ -1,3 +1,18 @@
+2006-07-24  Darin Adler  <darin@apple.com>
+
+        Reviewed by Adele and Justin.
+
+        - update for change to require context when creating fragments from text
+          (needed to handle whitespace properly)
+
+        * WebView/WebHTMLView.m:
+        (-[WebHTMLView _documentFragmentFromPasteboard:inContext:allowPlainText:chosePlainText:]):
+        Added context parameter, pass through to bridge.
+        (-[WebHTMLView _pasteWithPasteboard:allowPlainText:]): Pass selection range as context
+        when calling above method.
+        (-[WebHTMLView concludeDragForDraggingInfo:actionMask:]): Pass drag caret as context when
+        calling above method.
+
 2006-07-24  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Geoff.
index b493212..3a9f3c7 100644 (file)
@@ -176,7 +176,7 @@ void *_NSSoftLinkingGetFrameworkFuncPtr(NSString *inUmbrellaFrameworkName,
 
 @interface WebHTMLView (WebHTMLViewFileInternal)
 - (BOOL)_imageExistsAtPaths:(NSArray *)paths;
-- (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText chosePlainText:(BOOL *)chosePlainText;
+- (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard inContext:(DOMRange *)context allowPlainText:(BOOL)allowPlainText chosePlainText:(BOOL *)chosePlainText;
 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard;
 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText;
 - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard;
@@ -362,7 +362,10 @@ void *_NSSoftLinkingGetFrameworkFuncPtr(NSString *inUmbrellaFrameworkName,
     return elements;
 }
 
-- (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText chosePlainText:(BOOL *)chosePlainText
+- (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
+                                               inContext:(DOMRange *)context
+                                          allowPlainText:(BOOL)allowPlainText
+                                          chosePlainText:(BOOL *)chosePlainText
 {
     NSArray *types = [pasteboard types];
     *chosePlainText = NO;
@@ -463,7 +466,8 @@ void *_NSSoftLinkingGetFrameworkFuncPtr(NSString *inUmbrellaFrameworkName,
     
     if (allowPlainText && [types containsObject:NSStringPboardType]) {
         *chosePlainText = YES;
-        return [[self _bridge] documentFragmentWithText:[pasteboard stringForType:NSStringPboardType]];
+        return [[self _bridge] documentFragmentWithText:[pasteboard stringForType:NSStringPboardType]
+                                              inContext:context];
     }
     
     return nil;
@@ -508,8 +512,10 @@ void *_NSSoftLinkingGetFrameworkFuncPtr(NSString *inUmbrellaFrameworkName,
 
 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText
 {
+    DOMRange *range = [self _selectedRange];
     BOOL chosePlainText;
-    DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard allowPlainText:allowPlainText chosePlainText:&chosePlainText];
+    DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard
+        inContext:range allowPlainText:allowPlainText chosePlainText:&chosePlainText];
     WebFrameBridge *bridge = [self _bridge];
     if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:[self _selectedRange] givenAction:WebViewInsertActionPasted]) {
         [bridge replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:chosePlainText];
@@ -5725,9 +5731,11 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
     if ([self _canProcessDragWithDraggingInfo:draggingInfo]) {
         NSPasteboard *pasteboard = [draggingInfo draggingPasteboard];
         if ([self _isMoveDrag] || [innerBridge isDragCaretRichlyEditable]) { 
+            DOMRange *range = [innerBridge dragCaretDOMRange];
             BOOL chosePlainText;
-            DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard allowPlainText:YES chosePlainText:&chosePlainText];
-            if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:[innerBridge dragCaretDOMRange] givenAction:WebViewInsertActionDropped]) {
+            DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard
+                inContext:range allowPlainText:YES chosePlainText:&chosePlainText];
+            if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:range givenAction:WebViewInsertActionDropped]) {
                 [[webView _UIDelegateForwarder] webView:webView willPerformDragDestinationAction:WebDragDestinationActionEdit forDraggingInfo:draggingInfo];
                 if ([self _isMoveDrag]) {
                     BOOL smartMove = [innerBridge selectionGranularity] == WebBridgeSelectByWord && [self _canSmartReplaceWithPasteboard:pasteboard];