LayoutTests:
authorjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Dec 2006 21:01:30 +0000 (21:01 +0000)
committerjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Dec 2006 21:01:30 +0000 (21:01 +0000)
        Reviewed by harrison

        <rdar://problem/4753545>
        REGRESSION: Edited whitespace sequences are all nbsps (10636)

        * editing/inserting/edited-whitespace-1-expected.checksum: Added.
        * editing/inserting/edited-whitespace-1-expected.png: Added.
        * editing/inserting/edited-whitespace-1-expected.txt: Added.
        * editing/inserting/edited-whitespace-1.html: Added.

WebCore:

        Reviewed by harrison

        <rdar://problem/4753545>
        REGRESSION: Edited whitespace sequences are all nbsps (10636)

        * WebCore.xcodeproj/project.pbxproj: Removed RebalanceWhitespaceCommand.* from the project.
        * editing/CompositeEditCommand.cpp:
        (WebCore::isWhitespace): Moved from htmlediting.
        (WebCore::CompositeEditCommand::rebalanceWhitespaceAt): Moved the work that was
        once done in its own command here.
        (WebCore::CompositeEditCommand::prepareWhitespaceAtPositionForSplit): Prevents
        whitespace around a position from collapsing when it's pushed apart during Paste.
        This function can eventually be deployed to eliminate the need for leading/trailing
        whitespace handling in InsertParagraphSeparator, InsertLineBreak, Delete, and BreakBlockquote.
        (WebCore::CompositeEditCommand::rebalanceWhitespace): Cleaned up.
        * editing/CompositeEditCommand.h:
        * editing/DeleteSelectionCommand.cpp:
        (WebCore::DeleteSelectionCommand::doApply): Do rebalanceWhitespaceAt *before*
        saving the typing style, because whitespace rebalancing is no longer it's own
        command that claims to preserve the typing style.
        * editing/RebalanceWhitespaceCommand.cpp: Removed.
        * editing/RebalanceWhitespaceCommand.h: Removed.
        * editing/ReplaceSelectionCommand.cpp:
        (WebCore::ReplaceSelectionCommand::doApply): Moved the code to prepare whitespace
        arond a position for being pushed aparat to its own method.
        * editing/htmlediting.cpp:
        (WebCore::stringWithRebalancedWhitespace): Added.  Returns a rebalanced string.
        Takes in whether or not the beginning of that string will be at the start of
        a paragraph, because a space at such a position must have be nbsp, even if
        that doesn't follow the nbsp/space pattern used.  Similar stuff for the end
        of a paragraph.
        * editing/htmlediting.h:
        * editing/markup.cpp:
        (WebCore::fillContainerFromString): Call stringWithRelabacedWhitespace.  Pass
        it the startOfParagraph/endOfParagraph bools.

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

16 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/inserting/edited-whitespace-1-expected.checksum [new file with mode: 0644]
LayoutTests/editing/inserting/edited-whitespace-1-expected.png [new file with mode: 0644]
LayoutTests/editing/inserting/edited-whitespace-1-expected.txt [new file with mode: 0644]
LayoutTests/editing/inserting/edited-whitespace-1.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/editing/CompositeEditCommand.cpp
WebCore/editing/CompositeEditCommand.h
WebCore/editing/DeleteSelectionCommand.cpp
WebCore/editing/RebalanceWhitespaceCommand.cpp [deleted file]
WebCore/editing/RebalanceWhitespaceCommand.h [deleted file]
WebCore/editing/ReplaceSelectionCommand.cpp
WebCore/editing/htmlediting.cpp
WebCore/editing/htmlediting.h
WebCore/editing/markup.cpp

index 4e5e8db..ab1878f 100644 (file)
@@ -1,3 +1,15 @@
+2006-12-06  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by harrison
+        
+        <rdar://problem/4753545>
+        REGRESSION: Edited whitespace sequences are all nbsps (10636)
+
+        * editing/inserting/edited-whitespace-1-expected.checksum: Added.
+        * editing/inserting/edited-whitespace-1-expected.png: Added.
+        * editing/inserting/edited-whitespace-1-expected.txt: Added.
+        * editing/inserting/edited-whitespace-1.html: Added.
+
 2006-12-05  Rob Buis  <buis@kde.org>
 
         Reviewed by Mitz.
diff --git a/LayoutTests/editing/inserting/edited-whitespace-1-expected.checksum b/LayoutTests/editing/inserting/edited-whitespace-1-expected.checksum
new file mode 100644 (file)
index 0000000..44d39af
--- /dev/null
@@ -0,0 +1 @@
+86d834d1a588ad7066bc96a5e5a698b2
\ No newline at end of file
diff --git a/LayoutTests/editing/inserting/edited-whitespace-1-expected.png b/LayoutTests/editing/inserting/edited-whitespace-1-expected.png
new file mode 100644 (file)
index 0000000..c838705
Binary files /dev/null and b/LayoutTests/editing/inserting/edited-whitespace-1-expected.png differ
diff --git a/LayoutTests/editing/inserting/edited-whitespace-1-expected.txt b/LayoutTests/editing/inserting/edited-whitespace-1-expected.txt
new file mode 100644 (file)
index 0000000..4e46bd5
--- /dev/null
@@ -0,0 +1,17 @@
+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 784x576
+      RenderBlock {P} at (0,0) size 784x36
+        RenderText {#text} at (0,0) size 784x36
+          text run at (0,0) width 313: "This tests that edited whitespaces aren't all nbsps. "
+          text run at (313,0) width 471: "When the region becomes non-editable, Hello and World should still be on"
+          text run at (0,18) width 94: "different lines. "
+          text run at (94,18) width 584: "This demonstrates a bug: the div's focus halo doesn't go away when it becomes non-editable."
+      RenderBlock {DIV} at (0,52) size 62x38 [border: (1px solid #000000)]
+        RenderText {#text} at (1,1) size 55x36
+          text run at (1,1) width 55: " Hello    "
+          text run at (1,19) width 44: "World "
+      RenderBlock {OL} at (0,106) size 784x0
+caret: position 17 of child 0 {#text} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/inserting/edited-whitespace-1.html b/LayoutTests/editing/inserting/edited-whitespace-1.html
new file mode 100644 (file)
index 0000000..ebfe491
--- /dev/null
@@ -0,0 +1,37 @@
+<p>This tests that edited whitespaces aren't all nbsps.  When the region becomes non-editable, Hello and World should still be on different lines.  This demonstrates a bug: the div's focus halo doesn't go away when it becomes non-editable.</p>
+<div id="div" contenteditable="true" style="border: 1px solid black; width: 60px;"></div>
+<ol id="console"></ol>
+<script>
+function log(str) {
+    var li = document.createElement("li");
+    li.appendChild(document.createTextNode(str));
+    var console = document.getElementById("console");
+    console.appendChild(li);
+}
+
+var div = document.getElementById("div");
+var sel = window.getSelection();
+sel.setPosition(div, 0);
+document.execCommand("InsertText", false, " ");
+document.execCommand("InsertText", false, "Hello");
+document.execCommand("InsertText", false, " ");
+document.execCommand("InsertText", false, " ");
+document.execCommand("InsertText", false, " ");
+document.execCommand("InsertText", false, " ");
+document.execCommand("InsertText", false, " ");
+document.execCommand("InsertText", false, "World");
+document.execCommand("InsertText", false, " ");
+
+var innerText = div.innerHTML;
+
+// Check the pattern produced.  This might change in the future.
+var expected = "\xa0Hello \xa0 \xa0 World\xa0";
+var nbsp = false;
+for (var i = 0; i < innerText.length; i++) {
+    if(innerText[i] != expected[i])
+       log("Error: Character " + i + " of the editable region was not what was expected.");
+}
+
+div.contentEditable = "false";
+// When we turn content editability off, we'll see Hello and World on the same line if editing is using all nbsps.
+</script>
\ No newline at end of file
index c313712..3809aca 100644 (file)
@@ -1,3 +1,41 @@
+2006-12-06  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by harrison
+        
+        <rdar://problem/4753545>
+        REGRESSION: Edited whitespace sequences are all nbsps (10636)
+
+        * WebCore.xcodeproj/project.pbxproj: Removed RebalanceWhitespaceCommand.* from the project.
+        * editing/CompositeEditCommand.cpp:
+        (WebCore::isWhitespace): Moved from htmlediting.
+        (WebCore::CompositeEditCommand::rebalanceWhitespaceAt): Moved the work that was
+        once done in its own command here.  
+        (WebCore::CompositeEditCommand::prepareWhitespaceAtPositionForSplit): Prevents
+        whitespace around a position from collapsing when it's pushed apart during Paste.
+        This function can eventually be deployed to eliminate the need for leading/trailing 
+        whitespace handling in InsertParagraphSeparator, InsertLineBreak, Delete, and BreakBlockquote.
+        (WebCore::CompositeEditCommand::rebalanceWhitespace): Cleaned up.
+        * editing/CompositeEditCommand.h:
+        * editing/DeleteSelectionCommand.cpp:
+        (WebCore::DeleteSelectionCommand::doApply): Do rebalanceWhitespaceAt *before*
+        saving the typing style, because whitespace rebalancing is no longer it's own
+        command that claims to preserve the typing style.
+        * editing/RebalanceWhitespaceCommand.cpp: Removed.
+        * editing/RebalanceWhitespaceCommand.h: Removed.
+        * editing/ReplaceSelectionCommand.cpp:
+        (WebCore::ReplaceSelectionCommand::doApply): Moved the code to prepare whitespace
+        arond a position for being pushed aparat to its own method.
+        * editing/htmlediting.cpp:
+        (WebCore::stringWithRebalancedWhitespace): Added.  Returns a rebalanced string.
+        Takes in whether or not the beginning of that string will be at the start of
+        a paragraph, because a space at such a position must have be nbsp, even if
+        that doesn't follow the nbsp/space pattern used.  Similar stuff for the end 
+        of a paragraph.
+        * editing/htmlediting.h:
+        * editing/markup.cpp:
+        (WebCore::fillContainerFromString): Call stringWithRelabacedWhitespace.  Pass 
+        it the startOfParagraph/endOfParagraph bools.
+
 2006-12-05  John Sullivan  <sullivan@apple.com>
 
         Reviewed by Beth
index 93cd4dc..ef6f0df 100644 (file)
                93309DFA099E64920056E581 /* MergeIdenticalElementsCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DAB099E64910056E581 /* MergeIdenticalElementsCommand.h */; };
                93309DFB099E64920056E581 /* MoveSelectionCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DAC099E64910056E581 /* MoveSelectionCommand.cpp */; };
                93309DFC099E64920056E581 /* MoveSelectionCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DAD099E64910056E581 /* MoveSelectionCommand.h */; };
-               93309DFE099E64920056E581 /* RebalanceWhitespaceCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DAF099E64910056E581 /* RebalanceWhitespaceCommand.cpp */; };
-               93309DFF099E64920056E581 /* RebalanceWhitespaceCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DB0099E64910056E581 /* RebalanceWhitespaceCommand.h */; };
                93309E00099E64920056E581 /* RemoveCSSPropertyCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DB1099E64910056E581 /* RemoveCSSPropertyCommand.cpp */; };
                93309E01099E64920056E581 /* RemoveCSSPropertyCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 93309DB2099E64910056E581 /* RemoveCSSPropertyCommand.h */; };
                93309E02099E64920056E581 /* RemoveNodeAttributeCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93309DB3099E64910056E581 /* RemoveNodeAttributeCommand.cpp */; };
                93309DAB099E64910056E581 /* MergeIdenticalElementsCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MergeIdenticalElementsCommand.h; sourceTree = "<group>"; };
                93309DAC099E64910056E581 /* MoveSelectionCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MoveSelectionCommand.cpp; sourceTree = "<group>"; };
                93309DAD099E64910056E581 /* MoveSelectionCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MoveSelectionCommand.h; sourceTree = "<group>"; };
-               93309DAF099E64910056E581 /* RebalanceWhitespaceCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RebalanceWhitespaceCommand.cpp; sourceTree = "<group>"; };
-               93309DB0099E64910056E581 /* RebalanceWhitespaceCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RebalanceWhitespaceCommand.h; sourceTree = "<group>"; };
                93309DB1099E64910056E581 /* RemoveCSSPropertyCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveCSSPropertyCommand.cpp; sourceTree = "<group>"; };
                93309DB2099E64910056E581 /* RemoveCSSPropertyCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveCSSPropertyCommand.h; sourceTree = "<group>"; };
                93309DB3099E64910056E581 /* RemoveNodeAttributeCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveNodeAttributeCommand.cpp; sourceTree = "<group>"; };
                                C6D74AD309AA282E000B0A52 /* ModifySelectionListLevel.h */,
                                93309DAC099E64910056E581 /* MoveSelectionCommand.cpp */,
                                93309DAD099E64910056E581 /* MoveSelectionCommand.h */,
-                               93309DAF099E64910056E581 /* RebalanceWhitespaceCommand.cpp */,
-                               93309DB0099E64910056E581 /* RebalanceWhitespaceCommand.h */,
                                93309DB1099E64910056E581 /* RemoveCSSPropertyCommand.cpp */,
                                93309DB2099E64910056E581 /* RemoveCSSPropertyCommand.h */,
                                93309DB3099E64910056E581 /* RemoveNodeAttributeCommand.cpp */,
                                93309DF8099E64920056E581 /* markup.h in Headers */,
                                93309DFA099E64920056E581 /* MergeIdenticalElementsCommand.h in Headers */,
                                93309DFC099E64920056E581 /* MoveSelectionCommand.h in Headers */,
-                               93309DFF099E64920056E581 /* RebalanceWhitespaceCommand.h in Headers */,
                                93309E01099E64920056E581 /* RemoveCSSPropertyCommand.h in Headers */,
                                93309E03099E64920056E581 /* RemoveNodeAttributeCommand.h in Headers */,
                                93309E05099E64920056E581 /* RemoveNodeCommand.h in Headers */,
                0867D690FE84028FC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
-                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                English,
                        productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
                        projectDirPath = "";
                        projectRoot = "";
-                       shouldCheckCompatibility = 1;
                        targets = (
                                93F198A508245E59001E9ABC /* WebCore */,
                                DD041FBE09D9DDBE0010AF2A /* Derived Sources */,
                                93309DF7099E64920056E581 /* markup.cpp in Sources */,
                                93309DF9099E64920056E581 /* MergeIdenticalElementsCommand.cpp in Sources */,
                                93309DFB099E64920056E581 /* MoveSelectionCommand.cpp in Sources */,
-                               93309DFE099E64920056E581 /* RebalanceWhitespaceCommand.cpp in Sources */,
                                93309E00099E64920056E581 /* RemoveCSSPropertyCommand.cpp in Sources */,
                                93309E02099E64920056E581 /* RemoveNodeAttributeCommand.cpp in Sources */,
                                93309E04099E64920056E581 /* RemoveNodeCommand.cpp in Sources */,
index 6931eb3..99cc797 100644 (file)
@@ -45,7 +45,6 @@
 #include "markup.h"
 #include "MergeIdenticalElementsCommand.h"
 #include "Range.h"
-#include "RebalanceWhitespaceCommand.h"
 #include "RemoveCSSPropertyCommand.h"
 #include "RemoveNodeAttributeCommand.h"
 #include "RemoveNodeCommand.h"
@@ -327,27 +326,99 @@ void CompositeEditCommand::setNodeAttribute(Element* element, const QualifiedNam
     applyCommandToComposite(new SetNodeAttributeCommand(element, attribute, value));
 }
 
+static inline bool isWhitespace(UChar c)
+{
+    return c == NON_BREAKING_SPACE || c == ' ' || c == '\n' || c == '\t';
+}
+
+// FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).
 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
 {
-    Node* textNode = position.node();
-    if (!textNode || !textNode->isTextNode())
+    Node* node = position.node();
+    if (!node || !node->isTextNode())
         return;
-    if (static_cast<Text*>(textNode)->length() == 0)
+    Text* textNode = static_cast<Text*>(node);    
+    
+    if (textNode->length() == 0)
         return;
     RenderObject* renderer = textNode->renderer();
     if (renderer && !renderer->style()->collapseWhiteSpace())
         return;
-    applyCommandToComposite(new RebalanceWhitespaceCommand(position));    
+        
+    String text = textNode->data();
+    ASSERT(!text.isEmpty());
+
+    int offset = position.offset();
+    // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
+    if (!isWhitespace(text[offset])) {
+        offset--;
+        if (offset < 0 || !isWhitespace(text[offset]))
+            return;
+    }
+    
+    // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
+    int upstream = offset;
+    while (upstream > 0 && isWhitespace(text[upstream - 1]))
+        upstream--;
+    
+    int downstream = offset;
+    while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))
+        downstream++;
+    
+    int length = downstream - upstream + 1;
+    ASSERT(length > 0);
+    
+    VisiblePosition visibleUpstreamPos(Position(position.node(), upstream));
+    VisiblePosition visibleDownstreamPos(Position(position.node(), downstream + 1));
+    
+    String string = text.substring(upstream, length);
+    String rebalancedString = stringWithRebalancedWhitespace(string,
+    // FIXME: Because of the problem mentioned at the top of this function, we must also use nbsps at the start/end of the string because
+    // this function doesn't get all surrounding whitespace, just the whitespace in the current text node.
+                                                             isStartOfParagraph(visibleUpstreamPos) || upstream == 0, 
+                                                             isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length() - 1);
+    
+    if (string != rebalancedString)
+        replaceTextInNode(textNode, upstream, length, rebalancedString);
+}
+
+void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& position)
+{
+    Node* node = position.node();
+    if (!node || !node->isTextNode())
+        return;
+    Text* textNode = static_cast<Text*>(node);    
+    
+    if (textNode->length() == 0)
+        return;
+    RenderObject* renderer = textNode->renderer();
+    if (renderer && !renderer->style()->collapseWhiteSpace())
+        return;
+
+    // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it.
+    Position upstreamPos = position.upstream();
+    deleteInsignificantText(position.upstream(), position.downstream());
+    position = upstreamPos.downstream();
+
+    VisiblePosition visiblePos(position);
+    VisiblePosition previousVisiblePos(visiblePos.next());
+    Position previous(previousVisiblePos.deepEquivalent());
+    
+    if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.node()->isTextNode() && !previous.node()->hasTagName(brTag))
+        replaceTextInNode(static_cast<Text*>(previous.node()), previous.offset(), 1, nonBreakingSpaceString());
+    if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.node()->isTextNode() && !position.node()->hasTagName(brTag))
+        replaceTextInNode(static_cast<Text*>(position.node()), position.offset(), 1, nonBreakingSpaceString());
 }
 
 void CompositeEditCommand::rebalanceWhitespace()
 {
     Selection selection = endingSelection();
-    if (selection.isCaretOrRange()) {
-        rebalanceWhitespaceAt(endingSelection().start());
-        if (selection.isRange())
-            rebalanceWhitespaceAt(endingSelection().end());
-    }
+    if (selection.isNone())
+        return;
+        
+    rebalanceWhitespaceAt(selection.start());
+    if (selection.isRange())
+        rebalanceWhitespaceAt(selection.end());
 }
 
 void CompositeEditCommand::deleteInsignificantText(Text* textNode, int start, int end)
index a933f17..7978023 100644 (file)
@@ -63,6 +63,7 @@ protected:
     void joinTextNodes(Text*, Text*);
     void rebalanceWhitespace();
     void rebalanceWhitespaceAt(const Position&);
+    void prepareWhitespaceAtPositionForSplit(Position& position);
     void removeCSSProperty(CSSStyleDeclaration*, int property);
     void removeNodeAttribute(Element*, const QualifiedName& attribute);
     void removeChildrenInRange(Node*, int from, int to);
index c61101b..a834227 100644 (file)
@@ -603,9 +603,10 @@ void DeleteSelectionCommand::doApply()
     if (placeholder)
         insertNodeAt(placeholder.get(), m_endingPosition.node(), m_endingPosition.offset());
 
+    rebalanceWhitespaceAt(m_endingPosition);
+
     calculateTypingStyleAfterDelete(placeholder.get());
     
-    rebalanceWhitespaceAt(m_endingPosition);
     setEndingSelection(Selection(m_endingPosition, affinity));
     clearTransientState();
 }
diff --git a/WebCore/editing/RebalanceWhitespaceCommand.cpp b/WebCore/editing/RebalanceWhitespaceCommand.cpp
deleted file mode 100644 (file)
index 448f2eb..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#include "config.h"
-#include "RebalanceWhitespaceCommand.h"
-
-#include "Document.h"
-#include "htmlediting.h"
-#include "TextIterator.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-RebalanceWhitespaceCommand::RebalanceWhitespaceCommand(const Position& pos)
-    : EditCommand(pos.node()->document()), m_position(pos), m_upstreamOffset(InvalidOffset)
-{
-}
-
-static inline bool isWhitespace(UChar c)
-{
-    return c == 0xa0 || isCollapsibleWhitespace(c);
-}
-
-// FIXME: This doesn't go into adjacent text in siblings, cousins, etc.
-// FIXME: This turns preserved newlines into nbsps.
-void RebalanceWhitespaceCommand::doApply()
-{
-    if (!m_position.node()->isTextNode())
-        return;
-
-    Text* textNode = static_cast<Text*>(m_position.node());
-    String text = textNode->data();
-    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])) {
-        offset--;
-        if (offset < 0 || !isWhitespace(text[offset]))
-            return;
-    }
-    
-    // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
-    int upstream = offset;
-    while (upstream > 0 && isWhitespace(text[upstream - 1]))
-        upstream--;
-    m_upstreamOffset = upstream; // Save m_upstreamOffset, it will be used during an Undo
-    
-    int downstream = offset;
-    while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))
-        downstream++;
-    
-    int length = downstream - upstream + 1;
-    ASSERT(length > 0);
-    
-    m_beforeString = text.substring(upstream, length);
-    rebalanceWhitespaceInTextNode(textNode, upstream, length);
-    m_afterString = text.substring(upstream, length);
-}
-
-void RebalanceWhitespaceCommand::doUnapply()
-{
-    if (m_upstreamOffset == InvalidOffset)
-        return;
-    
-    ASSERT(m_position.node()->isTextNode());
-    
-    Text* node = static_cast<Text*>(m_position.node());
-    ExceptionCode ec = 0;
-    node->deleteData(m_upstreamOffset, m_afterString.length(), ec);
-    ASSERT(!ec);
-    node->insertData(m_upstreamOffset, m_beforeString, ec);
-    ASSERT(!ec);
-}
-
-bool RebalanceWhitespaceCommand::preservesTypingStyle() const
-{
-    return true;
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/RebalanceWhitespaceCommand.h b/WebCore/editing/RebalanceWhitespaceCommand.h
deleted file mode 100644 (file)
index 2a68082..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#ifndef rebalance_whitespace_command_h__
-#define rebalance_whitespace_command_h__
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class RebalanceWhitespaceCommand : public EditCommand {
-public:
-    RebalanceWhitespaceCommand(const Position&);
-
-    virtual void doApply();
-    virtual void doUnapply();
-
-private:
-    enum { InvalidOffset = -1 };
-
-    virtual bool preservesTypingStyle() const;
-
-    String m_beforeString;
-    String m_afterString;
-    Position m_position;
-    int m_upstreamOffset;
-    int m_downstreamOffset;
-};
-
-} // namespace WebCore
-
-#endif // rebalance_whitespace_command_h__
index 2d4563c..65372bd 100644 (file)
@@ -523,11 +523,7 @@ void ReplaceSelectionCommand::doApply()
     }
     
     // Inserting content could cause whitespace to collapse, e.g. inserting <div>foo</div> into hello^ world.
-    // We remove unrendered spaces and rebalance the rendered ones (turn them into nbsps) around insertionPos to prevent that.
-    Position upstreamInsertionPos = insertionPos.upstream();
-    deleteInsignificantText(insertionPos.upstream(), insertionPos.downstream());
-    insertionPos = upstreamInsertionPos.downstream();
-    rebalanceWhitespaceAt(insertionPos);
+    prepareWhitespaceAtPositionForSplit(insertionPos);
     
     // NOTE: This would be an incorrect usage of downstream() if downstream() were changed to mean the last position after 
     // p that maps to the same visible position as p (since in the case where a br is at the end of a block and collapsed 
index 33ccf44..c112a9c 100644 (file)
@@ -357,27 +357,27 @@ int maxDeepOffset(const Node *node)
     return 0;
 }
 
-void rebalanceWhitespaceInTextNode(Node *node, unsigned int start, unsigned int length)
+String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
 {
-    ASSERT(node->isTextNode());
-    Text *textNode = static_cast<Text *>(node);
-    String text = textNode->data();
-    ASSERT(length <= text.length() && start + length <= text.length());
+    static DeprecatedString twoSpaces("  ");
+    static DeprecatedString nbsp("\xa0");
+    static DeprecatedString pattern(" \xa0");
+
+    DeprecatedString rebalancedString = string.copy().deprecatedString();
+
+    rebalancedString.replace(NON_BREAKING_SPACE, ' ');
+    rebalancedString.replace('\n', ' ');
+    rebalancedString.replace('\t', ' ');
     
-    String substring = text.substring(start, length);
-
-    // FIXME: We rebalance with all nbsps, for simplicity (we don't need crazy sequences while editing
-    // because all editable regions will have -webkit-nbsp-mode: space.  We should produce sequences of 
-    // regular spaces and nbsps that are better for interchange when we serialize (10636).
-    substring.replace(' ', NON_BREAKING_SPACE);
-    substring.replace('\t', NON_BREAKING_SPACE);
-    substring.replace('\n', NON_BREAKING_SPACE);
+    rebalancedString.replace(twoSpaces, pattern);
     
-    ExceptionCode ec = 0;
-    textNode->deleteData(start, length, ec);
-    ASSERT(!ec);
-    textNode->insertData(start, String(substring), ec);
-    ASSERT(!ec);
+    if (startIsStartOfParagraph && rebalancedString[0] == ' ')
+        rebalancedString.replace(0, 1, nbsp);
+    int end = rebalancedString.length() - 1;
+    if (endIsEndOfParagraph && rebalancedString[end] == ' ')
+        rebalancedString.replace(end, 1, nbsp);    
+
+    return String(rebalancedString);
 }
 
 bool isTableStructureNode(const Node *node)
index a8f9b94..538513d 100644 (file)
@@ -61,7 +61,7 @@ Element* editableRootForPosition(const Position&);
 bool isBlock(Node*);
 Node* enclosingBlock(Node*);
 
-void rebalanceWhitespaceInTextNode(Node*, unsigned start, unsigned length);
+String stringWithRebalancedWhitespace(const String&, bool, bool);
 const String& nonBreakingSpaceString();
 
 //------------------------------------------------------------------------------------------
index b281535..b2ad84b 100644 (file)
@@ -595,6 +595,7 @@ static void fillContainerFromString(ContainerNode* paragraph, const DeprecatedSt
 
     DeprecatedStringList tabList = DeprecatedStringList::split('\t', string, true);
     DeprecatedString tabText = "";
+    bool first = true;
     while (!tabList.isEmpty()) {
         DeprecatedString s = tabList.first();
         tabList.pop_front();
@@ -606,8 +607,7 @@ static void fillContainerFromString(ContainerNode* paragraph, const DeprecatedSt
                 ASSERT(ec == 0);
                 tabText = "";
             }
-            RefPtr<Node> textNode = document->createTextNode(s);
-            rebalanceWhitespaceInTextNode(textNode.get(), 0, s.length());
+            RefPtr<Node> textNode = document->createTextNode(stringWithRebalancedWhitespace(s, first, tabList.isEmpty()));
             paragraph->appendChild(textNode.release(), ec);
             ASSERT(ec == 0);
         }
@@ -620,6 +620,8 @@ static void fillContainerFromString(ContainerNode* paragraph, const DeprecatedSt
             paragraph->appendChild(createTabSpanElement(document, tabText), ec);
             ASSERT(ec == 0);
         }
+        
+        first = false;
     }
 }