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 15e928de404581fa54406ec4cabe3241482622e9..13e567ca39e149d0ef088bfeeb7241a531aaa09b 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 ecdc79b1f21fda1cd5082332b70e80cac3178cee..6f741fd54751102418a843a67ad820839e7b7996 100644 (file)
@@ -1 +1 @@
-4f3c4bb088358dbb7dd79f971a4a41b8
\ No newline at end of file
+6ac121385e85689201493f064d0014f2
\ No newline at end of file
index 526ae7405d33c87f101a3754bdf17c43f02c423d..5b42d561fde0bafaaa25efe1dc8fcf95fcd613ea 100644 (file)
@@ -1 +1 @@
-827eed3249a8431338e7c6ea96dc90d8
\ No newline at end of file
+9a95881ba32b5b25fa40bd8cf30fa1d4
\ No newline at end of file
index 93685727d9cd60672a2cde46a1525a2ba44a49dd..7a2c011a6a352fb6f894530666784d054b686993 100644 (file)
Binary files a/LayoutTests/editing/pasteboard/4641033-expected.png and b/LayoutTests/editing/pasteboard/4641033-expected.png differ
index a80ab16352408cc66155e2ccf4a20b370692225b..ae1f2d0cc0558117d4eec77e4a7c134b4573ba7b 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 e4d0b8ff9351da1c7aaba42c4696f18f3c1e6634..0e18a972aa2af14604c5f1f4bf745d16a0fd9cac 100644 (file)
@@ -1 +1 @@
-00eb248dca688216f1341399284e4d66
\ No newline at end of file
+9697e5aa6aff2be0a6d9c1e2098d3c89
\ No newline at end of file
index b66d01481ec0f966a49ab733cc55c294706286df..d2e1b29bc31b1599e829845c04648d5b6177ff47 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 d298b90ff7c3a09ea3b369afc96dd28badfbe16b..798fb3be089dc4eba7c82ec962290733eb768c8e 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 4deab4bb924f7c80827ed5884dd463e85ee1ccb4..928d6c0dddd7205a7d17ebf0cce607b0f8772f32 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 27847d98faf73db599ba25abcc418dcae199ce6d..5770781f2354ad00dbb26736549ccb1915de92e8 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 55f42633e778030cfc4b067ab4c469c0b26a1055..71774badce7f2ca30df2bf7777251ed0ba94bc12 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 8c677d099c5cb893b9f0069531c10b732ce762cf..a3d2b01023f88e289ab506ddfd73aa6378244e0d 100644 (file)
@@ -1 +1 @@
-2762a21712500c513288a4796e7c6f0d
\ No newline at end of file
+e93d8592f6229d3c0681c600617c9f4d
\ No newline at end of file
index af80ca4110aa2ee5a53f7956e2a9da96d783cc3d..8c5435ea832e2df11b4a66ce2eae76b0c3d971f7 100644 (file)
@@ -1 +1 @@
-675958ca1760e67d565768737724a7ed
\ No newline at end of file
+b6430b633335a2e5a40c5bae7d791546
\ No newline at end of file
index b09182d474af6ec86ca77e15510a1dae1fa5c92f..3d34f8dda28250fd6fd19a6093a58ca6dd5d95cb 100644 (file)
@@ -1 +1 @@
-2a251ca75a4ee28206fbc9f203a921e3
\ No newline at end of file
+8a9b3e46242b36500276135ba1c29d62
\ No newline at end of file
index e4f79554d89130358c916023da7443181562f48a..76df3518d61a73cddf7bd95b53d4dedafe2f5735 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 d30232d6a7a2654963ce25cbf9ff2fdc3352863a..671471ea793eb8b2e37c510f7fec478d4edfd903 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 13d907d2355a4edcd325f78d0d5644929acf4818..3d24a5f8f9642472f5264924795d33dff6a56d15 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 2483b7a87bd998cff2c6acf444227fa962f7aaad..4f72001c6da9630a6c80ea54a78b268c3126323b 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 ee06033e9eccbcbeaf0e0ba98e3304dbae0adb70..d3e74632dcc87f288cad172dfbad5890f0e952ba 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 9beb219e88f9f549ce9f4e2755a2aa1c1b693aca..947c17d29ff45ac0b0553806181da9fa2455602c 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 6098b26435d2ff96e01801ac261bd172783e6fb7..6c97c5ba21891824dd8852dd4c0f101846ffc959 100644 (file)
@@ -1 +1 @@
-7f38cf2e654f194ce1a95e256537fbfe
\ No newline at end of file
+bb1e86fd2232a0b2c6bda501f303b1de
\ No newline at end of file
index 74f36b51236b79fa210d14be167c9fe729953029..7a7d8c3a6bf9140e34e9c1095ab1887dd8551177 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 b38295877171606512a27c3b04b835d1ac10952a..6345c5a10a172b9a715f2cdf00d3c4505ed41d39 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 bde451f70b1796eccac71d835ad71b606d38f29e..811e1c490ad043a80eb2d5ff0f249eb01a87b5b8 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 a06352bf82cc7f30930f5d65ad0f3c19d31b8692..57bd2c2c301e1d37b359af2d7ce53f6c4b55eee0 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 399e46c86a04e8dfe63f9fd7995c1ad309152419..6d56ec9511d48dca0b389ffc1bd5b49ae59ce756 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 200c57675e24810b0c95324bbe08e90cef971823..12bd2b4701fe4c1f28a45648e9b30fc83d260b6d 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 8fd549ec87fcad10f6f0c029173d0ff86574c235..0e9ac786c570cb6ebd585a2ca840d1b14e707199 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 8da332b800a5a53fe8fec8ebdbbfa017684e8805..a357cdf7a7ccef01d67c4989ca64540194b5cab3 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 900050716d9baac4094ca520346aab7acaa997b2..6eec0a6be9431b4aaba12502b98ad63c3d1a41f8 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 9b8af1b8ad2b8bf558d0a176087dea8d6a5d2e6d..ea0ecf702e6abf0e4672eb08991a038f5ef8ae68 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 584359d22fed4eafe8901042bb3aaaaf8e0b1831..a53422c2420171360615d93cea7b8fc533f63189 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 1a6322325778cf676eb7dd670b5da1f85cad75fb..faf498ee479071f8532203791534ae8dd7907d56 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 2243b57f7588959678a14b88958e3c3bc0600364..71af76eddc974bf6eadac540db7581b33732a197 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 ffa76f262e23d491e0de3ca148386f2b37b7a3be..2f76465d7088c89238c62a322d2f904bdda31093 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 0be387813356ec14d6332c5fa0a47efd4afa9c98..8c90dc912107cc9e7d0ccce289c0c25095b48627 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 0c1f096e4dbc82dc3667e20e18d36c369eea0b07..c1d7d3fa83123f5b7798f1db2e868204102d45fc 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 c06b02a36ac5c483238ba2e577279787a1db8eb9..1defa2b12013c653353b27d25a16e0cbfde982ac 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 8eb256fe89e64f96a3f88efe19851611844a1305..1482bac523a9421bf8d89411bb8ef6bf11355fb3 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 ac48855c55da2c0a428b10dee3056652467fb15b..967b4e667ea281da23f2a022d1579e13e778637e 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 d3796d940930444f7910a28c6a26a6b04a0d7a7c..66889537c47bef92c086732d7b4debc7dfa1ccc4 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 f563d70aaee88a555a2a36cada7db919857ef668..ff4a85d686db714a49a767bac9f9c32f9bedd1f0 100644 (file)
@@ -28,7 +28,6 @@
 #define Cache_h
 
 #include "CachePolicy.h"
-#include "DeprecatedPtrList.h"
 #include "PlatformString.h"
 #include <wtf/HashSet.h>
 
index 11053f5e76f09303182d716924d5b29df2ad973c..1d06d8b88da2db0ce66139832d9fe26c8bb787a2 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 54180da5842ff5b7089ac0428d54ef636f7d6031..e9a5563b29193c8735f6f64fab17ad31fbe54130 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 ced88aa226839b995482a3b3f5ab2b97a4b67609..b472fa9655b814ce4b327c4df63882024005f406 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 7f3f2a0c5439be0abe211fb28246edf48173f0fd..54085cfeea7761edc6e9996a4bafee445cba20d9 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 c827f183005f7954e3a2541f6452eb8fdbf35673..59c09b10c97dd338fb1c60c3525dec7f25c299c4 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 4200cb0a96c716835c145d3acf6770b440a697e4..d23490e49a17557566c682ecab29dbf2cd09e238 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 acf7a1b1a4318b6febacb3420d244b0fe794b44f..6cda547980866e43cb26c7034d72d3a228b43306 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 b493212e98197a67410ded80a695e86d7022fe62..3a9f3c7524190a788aa78e09e2d63d745f706875 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];