LayoutTests:
authorharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Oct 2006 18:17:52 +0000 (18:17 +0000)
committerharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Oct 2006 18:17:52 +0000 (18:17 +0000)
        Reviewed by Justin.

        <rdar://problem/4746860> Mail crash in WebCore::CSSMutableStyleDeclaration::merge(WebCore::CSSMutableStyleDeclaration*, bool)

        * editing/style/style-boundary-005.html: Added. Matches steps from bug.
        * editing/execCommand/hilitecolor-expected.txt: Updated (no empty Apple style spans).
        * editing/style/remove-underline-across-paragraph-in-bold-expected.txt: Updated (no empty Apple style spans).
        * editing/style/remove-underline-in-bold-expected.txt: Updated (no empty Apple style spans).
        * editing/style/typing-style-003-expected.txt: Updated (no empty Apple style spans).

WebCore:

        Reviewed by Justin.

        <rdar://problem/4746860> Mail crash in WebCore::CSSMutableStyleDeclaration::merge(WebCore::CSSMutableStyleDeclaration*, bool)

        Tests added or changed:
        * editing/style/style-boundary-005.html: Added. Matches steps from bug.
        * editing/execCommand/hilitecolor-expected.txt: Updated (no empty Apple style spans).
        * editing/style/remove-underline-across-paragraph-in-bold-expected.txt: Updated (no empty Apple style spans).
        * editing/style/remove-underline-in-bold-expected.txt: Updated (no empty Apple style spans).
        * editing/style/typing-style-003-expected.txt: Updated (no empty Apple style spans).

        * dom/Text.cpp:
        (WebCore::Text::splitText):
        Comment changes.

        * editing/ApplyStyleCommand.cpp:
        (WebCore::isUnstyledStyleSpan):
        Renamed from isEmptyStyleSpan.

        (WebCore::ApplyStyleCommand::applyRelativeFontStyleChange):
        Rename emptySpans local to unstyledSpans.

        (WebCore::dummySpanAncestorForNode):
        New. To locate Apple style span created when splitting a text node.

        (WebCore::ApplyStyleCommand::cleanupUnstyledAppleStyleSpans):
        Renamed from cleanUpEmptyStyleSpans. Algorithm changed to scan children
        of dummy span's parents, rather than traversing up from start and
        end locations. Old algorithm would miss empty spans in the bug case.

        (WebCore::ApplyStyleCommand::applyInlineStyle):
        Use dummySpanAncestorForNode() and cleanupUnstyledAppleStyleSpans().

        (WebCore::ApplyStyleCommand::removeCSSStyle):
        Renamed isEmptyStyleSpan() to isUnstyledStyleSpan().

        (WebCore::ApplyStyleCommand::mergeStartWithPreviousIfIdentical):
        Comment changes.

        * editing/ApplyStyleCommand.h:
        Renamed cleanUpEmptyStyleSpans() to cleanupUnstyledAppleStyleSpans().

        * editing/ReplaceSelectionCommand.cpp:
        (WebCore::ReplaceSelectionCommand::removeRedundantStyles):
        Allow for Apple style span to be unstyled, because old email may have this in the DOM.
        Use !node->hasChildNodes() instead of !node->firstChild().

        * editing/SplitTextNodeCommand.cpp:
        (WebCore::SplitTextNodeCommand::doApply):
        Comment changes.

        * rendering/RenderTreeAsText.cpp:
        (WebCore::isEmptyOrUnstyledAppleStyleSpan):
        (WebCore::operator<<):
        Flag empty or unstyled AppleStyleSpa nbecause we never want to leave them in the DOM

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

16 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/execCommand/hilitecolor-expected.txt
LayoutTests/editing/style/remove-underline-across-paragraph-in-bold-expected.txt
LayoutTests/editing/style/remove-underline-in-bold-expected.txt
LayoutTests/editing/style/style-boundary-005-expected.checksum [new file with mode: 0644]
LayoutTests/editing/style/style-boundary-005-expected.png [new file with mode: 0644]
LayoutTests/editing/style/style-boundary-005-expected.txt [new file with mode: 0644]
LayoutTests/editing/style/style-boundary-005.html [new file with mode: 0644]
LayoutTests/editing/style/typing-style-003-expected.txt
WebCore/ChangeLog
WebCore/dom/Text.cpp
WebCore/editing/ApplyStyleCommand.cpp
WebCore/editing/ApplyStyleCommand.h
WebCore/editing/ReplaceSelectionCommand.cpp
WebCore/editing/SplitTextNodeCommand.cpp
WebCore/rendering/RenderTreeAsText.cpp

index 84b4151189480f0ea0fdfd4284bbd8b2dc7f8300..f291e89b7c315c3b5820c091c45150fbb42b267b 100644 (file)
@@ -1,3 +1,15 @@
+2006-10-13  David Harrison  <harrison@apple.com>
+
+        Reviewed by Justin.
+
+        <rdar://problem/4746860> Mail crash in WebCore::CSSMutableStyleDeclaration::merge(WebCore::CSSMutableStyleDeclaration*, bool)
+
+        * editing/style/style-boundary-005.html: Added. Matches steps from bug.
+        * editing/execCommand/hilitecolor-expected.txt: Updated (no empty Apple style spans).
+        * editing/style/remove-underline-across-paragraph-in-bold-expected.txt: Updated (no empty Apple style spans).
+        * editing/style/remove-underline-in-bold-expected.txt: Updated (no empty Apple style spans).
+        * editing/style/typing-style-003-expected.txt: Updated (no empty Apple style spans).
+
 2006-10-12  Adele Peterson  <adele@apple.com>
 
         Reviewed by Anders.
index 0ffebffbc20ff5788d50d34a8eb8ecc74598a484..ae463de5ca7e5f892e279acd8ba6b633c297ca62 100644 (file)
@@ -5,7 +5,7 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of #text > SPAN > SPAN > DIV > BODY > HTML > #document to 6 of #text > SPAN > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of #text > SPAN > DIV > BODY > HTML > #document to 6 of #text > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
@@ -15,12 +15,11 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x18
-        RenderInline {SPAN} at (0,0) size 616x18
-          RenderText {#text} at (0,0) size 29x18
-            text run at (0,0) width 29: "The "
-          RenderInline {SPAN} at (0,0) size 44x18 [bgcolor=#FF0000]
-            RenderText {#text} at (29,0) size 44x18
-              text run at (29,0) width 44: "second"
-          RenderText {#text} at (73,0) size 543x18
-            text run at (73,0) width 543: " word, and only the second word of this sentence should have a red background color."
-caret: position 0 of child 0 {#text} of child 0 {SPAN} of child 0 {DIV} of child 0 {BODY} of child 0 {HTML} of document
+        RenderText {#text} at (0,0) size 29x18
+          text run at (0,0) width 29: "The "
+        RenderInline {SPAN} at (0,0) size 44x18 [bgcolor=#FF0000]
+          RenderText {#text} at (29,0) size 44x18
+            text run at (29,0) width 44: "second"
+        RenderText {#text} at (73,0) size 543x18
+          text run at (73,0) width 543: " word, and only the second word of this sentence should have a red background color."
+caret: position 0 of child 0 {#text} of child 0 {DIV} of child 0 {BODY} of child 0 {HTML} of document
index 65ad55ccf12071b0691dc9b10b84af6f3a92ffcf..1c461c5bf2da2296c7ef5cab84cb7ecedc109db1 100644 (file)
@@ -91,7 +91,8 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of SPAN > DIV > BODY > HTML > #document to 7 of #text > B > SPAN > DIV > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > B > SPAN > DIV > BODY > HTML > #document to 7 of #text > B > SPAN > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of #text > B > DIV > BODY > HTML > #document to 7 of #text > B > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
@@ -101,21 +102,19 @@ layer at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x84 [border: (2px solid #FF0000)]
         RenderBlock (anonymous) at (14,14) size 756x28
-          RenderInline {SPAN} at (0,0) size 150x28
-            RenderInline {B} at (0,0) size 78x28
-              RenderText {#text} at (0,0) size 78x28
-                text run at (0,0) width 78: "xxxxxx "
-            RenderInline {B} at (0,0) size 72x28
-              RenderText {#text} at (78,0) size 72x28
-                text run at (78,0) width 72: "xxxxxx"
+          RenderInline {B} at (0,0) size 78x28
+            RenderText {#text} at (0,0) size 78x28
+              text run at (0,0) width 78: "xxxxxx "
+          RenderInline {B} at (0,0) size 72x28
+            RenderText {#text} at (78,0) size 72x28
+              text run at (78,0) width 72: "xxxxxx"
           RenderInline {SPAN} at (0,0) size 0x28
         RenderBlock {DIV} at (14,42) size 756x28
-          RenderInline {SPAN} at (0,0) size 156x28
-            RenderInline {B} at (0,0) size 78x28
-              RenderText {#text} at (0,0) size 78x28
-                text run at (0,0) width 78: " xxxxxx"
-            RenderInline {B} at (0,0) size 78x28
-              RenderText {#text} at (78,0) size 78x28
-                text run at (78,0) width 78: " xxxxxx"
-selection start: position 0 of child 0 {#text} of child 1 {B} of child 0 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
-selection end:   position 7 of child 0 {#text} of child 0 {B} of child 0 {SPAN} of child 3 {DIV} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+          RenderInline {B} at (0,0) size 78x28
+            RenderText {#text} at (0,0) size 78x28
+              text run at (0,0) width 78: " xxxxxx"
+          RenderInline {B} at (0,0) size 78x28
+            RenderText {#text} at (78,0) size 78x28
+              text run at (78,0) width 78: " xxxxxx"
+selection start: position 0 of child 0 {#text} of child 1 {B} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+selection end:   position 7 of child 0 {#text} of child 0 {B} of child 4 {DIV} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index 7a8186edcd397cd15379b76d5e7adb182b5fef4f..81651d822b9ecf92a2e773d8df8dad34d8cd5b5d 100644 (file)
@@ -64,7 +64,8 @@ EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > B > SPAN > DIV > BODY > HTML > #document to 0 of SPAN > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > B > SPAN > DIV > BODY > HTML > #document to 6 of #text > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of #text > B > DIV > BODY > HTML > #document to 6 of #text > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
@@ -73,16 +74,15 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 228x28
-          RenderInline {B} at (0,0) size 78x28
-            RenderText {#text} at (14,14) size 78x28
-              text run at (14,14) width 78: "xxxxxx "
-          RenderInline {B} at (0,0) size 72x28
-            RenderText {#text} at (92,14) size 72x28
-              text run at (92,14) width 72: "xxxxxx"
-          RenderInline {B} at (0,0) size 78x28
-            RenderText {#text} at (164,14) size 78x28
-              text run at (164,14) width 78: " xxxxxx"
+        RenderInline {B} at (0,0) size 78x28
+          RenderText {#text} at (14,14) size 78x28
+            text run at (14,14) width 78: "xxxxxx "
+        RenderInline {B} at (0,0) size 72x28
+          RenderText {#text} at (92,14) size 72x28
+            text run at (92,14) width 72: "xxxxxx"
+        RenderInline {B} at (0,0) size 78x28
+          RenderText {#text} at (164,14) size 78x28
+            text run at (164,14) width 78: " xxxxxx"
         RenderInline {SPAN} at (0,0) size 0x28
-selection start: position 0 of child 0 {#text} of child 1 {B} of child 0 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
-selection end:   position 6 of child 0 {#text} of child 1 {B} of child 0 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+selection start: position 0 of child 0 {#text} of child 1 {B} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+selection end:   position 6 of child 0 {#text} of child 1 {B} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/style/style-boundary-005-expected.checksum b/LayoutTests/editing/style/style-boundary-005-expected.checksum
new file mode 100644 (file)
index 0000000..b3abe69
--- /dev/null
@@ -0,0 +1 @@
+f11d36fc2aff123bb37aba88f7e0a150
\ No newline at end of file
diff --git a/LayoutTests/editing/style/style-boundary-005-expected.png b/LayoutTests/editing/style/style-boundary-005-expected.png
new file mode 100644 (file)
index 0000000..ca94c01
Binary files /dev/null and b/LayoutTests/editing/style/style-boundary-005-expected.png differ
diff --git a/LayoutTests/editing/style/style-boundary-005-expected.txt b/LayoutTests/editing/style/style-boundary-005-expected.txt
new file mode 100644 (file)
index 0000000..dddfca0
--- /dev/null
@@ -0,0 +1,69 @@
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 3 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > B > DIV > DIV > BODY > HTML > #document to 1 of #text > B > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > B > DIV > DIV > BODY > HTML > #document to 1 of #text > B > DIV > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > B > DIV > DIV > BODY > HTML > #document to 2 of #text > B > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > B > DIV > DIV > BODY > HTML > #document to 2 of #text > B > DIV > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > B > DIV > DIV > BODY > HTML > #document to 3 of #text > B > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 3 of #text > B > DIV > DIV > BODY > HTML > #document to 3 of #text > B > DIV > DIV > BODY > HTML > #document toDOMRange:range from 4 of #text > B > DIV > DIV > BODY > HTML > #document to 4 of #text > B > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 4 of #text > B > DIV > DIV > BODY > HTML > #document to 4 of #text > B > DIV > DIV > BODY > HTML > #document toDOMRange:range from 5 of #text > B > DIV > DIV > BODY > HTML > #document to 5 of #text > B > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 5 of #text > B > DIV > DIV > BODY > HTML > #document to 5 of #text > B > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 5 of #text > B > DIV > DIV > BODY > HTML > #document to 5 of #text > B > DIV > DIV > BODY > HTML > #document toDOMRange:range from 4 of #text > SPAN > B > DIV > DIV > BODY > HTML > #document to 4 of #text > SPAN > B > DIV > DIV > BODY > HTML > #document 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 {DIV} at (0,0) size 784x184 [border: (2px solid #0000FF)]
+        RenderBlock {DIV} at (14,14) size 756x56
+          RenderText {#text} at (0,0) size 67x28
+            text run at (0,0) width 67: "Tests: "
+          RenderBR {BR} at (0,0) size 0x0
+          RenderText {#text} at (0,28) size 698x28
+            text run at (0,28) width 698: "Pasting at style boundary does not crash or produce empty style span(s)."
+        RenderBlock {DIV} at (14,86) size 756x84
+          RenderBlock (anonymous) at (0,0) size 756x56
+            RenderText {#text} at (0,0) size 189x28
+              text run at (0,0) width 189: "Expected Results: "
+            RenderBR {BR} at (189,22) size 0x0
+            RenderText {#text} at (0,28) size 442x28
+              text run at (0,28) width 442: "Should see this content in the red box below: "
+            RenderBR {BR} at (442,50) size 0x0
+          RenderBlock {DIV} at (0,56) size 756x28
+            RenderText {#text} at (0,0) size 138x28
+              text run at (0,0) width 138: "one two three "
+            RenderInline {B} at (0,0) size 44x28
+              RenderText {#text} at (138,0) size 44x28
+                text run at (138,0) width 44: "four"
+            RenderText {#text} at (182,0) size 41x28
+              text run at (182,0) width 41: " one"
+      RenderBlock {DIV} at (0,208) size 784x22
+        RenderBlock {DIV} at (0,0) size 784x22 [border: (2px solid #FF0000)]
+          RenderText {#text} at (2,2) size 86x18
+            text run at (2,2) width 86: "one two three"
+          RenderInline {B} at (0,0) size 60x18
+            RenderText {#text} at (88,2) size 33x18
+              text run at (88,2) width 33: " four"
+            RenderInline {SPAN} at (0,0) size 27x18
+              RenderText {#text} at (121,2) size 27x18
+                text run at (121,2) width 27: " one"
+        RenderBlock (anonymous) at (0,22) size 784x0
+caret: position 4 of child 0 {#text} of child 1 {SPAN} of child 1 {B} of child 1 {DIV} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/style/style-boundary-005.html b/LayoutTests/editing/style/style-boundary-005.html
new file mode 100644 (file)
index 0000000..dd75d99
--- /dev/null
@@ -0,0 +1,67 @@
+<html> 
+<head>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+}
+.explanation { 
+    border: 2px solid blue; 
+    padding: 12px; 
+    font-size: 24px; 
+    margin-bottom: 24px;
+}
+.scenario { margin-bottom: 16px;}
+.scenario:first-line { font-weight: bold; margin-bottom: 16px;}
+.expected-results:first-line { font-weight: bold }
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+
+function editingTest() {
+    moveSelectionForwardByLineCommand();
+    boldCommand();
+    typeCharacterCommand(' ');
+    typeCharacterCommand('f');
+    typeCharacterCommand('o');
+    typeCharacterCommand('u');
+    typeCharacterCommand('r');
+    moveSelectionBackwardByLineCommand();
+    extendSelectionForwardByWordCommand();
+    copyCommand();
+    moveSelectionForwardByWordCommand();
+    moveSelectionForwardByWordCommand();
+    moveSelectionForwardByWordCommand();
+    pasteCommand();
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+
+<div class="explanation">
+<div class="scenario">
+Tests: 
+<br>
+Pasting at style boundary does not crash or produce empty style span(s).
+</div>
+<div class="expected-results">
+Expected Results:
+<br>
+Should see this content in the red box below: <br><div>one two three <b>four</b> one</div>
+</div>
+</div>
+
+<div contenteditable id="root">
+<div id="test" class="editing">one two three</div>
+</div>
+
+<script>
+runEditingTest();
+</script>
+
+</body>
+</html>
index 3c531d70391294c0c46f286d347d772a73924922..7cc2f724691b993760358fabab7aef7d1c0bbed2 100644 (file)
@@ -11,43 +11,43 @@ EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > DIV > BOD
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > B > DIV > BODY > HTML > #document to 1 of #text > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > B > DIV > BODY > HTML > #document to 1 of #text > B > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > B > DIV > BODY > HTML > #document to 2 of #text > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > B > SPAN > DIV > BODY > HTML > #document to 3 of #text > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > B > DIV > BODY > HTML > #document to 2 of #text > B > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > B > DIV > BODY > HTML > #document to 3 of #text > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > I > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > I > B > DIV > BODY > HTML > #document to 1 of #text > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > I > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > I > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > I > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > I > B > DIV > BODY > HTML > #document to 1 of #text > I > B > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > I > B > DIV > BODY > HTML > #document to 2 of #text > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > I > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > I > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > I > B > SPAN > DIV > BODY > HTML > #document to 3 of #text > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > I > B > DIV > BODY > HTML > #document to 2 of #text > I > B > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > I > B > DIV > BODY > HTML > #document to 3 of #text > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > SPAN > I > B > DIV > BODY > HTML > #document to 1 of #text > SPAN > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > I > B > DIV > BODY > HTML > #document to 1 of #text > SPAN > I > B > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > I > B > DIV > BODY > HTML > #document to 2 of #text > SPAN > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 3 of #text > SPAN > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > SPAN > I > B > DIV > BODY > HTML > #document to 2 of #text > SPAN > I > B > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > SPAN > I > B > DIV > BODY > HTML > #document to 3 of #text > SPAN > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document to 1 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document to 3 of #text > SPAN > SPAN > I > B > SPAN > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document to 2 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document to 3 of #text > SPAN > SPAN > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
@@ -56,20 +56,19 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 177x28
-          RenderText {#text} at (14,14) size 36x28
-            text run at (14,14) width 36: "xxx"
-          RenderInline {B} at (0,0) size 141x28
-            RenderText {#text} at (50,14) size 36x28
-              text run at (50,14) width 36: "xxx"
-            RenderInline {I} at (0,0) size 105x28
-              RenderText {#text} at (86,14) size 36x28
-                text run at (86,14) width 36: "xxx"
-              RenderInline {SPAN} at (0,0) size 69x28
-                RenderText {#text} at (122,14) size 33x28
-                  text run at (122,14) width 33: "xxx"
-                RenderInline {SPAN} at (0,0) size 36x28
-                  RenderText {#text} at (155,14) size 36x28
-                    text run at (155,14) width 36: "xxx"
-          RenderInline {SPAN} at (0,0) size 0x28
-caret: position 3 of child 0 {#text} of child 1 {SPAN} of child 1 {SPAN} of child 1 {I} of child 1 {B} of child 0 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+        RenderText {#text} at (14,14) size 36x28
+          text run at (14,14) width 36: "xxx"
+        RenderInline {B} at (0,0) size 141x28
+          RenderText {#text} at (50,14) size 36x28
+            text run at (50,14) width 36: "xxx"
+          RenderInline {I} at (0,0) size 105x28
+            RenderText {#text} at (86,14) size 36x28
+              text run at (86,14) width 36: "xxx"
+            RenderInline {SPAN} at (0,0) size 69x28
+              RenderText {#text} at (122,14) size 33x28
+                text run at (122,14) width 33: "xxx"
+              RenderInline {SPAN} at (0,0) size 36x28
+                RenderText {#text} at (155,14) size 36x28
+                  text run at (155,14) width 36: "xxx"
+        RenderInline {SPAN} at (0,0) size 0x28
+caret: position 3 of child 0 {#text} of child 1 {SPAN} of child 1 {SPAN} of child 1 {I} of child 1 {B} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index 7eabb792d304ac1fdc555897817ea67400bae043..2aa99f162111b2939bda6f279b582fd9f0a1244b 100644 (file)
@@ -1,3 +1,61 @@
+2006-10-13  David Harrison  <harrison@apple.com>
+
+        Reviewed by Justin.
+
+        <rdar://problem/4746860> Mail crash in WebCore::CSSMutableStyleDeclaration::merge(WebCore::CSSMutableStyleDeclaration*, bool)
+
+        Tests added or changed:
+        * editing/style/style-boundary-005.html: Added. Matches steps from bug.
+        * editing/execCommand/hilitecolor-expected.txt: Updated (no empty Apple style spans).
+        * editing/style/remove-underline-across-paragraph-in-bold-expected.txt: Updated (no empty Apple style spans).
+        * editing/style/remove-underline-in-bold-expected.txt: Updated (no empty Apple style spans).
+        * editing/style/typing-style-003-expected.txt: Updated (no empty Apple style spans).
+
+        * dom/Text.cpp:
+        (WebCore::Text::splitText):
+        Comment changes.
+        
+        * editing/ApplyStyleCommand.cpp:
+        (WebCore::isUnstyledStyleSpan):
+        Renamed from isEmptyStyleSpan.
+        
+        (WebCore::ApplyStyleCommand::applyRelativeFontStyleChange):
+        Rename emptySpans local to unstyledSpans.
+        
+        (WebCore::dummySpanAncestorForNode):
+        New. To locate Apple style span created when splitting a text node.
+        
+        (WebCore::ApplyStyleCommand::cleanupUnstyledAppleStyleSpans):
+        Renamed from cleanUpEmptyStyleSpans. Algorithm changed to scan children
+        of dummy span's parents, rather than traversing up from start and
+        end locations. Old algorithm would miss empty spans in the bug case.
+        
+        (WebCore::ApplyStyleCommand::applyInlineStyle):
+        Use dummySpanAncestorForNode() and cleanupUnstyledAppleStyleSpans().
+        
+        (WebCore::ApplyStyleCommand::removeCSSStyle):
+        Renamed isEmptyStyleSpan() to isUnstyledStyleSpan().
+        
+        (WebCore::ApplyStyleCommand::mergeStartWithPreviousIfIdentical):
+        Comment changes.
+        
+        * editing/ApplyStyleCommand.h:
+        Renamed cleanUpEmptyStyleSpans() to cleanupUnstyledAppleStyleSpans().
+          
+        * editing/ReplaceSelectionCommand.cpp:
+        (WebCore::ReplaceSelectionCommand::removeRedundantStyles):
+        Allow for Apple style span to be unstyled, because old email may have this in the DOM.
+        Use !node->hasChildNodes() instead of !node->firstChild().
+        
+        * editing/SplitTextNodeCommand.cpp:
+        (WebCore::SplitTextNodeCommand::doApply):
+        Comment changes.
+        
+        * rendering/RenderTreeAsText.cpp:
+        (WebCore::isEmptyOrUnstyledAppleStyleSpan):
+        (WebCore::operator<<):
+        Flag empty or unstyled AppleStyleSpa nbecause we never want to leave them in the DOM
+
 2006-10-13  Nikolas Zimmermann  <zimmermann@kde.org>
 
         Reviewed by Eric.
index cae2f42455c259f1171fc38c51d62fa93b972d5e..a76f59c49042ac9096830468dff2d9e44515abb7 100644 (file)
@@ -56,6 +56,8 @@ Text *Text::splitText(unsigned offset, ExceptionCode& ec)
 {
     ec = 0;
 
+    // FIXME: This does not copy markers
+    
     // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than
     // the number of 16-bit units in data.
     if (offset > str->length()) {
index ef0f143c00e867d8118f0c7cc852d929e498bcae..8300a97405d9267947014364b68d7af48a413002 100644 (file)
@@ -220,7 +220,7 @@ bool isStyleSpan(const Node *node)
     return elem->hasLocalName(spanAttr) && elem->getAttribute(classAttr) == styleSpanClassString();
 }
 
-static bool isEmptyStyleSpan(const Node *node)
+static bool isUnstyledStyleSpan(const Node *node)
 {
     if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag))
         return false;
@@ -496,7 +496,7 @@ void ApplyStyleCommand::applyRelativeFontStyleChange(CSSMutableStyleDeclaration
         startingFontSizes.set(node, computedFontSize(node));
 
     // These spans were added by us. If empty after font size changes, they can be removed.
-    DeprecatedPtrList<Node> emptySpans;
+    DeprecatedPtrList<Node> unstyledSpans;
     
     Node *lastStyledNode = 0;
     for (Node *node = startNode; node != beyondEnd; node = node->traverseNextNode()) {
@@ -533,25 +533,54 @@ void ApplyStyleCommand::applyRelativeFontStyleChange(CSSMutableStyleDeclaration
         }
         if (inlineStyleDecl->length() == 0) {
             removeNodeAttribute(elem, styleAttr);
-            if (isEmptyStyleSpan(elem))
-                emptySpans.append(elem);
+            if (isUnstyledStyleSpan(elem))
+                unstyledSpans.append(elem);
         }
     }
 
-    for (DeprecatedPtrListIterator<Node> it(emptySpans); it.current(); ++it)
+    for (DeprecatedPtrListIterator<Node> it(unstyledSpans); it.current(); ++it)
         removeNodePreservingChildren(it.current());
 }
 
 #undef NoFontDelta
 #undef MinimumFontSize
 
+static Node* dummySpanAncestorForNode(const Node* node)
+{
+    while (node && !isStyleSpan(node))
+        node = node->parent();
+    
+    return node ? node->parent() : 0;
+}
+
+void ApplyStyleCommand::cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor)
+{
+    if (!dummySpanAncestor)
+        return;
+
+    // Dummy spans are created when text node is split, so that style information
+    // can be propagated, which can result in more splitting. If a dummy span gets
+    // cloned/split, the new node is always a sibling of it. Therefore, we scan
+    // all the children of the dummy's parent
+    Node* next;
+    for (Node* node = dummySpanAncestor->firstChild(); node; node = next) {
+        next = node->nextSibling();
+        if (isUnstyledStyleSpan(node))
+            removeNodePreservingChildren(node);
+        node = next;
+    }
+}
+
 void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
 {
+    Node* startDummySpanAncestor = 0;
+    Node* endDummySpanAncestor = 0;
+    
     // update document layout once before removing styles
     // so that we avoid the expense of updating before each and every call
     // to check a computed style
     updateLayout();
-    
+
     // adjust to the positions we want to use for applying style
     Position start = startPosition();
     Position end = endPosition();
@@ -566,6 +595,7 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
     if (splitStart) {
         start = startPosition();
         end = endPosition();
+        startDummySpanAncestor = dummySpanAncestorForNode(start.node());
     }
 
     // split the end node and containing element if the selection ends inside of it
@@ -573,6 +603,7 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
     if (splitEnd) {
         start = startPosition();
         end = endPosition();
+        endDummySpanAncestor = dummySpanAncestorForNode(end.node());
     }
 
     // Remove style from the selection.
@@ -651,9 +682,10 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
         }
     }
 
-    if (splitStart || splitEnd) {
-        cleanUpEmptyStyleSpans(start, end);
-    }
+    // remove dummy style spans created by splitting text elements
+    cleanupUnstyledAppleStyleSpans(startDummySpanAncestor);
+    if (endDummySpanAncestor != startDummySpanAncestor)
+        cleanupUnstyledAppleStyleSpans(endDummySpanAncestor);
 }
 
 bool ApplyStyleCommand::isHTMLStyleNode(CSSMutableStyleDeclaration *style, HTMLElement *elem)
@@ -732,7 +764,7 @@ void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration *style, HTMLEl
             removeCSSProperty(decl, propertyID);
     }
 
-    if (isEmptyStyleSpan(elem))
+    if (isUnstyledStyleSpan(elem))
         removeNodePreservingChildren(elem);
 }
 
@@ -1092,6 +1124,8 @@ bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position &start,
         if (start.offset() != 0)
             return false;
 
+        // note: prior siblings could be unrendered elements. it's silly to miss the
+        // merge opportunity just for that.
         if (start.node()->previousSibling())
             return false;
 
@@ -1163,53 +1197,6 @@ bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position &start, const
     return false;
 }
 
-void ApplyStyleCommand::cleanUpEmptyStyleSpans(const Position &start, const Position &end)
-{
-    Node *node;
-    for (node = start.node(); node && !node->previousSibling(); node = node->parentNode()) {
-    }
-
-    if (node && isEmptyStyleSpan(node->previousSibling())) {
-        removeNodePreservingChildren(node->previousSibling());
-    }
-
-    if (start.node() == end.node()) {
-        if (start.node()->isTextNode()) {
-            for (Node *last = start.node(), *cur = last->parentNode(); cur && !last->previousSibling() && !last->nextSibling(); last = cur, cur = cur->parentNode()) {
-                if (isEmptyStyleSpan(cur)) {
-                    removeNodePreservingChildren(cur);
-                    break;
-                }
-            }
-
-        }
-    } else {
-        if (start.node()->isTextNode()) {
-            for (Node *last = start.node(), *cur = last->parentNode(); cur && !last->previousSibling(); last = cur, cur = cur->parentNode()) {
-                if (isEmptyStyleSpan(cur)) {
-                    removeNodePreservingChildren(cur);
-                    break;
-                }
-            }
-        }
-
-        if (end.node()->isTextNode()) {
-            for (Node *last = end.node(), *cur = last->parentNode(); cur && !last->nextSibling(); last = cur, cur = cur->parentNode()) {
-                if (isEmptyStyleSpan(cur)) {
-                    removeNodePreservingChildren(cur);
-                    break;
-                }
-            }
-        }
-    }
-    
-    for (node = end.node(); node && !node->nextSibling(); node = node->parentNode()) {
-    }
-    if (node && isEmptyStyleSpan(node->nextSibling())) {
-        removeNodePreservingChildren(node->nextSibling());
-    }
-}
-
 void ApplyStyleCommand::surroundNodeRangeWithElement(Node *startNode, Node *endNode, Element *element)
 {
     ASSERT(startNode);
index e9342a838e4cb81b207549ab1560c6a2b97c0b74..e6506af8633e8fa5f6322f79c9e98def429f86cc 100644 (file)
@@ -73,7 +73,7 @@ private:
     bool splitTextElementAtEndIfNeeded(const Position& start, const Position& end);
     bool mergeStartWithPreviousIfIdentical(const Position& start, const Position& end);
     bool mergeEndWithNextIfIdentical(const Position& start, const Position& end);
-    void cleanUpEmptyStyleSpans(const Position& start, const Position& end);
+    void cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor);
 
     void surroundNodeRangeWithElement(Node* start, Node* end, Element* element);
     float computedFontSize(const Node*);
index 30643e5713691c6c4bfcbf4bb65bad2925d58402..b1a0901524e4d9a3ffaae6f29e32a2b61ca739de 100644 (file)
@@ -330,8 +330,14 @@ void ReplaceSelectionCommand::removeRedundantStyles()
             if (isStyleSpan(child.get())) {
                 HTMLElement* elem = static_cast<HTMLElement*>(child.get());
                 CSSMutableStyleDeclaration* inlineStyleDecl = elem->inlineStyleDecl();
-                inlineStyleDecl->merge(parentStyle.get(), false);
-                setNodeAttribute(elem, styleAttr, inlineStyleDecl->cssText());
+                // be defensive because we used to sometimes leave unstyled Apple style spans in the DOM,
+                // and we could be processing an old email with that flaw
+                if (!inlineStyleDecl)
+                    setNodeAttribute(elem, styleAttr, parentStyle->cssText());
+                else {
+                    inlineStyleDecl->merge(parentStyle.get(), false);
+                    setNodeAttribute(elem, styleAttr, inlineStyleDecl->cssText());
+                }
             } else if (node->isElementNode()) {
                 RefPtr<Node> clone = node->cloneNode(false);
                 int index = child->nodeIndex();
@@ -379,7 +385,7 @@ void ReplaceSelectionCommand::removeRedundantStyles()
         Node *node = it->first;
         
         // Remove empty style spans.
-        if (isStyleSpan(node) && !node->firstChild()) {
+        if (isStyleSpan(node) && !node->hasChildNodes()) {
             removeNodeAndPruneAncestors(node);
             continue;
         }
index 157e2ba5bdf20257aba20c76c12f31aa670712ab..0aef323d6aa7c5993f4d93dc5471104271677ab6 100644 (file)
@@ -47,10 +47,10 @@ void SplitTextNodeCommand::doApply()
 
     ExceptionCode ec = 0;
 
-    // EDIT FIXME: This should use better smarts for figuring out which portion
-    // of the split to copy (based on their comparitive sizes). We should also
-    // just use the DOM's splitText function.
-    
+    // NOTE: Various callers rely on the fact that the original node becomes
+    // the second node (i.e. the new node is inserted before the existing one).
+    // That is not a fundamental dependency (i.e. it could be re-coded), but
+    // rather is based on how this code happens to work.
     if (!m_text1) {
         // create only if needed.
         // if reapplying, this object will already exist.
index 51c1c49d571824025bd948b89b89862384872150..8ac3243f21478d382c50ec32d76abee04104b337 100644 (file)
@@ -28,6 +28,8 @@
 
 #include "Document.h"
 #include "Frame.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
 #include "InlineTextBox.h"
 #include "JSEditor.h"
 #include "RenderBR.h"
@@ -44,6 +46,8 @@
 
 namespace WebCore {
 
+using namespace HTMLNames;
+
 static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0);
 
 #ifndef SVG_SUPPORT
@@ -107,6 +111,22 @@ static DeprecatedString getTagName(Node *n)
     return n->nodeName().deprecatedString(); 
 }
 
+static bool isEmptyOrUnstyledAppleStyleSpan(const Node *node)
+{
+    if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag))
+        return false;
+
+    const HTMLElement *elem = static_cast<const HTMLElement *>(node);
+    if (elem->getAttribute(classAttr) != "Apple-style-span")
+        return false;
+    
+    if (!node->hasChildNodes())
+        return true;
+    
+    CSSMutableStyleDeclaration *inlineStyleDecl = elem->inlineStyleDecl();
+    return (!inlineStyleDecl || inlineStyleDecl->length() == 0);
+}
+
 static TextStream &operator<<(TextStream &ts, const RenderObject &o)
 {
     ts << o.renderName();
@@ -119,6 +139,10 @@ static TextStream &operator<<(TextStream &ts, const RenderObject &o)
         DeprecatedString tagName = getTagName(o.element());
         if (!tagName.isEmpty()) {
             ts << " {" << tagName << "}";
+            // flag empty or unstyled AppleStyleSpan because we never
+            // want to leave them in the DOM
+            if (isEmptyOrUnstyledAppleStyleSpan(o.element()))
+                ts << " *empty or unstyled AppleStyleSpan*";
         }
     }