LayoutTests:
authorjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Nov 2006 01:04:48 +0000 (01:04 +0000)
committerjusting <justing@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Nov 2006 01:04:48 +0000 (01:04 +0000)
        Reviewed by harrison

        <rdar://problem/4237467> REGRESSION: Pasting word from quoted text quotes the destination
        <rdar://problem/4017358> quoted text is wrong color, when pasted as quotation

        Fixed:
        * editing/pasteboard/merge-end-blockquote-expected.checksum:
        * editing/pasteboard/merge-end-blockquote-expected.png:
        * editing/pasteboard/merge-end-blockquote-expected.txt:
        * editing/pasteboard/merge-end-blockquote.html:

        Added:
        * editing/pasteboard/paste-blockquote-1-expected.checksum: Added.
        * editing/pasteboard/paste-blockquote-1-expected.png: Added.
        * editing/pasteboard/paste-blockquote-1-expected.txt: Added.
        * editing/pasteboard/paste-blockquote-1.html: Added.
        * editing/pasteboard/paste-blockquote-2-expected.checksum: Added.
        * editing/pasteboard/paste-blockquote-2-expected.png: Added.
        * editing/pasteboard/paste-blockquote-2-expected.txt: Added.
        * editing/pasteboard/paste-blockquote-2.html: Added.
        * editing/pasteboard/paste-blockquote-3-expected.checksum: Added.
        * editing/pasteboard/paste-blockquote-3-expected.png: Added.
        * editing/pasteboard/paste-blockquote-3-expected.txt: Added.
        * editing/pasteboard/paste-blockquote-3.html: Added.

WebCore:

        Reviewed by harrison

        <rdar://problem/4237467> REGRESSION: Pasting word from quoted text quotes the destination
        <rdar://problem/4017358> quoted text is wrong color, when pasted as quotation

        * editing/ReplaceSelectionCommand.cpp:
        (WebCore::isMailPasteAsQuotationNode): Added.  Checks for the node
        that Mail wraps around an incoming fragment when it wants it to be pasted
        with quoting (no merging should be done).
        (WebCore::ReplaceSelectionCommand::removeNodePreservingChildren): Added
        this virtual method in order to adjust the nodes that ReplaceSelectionCommand
        tracks.
        (WebCore::ReplaceSelectionCommand::shouldMerge): Don't merge from content
        inside a Mail Paste as Quotation node.  Allow merging from Mail blockquotes.
        (WebCore::ReplaceSelectionCommand::removeRedundantStyles): When pasting into
        a Mail blockquote, we ignore the parts of the source document's default style
        that are overriden by styles from the Mail blockquote.  This is necessary in order
        for text that's black (because black is the source document's default font color)
        to appear blue/green/whatever when it's pasted into a Mail blockquote.
        (WebCore::ReplaceSelectionCommand::handlePasteAsQuotationNode): Turn an inserted
        Mail Paste as Quotation node into a normal Mail blockquote.  This will prevent
        a copied blockquote that was inserted into the document using Paste as Quotation
        from triggering Paste as Quotation behavior when it's pasted.
        (WebCore::ReplaceSelectionCommand::doApply): Call the new/altered methods.
        * editing/ReplaceSelectionCommand.h:
        * editing/markup.cpp:
        (WebCore::styleFromMatchedRulesForElement): Put this code into a subroutine.
        (WebCore::removeEnclosingMailBlockquoteStyle): Added.
        (WebCore::startMarkup): When wrapping text nodes in style spans, leave out
        styles that Mail blockquotes contribute, so that Mail blockquote styles can
        be differentiated from styles that the user has applied.  When creating markup
        for elements, do the same thing.
        (WebCore::createMarkup): Call the new subroutine.

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

21 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/pasteboard/merge-end-blockquote-expected.checksum
LayoutTests/editing/pasteboard/merge-end-blockquote-expected.png
LayoutTests/editing/pasteboard/merge-end-blockquote-expected.txt
LayoutTests/editing/pasteboard/merge-end-blockquote.html
LayoutTests/editing/pasteboard/paste-blockquote-1-expected.checksum [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-1-expected.png [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-1-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-1.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-2-expected.checksum [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-2-expected.png [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-2-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-2.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-3-expected.checksum [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-3-expected.png [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-3-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/paste-blockquote-3.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/editing/ReplaceSelectionCommand.cpp
WebCore/editing/ReplaceSelectionCommand.h
WebCore/editing/markup.cpp

index ea61fb3..f8ea7eb 100644 (file)
@@ -1,3 +1,30 @@
+2006-11-17  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by harrison
+        
+        <rdar://problem/4237467> REGRESSION: Pasting word from quoted text quotes the destination
+        <rdar://problem/4017358> quoted text is wrong color, when pasted as quotation
+
+        Fixed:
+        * editing/pasteboard/merge-end-blockquote-expected.checksum:
+        * editing/pasteboard/merge-end-blockquote-expected.png:
+        * editing/pasteboard/merge-end-blockquote-expected.txt:
+        * editing/pasteboard/merge-end-blockquote.html:
+        
+        Added:
+        * editing/pasteboard/paste-blockquote-1-expected.checksum: Added.
+        * editing/pasteboard/paste-blockquote-1-expected.png: Added.
+        * editing/pasteboard/paste-blockquote-1-expected.txt: Added.
+        * editing/pasteboard/paste-blockquote-1.html: Added.
+        * editing/pasteboard/paste-blockquote-2-expected.checksum: Added.
+        * editing/pasteboard/paste-blockquote-2-expected.png: Added.
+        * editing/pasteboard/paste-blockquote-2-expected.txt: Added.
+        * editing/pasteboard/paste-blockquote-2.html: Added.
+        * editing/pasteboard/paste-blockquote-3-expected.checksum: Added.
+        * editing/pasteboard/paste-blockquote-3-expected.png: Added.
+        * editing/pasteboard/paste-blockquote-3-expected.txt: Added.
+        * editing/pasteboard/paste-blockquote-3.html: Added.
+
 2006-11-16  Rob Buis  <buis@kde.org>
 
         Reviewed and landed by Brady
index a5fffcf..ebe768c 100644 (file)
Binary files a/LayoutTests/editing/pasteboard/merge-end-blockquote-expected.png and b/LayoutTests/editing/pasteboard/merge-end-blockquote-expected.png differ
index aefaac0..e42f49e 100644 (file)
@@ -1,7 +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:range from 0 of #text > DIV > BODY > HTML > #document to 0 of #text > DIV > BODY > HTML > #document toDOMRange:range from 16 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document to 16 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 16 of #text > DIV > BODY > HTML > #document to 16 of #text > DIV > BODY > HTML > #document toDOMRange:range from 16 of #text > DIV > BODY > HTML > #document to 16 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 2 of DIV > BODY > HTML > #document
@@ -20,22 +20,20 @@ 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 784x18
-        RenderText {#text} at (0,0) size 597x18
-          text run at (0,0) width 597: "This tests pasting a Mail blockquote into a position that would normally result in an end merge."
-      RenderBlock {DIV} at (0,34) size 784x52
-        RenderBlock {BLOCKQUOTE} at (40,0) size 704x18
-          RenderBlock {DIV} at (0,0) size 704x18
-            RenderText {#text} at (0,0) size 114x18
-              text run at (0,0) width 114: "Blockquoted Text"
-        RenderBlock (anonymous) at (0,34) size 784x18
-          RenderText {#text} at (0,0) size 8x18
-            text run at (0,0) width 8: "x"
-      RenderBlock {P} at (0,102) size 784x36
+        RenderText {#text} at (0,0) size 606x18
+          text run at (0,0) width 397: "This tests pasting a Mail blockquote at the start of a paragraph. "
+          text run at (397,0) width 209: "Blockquoting should be stripped."
+      RenderBlock {DIV} at (0,34) size 784x18
+        RenderText {#text} at (0,0) size 114x18
+          text run at (0,0) width 114: "Blockquoted Text"
+        RenderText {#text} at (114,0) size 8x18
+          text run at (114,0) width 8: "x"
+      RenderBlock {P} at (0,68) size 784x36
         RenderText {#text} at (0,0) size 759x36
           text run at (0,0) width 289: "This tests pasting text into a Mail blockquote. "
           text run at (289,0) width 470: "The last bit of content in the incoming fragment should be merged with the"
           text run at (0,18) width 287: "paragraph after the position being pasted into."
-      RenderBlock {DIV} at (0,154) size 784x36
+      RenderBlock {DIV} at (0,120) size 784x36
         RenderBlock {BLOCKQUOTE} at (40,0) size 704x36
           RenderBlock {DIV} at (0,0) size 704x18
             RenderText {#text} at (0,0) size 81x18
index 09d6958..0698bd5 100644 (file)
@@ -2,7 +2,7 @@
 if (window.layoutTestController)
      layoutTestController.dumpEditingCallbacks();
 </script>
-<p>This tests pasting a Mail blockquote into a position that would normally result in an end merge.</p>
+<p>This tests pasting a Mail blockquote at the start of a paragraph.  Blockquoting should be stripped.</p>
 <div id="test1" contenteditable="true">x</div>
 
 <script type="text/javascript" src="../editing.js"></script>
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-1-expected.checksum b/LayoutTests/editing/pasteboard/paste-blockquote-1-expected.checksum
new file mode 100644 (file)
index 0000000..d68f73d
--- /dev/null
@@ -0,0 +1 @@
+f52fe7ca5b3b3e8fe1d198ad6d1a275f
\ No newline at end of file
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-1-expected.png b/LayoutTests/editing/pasteboard/paste-blockquote-1-expected.png
new file mode 100644 (file)
index 0000000..0e28bba
Binary files /dev/null and b/LayoutTests/editing/pasteboard/paste-blockquote-1-expected.png differ
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-1-expected.txt b/LayoutTests/editing/pasteboard/paste-blockquote-1-expected.txt
new file mode 100644 (file)
index 0000000..bb8788a
--- /dev/null
@@ -0,0 +1,13 @@
+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 354x18
+          text run at (0,0) width 354: "This tests pasting a blockquote into an empty paragraph."
+      RenderBlock {DIV} at (0,34) size 784x18
+        RenderBlock {BLOCKQUOTE} at (0,0) size 784x18 [color=#0000FF] [border: (2px solid #0000FF)]
+          RenderText {#text} at (22,0) size 179x18
+            text run at (22,0) width 179: "This should be blockquoted."
+caret: position 27 of child 0 {#text} of child 0 {BLOCKQUOTE} of child 2 {DIV} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-1.html b/LayoutTests/editing/pasteboard/paste-blockquote-1.html
new file mode 100644 (file)
index 0000000..5690fed
--- /dev/null
@@ -0,0 +1,19 @@
+<style>
+blockquote {
+    color: blue;
+    border-left: 2px solid blue;
+    margin: 0px;
+    padding: 0 0 0 20px;
+}
+</style>
+
+<p>This tests pasting a blockquote into an empty paragraph.</p>
+<div id="div" contenteditable="true"></div>
+
+<script>
+var sel = window.getSelection();
+var div = document.getElementById("div");
+
+sel.setPosition(div, 0);
+document.execCommand("InsertHTML", false, "<blockquote type='cite'>This should be blockquoted.</blockquote>");
+</script>
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-2-expected.checksum b/LayoutTests/editing/pasteboard/paste-blockquote-2-expected.checksum
new file mode 100644 (file)
index 0000000..8606140
--- /dev/null
@@ -0,0 +1 @@
+dd43c28115c2cdedd20809ff26199c39
\ No newline at end of file
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-2-expected.png b/LayoutTests/editing/pasteboard/paste-blockquote-2-expected.png
new file mode 100644 (file)
index 0000000..d74714a
Binary files /dev/null and b/LayoutTests/editing/pasteboard/paste-blockquote-2-expected.png differ
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-2-expected.txt b/LayoutTests/editing/pasteboard/paste-blockquote-2-expected.txt
new file mode 100644 (file)
index 0000000..d0be1b8
--- /dev/null
@@ -0,0 +1,14 @@
+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 360x18
+          text run at (0,0) width 360: "This tests pasting a blockquote at the start of a paragraph."
+      RenderBlock {DIV} at (0,34) size 784x18
+        RenderText {#text} at (0,0) size 203x18
+          text run at (0,0) width 203: "This should not be blockquoted."
+        RenderText {#text} at (203,0) size 207x18
+          text run at (203,0) width 207: " This should not be blockquoted."
+caret: position 31 of child 0 {#text} of child 2 {DIV} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-2.html b/LayoutTests/editing/pasteboard/paste-blockquote-2.html
new file mode 100644 (file)
index 0000000..eb631ef
--- /dev/null
@@ -0,0 +1,19 @@
+<style>
+blockquote {
+    color: blue;
+    border-left: 2px solid blue;
+    margin: 0px;
+    padding: 0 0 0 20px;
+}
+</style>
+
+<p>This tests pasting a blockquote at the start of a paragraph.</p>
+<div id="div" contenteditable="true">&nbsp;This should not be blockquoted.</div>
+
+<script>
+var sel = window.getSelection();
+var div = document.getElementById("div");
+
+sel.setPosition(div, 0);
+document.execCommand("InsertHTML", false, "<blockquote type='cite'>This should not be blockquoted.</blockquote>");
+</script>
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-3-expected.checksum b/LayoutTests/editing/pasteboard/paste-blockquote-3-expected.checksum
new file mode 100644 (file)
index 0000000..a6e9fbc
--- /dev/null
@@ -0,0 +1 @@
+b9e381e60a79b5781cc29a605ba5f6d5
\ No newline at end of file
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-3-expected.png b/LayoutTests/editing/pasteboard/paste-blockquote-3-expected.png
new file mode 100644 (file)
index 0000000..bd9b1bf
Binary files /dev/null and b/LayoutTests/editing/pasteboard/paste-blockquote-3-expected.png differ
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-3-expected.txt b/LayoutTests/editing/pasteboard/paste-blockquote-3-expected.txt
new file mode 100644 (file)
index 0000000..544b719
--- /dev/null
@@ -0,0 +1,24 @@
+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 390x18
+          text run at (0,0) width 390: "This tests pasting a blockquote into the middle of a paragraph."
+      RenderBlock {DIV} at (0,34) size 784x54
+        RenderBlock (anonymous) at (0,0) size 784x18
+          RenderText {#text} at (0,0) size 203x18
+            text run at (0,0) width 203: "This should not be blockquoted."
+          RenderText {#text} at (203,0) size 207x18
+            text run at (203,0) width 207: " This should not be blockquoted."
+        RenderBlock {BLOCKQUOTE} at (0,18) size 784x18 [color=#0000FF] [border: (2px solid #0000FF)]
+          RenderText {#text} at (22,0) size 179x18
+            text run at (22,0) width 179: "This should be blockquoted."
+          RenderBR {BR} at (201,14) size 0x0
+        RenderBlock (anonymous) at (0,36) size 784x18
+          RenderText {#text} at (0,0) size 203x18
+            text run at (0,0) width 203: "This should not be blockquoted."
+          RenderText {#text} at (203,0) size 207x18
+            text run at (203,0) width 207: " This should not be blockquoted."
+caret: position 31 of child 3 {#text} of child 2 {DIV} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/editing/pasteboard/paste-blockquote-3.html b/LayoutTests/editing/pasteboard/paste-blockquote-3.html
new file mode 100644 (file)
index 0000000..15ebccb
--- /dev/null
@@ -0,0 +1,25 @@
+<style>
+blockquote {
+    color: blue;
+    border-left: 2px solid blue;
+    margin: 0px;
+    padding: 0 0 0 20px;
+}
+</style>
+
+<p>This tests pasting a blockquote into the middle of a paragraph.</p>
+<div id="div" contenteditable="true">This should not be blockquoted. This should not be blockquoted.</div>
+
+<script>
+var sel = window.getSelection();
+var div = document.getElementById("div");
+
+sel.setPosition(div, 0);
+sel.modify("move", "forward", "word");
+sel.modify("move", "forward", "word");
+sel.modify("move", "forward", "word");
+sel.modify("move", "forward", "word");
+sel.modify("move", "forward", "word");
+sel.modify("move", "forward", "character");
+document.execCommand("InsertHTML", false, "<blockquote type='cite'>&nbsp;This should not be blockquoted.<br>This should be blockquoted.<br>This should not be blockquoted.</blockquote>");
+</script>
index 2a0f8fd..9470ac5 100644 (file)
@@ -1,3 +1,39 @@
+2006-11-17  Justin Garcia  <justin.garcia@apple.com>
+
+        Reviewed by harrison
+        
+        <rdar://problem/4237467> REGRESSION: Pasting word from quoted text quotes the destination
+        <rdar://problem/4017358> quoted text is wrong color, when pasted as quotation
+
+        * editing/ReplaceSelectionCommand.cpp:
+        (WebCore::isMailPasteAsQuotationNode): Added.  Checks for the node
+        that Mail wraps around an incoming fragment when it wants it to be pasted
+        with quoting (no merging should be done).
+        (WebCore::ReplaceSelectionCommand::removeNodePreservingChildren): Added
+        this virtual method in order to adjust the nodes that ReplaceSelectionCommand
+        tracks.
+        (WebCore::ReplaceSelectionCommand::shouldMerge): Don't merge from content
+        inside a Mail Paste as Quotation node.  Allow merging from Mail blockquotes.
+        (WebCore::ReplaceSelectionCommand::removeRedundantStyles): When pasting into
+        a Mail blockquote, we ignore the parts of the source document's default style
+        that are overriden by styles from the Mail blockquote.  This is necessary in order
+        for text that's black (because black is the source document's default font color) 
+        to appear blue/green/whatever when it's pasted into a Mail blockquote.
+        (WebCore::ReplaceSelectionCommand::handlePasteAsQuotationNode): Turn an inserted
+        Mail Paste as Quotation node into a normal Mail blockquote.  This will prevent
+        a copied blockquote that was inserted into the document using Paste as Quotation
+        from triggering Paste as Quotation behavior when it's pasted.
+        (WebCore::ReplaceSelectionCommand::doApply): Call the new/altered methods.
+        * editing/ReplaceSelectionCommand.h:
+        * editing/markup.cpp:
+        (WebCore::styleFromMatchedRulesForElement): Put this code into a subroutine.
+        (WebCore::removeEnclosingMailBlockquoteStyle): Added.
+        (WebCore::startMarkup): When wrapping text nodes in style spans, leave out
+        styles that Mail blockquotes contribute, so that Mail blockquote styles can
+        be differentiated from styles that the user has applied.  When creating markup
+        for elements, do the same thing.
+        (WebCore::createMarkup): Call the new subroutine.
+
 2006-11-17  Rob Buis  <buis@kde.org>
 
         Reviewed by Mitz.
index 5c6799c..2d4563c 100644 (file)
@@ -312,6 +312,21 @@ bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
            shouldMerge(endOfInsertedContent, next);
 }
 
+static bool isMailPasteAsQuotationNode(Node* node)
+{
+    return node && node->hasTagName(blockquoteTag) && node->isElementNode() && static_cast<Element*>(node)->getAttribute(classAttr) == ApplePasteAsQuotation;
+}
+
+// Virtual method used so that ReplaceSelectionCommand can update the node's it tracks.
+void ReplaceSelectionCommand::removeNodePreservingChildren(Node* node)
+{
+    if (m_firstNodeInserted == node)
+        m_firstNodeInserted = node->traverseNextNode();
+    if (m_lastNodeInserted == node)
+        m_lastNodeInserted = node->lastChild() ? node->lastChild() : node->traverseNextSibling();
+    CompositeEditCommand::removeNodePreservingChildren(node);
+}
+
 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& from, const VisiblePosition& to)
 {
     if (from.isNull() || to.isNull())
@@ -320,8 +335,8 @@ bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& from, const Vis
     Node* fromNode = from.deepEquivalent().node();
     Node* toNode = to.deepEquivalent().node();
     
-    return nearestMailBlockquote(fromNode) == nearestMailBlockquote(toNode) &&
-           !enclosingBlock(fromNode)->hasTagName(blockquoteTag) &&
+    return !enclosingNodeOfType(fromNode, &isMailPasteAsQuotationNode) &&
+           (!enclosingBlock(fromNode)->hasTagName(blockquoteTag) || isMailBlockquote(enclosingBlock(fromNode)))  &&
            enclosingListChild(fromNode) == enclosingListChild(toNode) &&
            enclosingTableCell(fromNode) == enclosingTableCell(toNode) &&
            !(fromNode->renderer() && fromNode->renderer()->isTable()) &&
@@ -329,11 +344,18 @@ bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& from, const Vis
            !fromNode->hasTagName(hrTag) && !toNode->hasTagName(hrTag);
 }
 
-void ReplaceSelectionCommand::removeRedundantStyles()
+void ReplaceSelectionCommand::removeRedundantStyles(Node* mailBlockquoteEnclosingSelectionStart)
 {
     // There's usually a top level style span that holds the document's default style, push it down.
     Node* node = m_firstNodeInserted.get();
-    if (isStyleSpan(node)) {
+    if (isStyleSpan(node) && mailBlockquoteEnclosingSelectionStart) {
+        // Calculate the document default style.
+        RefPtr<CSSMutableStyleDeclaration> blockquoteStyle = Position(mailBlockquoteEnclosingSelectionStart, 0).computedStyle()->copyInheritableProperties();
+        RefPtr<CSSMutableStyleDeclaration> spanStyle = static_cast<HTMLElement*>(node)->inlineStyleDecl();
+        spanStyle->merge(blockquoteStyle.get());  
+    }
+    else if (isStyleSpan(node)) {
+    
         RefPtr<CSSMutableStyleDeclaration> parentStyle
             = Position(node, 0).computedStyle()->copyInheritableProperties();
 
@@ -360,11 +382,7 @@ void ReplaceSelectionCommand::removeRedundantStyles()
             }
             child = next;
         }
-
-        if (m_firstNodeInserted == node)
-            m_firstNodeInserted = node->firstChild();
-        if (m_lastNodeInserted == node)
-            m_lastNodeInserted = node->lastChild();
+        
         removeNodePreservingChildren(node);
     }
     
@@ -411,10 +429,6 @@ void ReplaceSelectionCommand::removeRedundantStyles()
                     || element->hasTagName(fontTag)
                     || element->hasTagName(iTag)
                     || element->hasTagName(uTag))) {
-            if (element == m_firstNodeInserted)
-                m_firstNodeInserted = element->traverseNextNode();
-            if (element == m_lastNodeInserted)
-                m_lastNodeInserted = element->traverseNextNode();
             removeNodePreservingChildren(element);
             continue;
         }
@@ -429,6 +443,13 @@ void ReplaceSelectionCommand::removeRedundantStyles()
     }
 }
 
+void ReplaceSelectionCommand::handlePasteAsQuotationNode()
+{
+    Node* node = m_firstNodeInserted.get();
+    if (isMailPasteAsQuotationNode(node))
+        static_cast<Element*>(node)->setAttribute(classAttr, "");
+}
+
 void ReplaceSelectionCommand::doApply()
 {
     Selection selection = endingSelection();
@@ -454,6 +475,7 @@ void ReplaceSelectionCommand::doApply()
     
     bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
     bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);
+    Node* mailBlockquoteEnclosingSelectionStart = nearestMailBlockquote(visibleStart.deepEquivalent().node());
     
     Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().node());
     
@@ -567,7 +589,7 @@ void ReplaceSelectionCommand::doApply()
         node = next;
     }
     
-    removeRedundantStyles();
+    removeRedundantStyles(mailBlockquoteEnclosingSelectionStart);
     
     endOfInsertedContent = VisiblePosition(Position(m_lastNodeInserted.get(), maxDeepOffset(m_lastNodeInserted.get())));
     startOfInsertedContent = VisiblePosition(Position(m_firstNodeInserted.get(), 0));
@@ -651,6 +673,8 @@ void ReplaceSelectionCommand::doApply()
         }
     }
     
+    handlePasteAsQuotationNode();
+    
     endOfInsertedContent = VisiblePosition(Position(m_lastNodeInserted.get(), maxDeepOffset(m_lastNodeInserted.get())));
     startOfInsertedContent = VisiblePosition(Position(m_firstNodeInserted.get(), 0));    
     
index a6b7089..f14fdd8 100644 (file)
@@ -89,7 +89,11 @@ private:
     bool shouldMergeEnd(bool);
     bool shouldMerge(const VisiblePosition&, const VisiblePosition&);
     
-    void removeRedundantStyles();
+    void removeRedundantStyles(Node*);
+    
+    void handlePasteAsQuotationNode();
+    
+    virtual void removeNodePreservingChildren(Node*);
 
     RefPtr<Node> m_firstNodeInserted;
     RefPtr<Node> m_lastNodeInserted;
index 7427f8c..8a7bff5 100644 (file)
@@ -118,6 +118,34 @@ static DeprecatedString renderedText(const Node *node, const Range *range)
     return plainText(&r);
 }
 
+static PassRefPtr<CSSMutableStyleDeclaration> styleFromMatchedRulesForElement(Element* element, bool authorOnly = true)
+{
+    RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration();
+    RefPtr<CSSRuleList> matchedRules = element->document()->styleSelector()->styleRulesForElement(element, authorOnly);
+    if (matchedRules) {
+        for (unsigned i = 0; i < matchedRules->length(); i++) {
+            if (matchedRules->item(i)->type() == CSSRule::STYLE_RULE) {
+                RefPtr<CSSMutableStyleDeclaration> s = static_cast<CSSStyleRule*>(matchedRules->item(i))->style();
+                style->merge(s.get(), true);
+            }
+        }
+    }
+    
+    return style.release();
+}
+
+static void removeEnclosingMailBlockquoteStyle(CSSMutableStyleDeclaration* style, Node* node)
+{
+    Node* blockquote = nearestMailBlockquote(node);
+    if (!blockquote || !blockquote->parentNode())
+        return;
+            
+    RefPtr<CSSMutableStyleDeclaration> parentStyle = Position(blockquote->parentNode(), 0).computedStyle()->copyInheritableProperties();
+    RefPtr<CSSMutableStyleDeclaration> blockquoteStyle = Position(blockquote, 0).computedStyle()->copyInheritableProperties();
+    parentStyle->diff(blockquoteStyle.get());
+    blockquoteStyle->diff(style);
+}
+
 static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnotateForInterchange annotate, CSSMutableStyleDeclaration *defaultStyle)
 {
     bool documentIsHTML = node->document()->isHTMLDocument();
@@ -140,6 +168,11 @@ static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnot
                 if (element) {
                     RefPtr<CSSComputedStyleDeclaration> computedStyle = Position(element, 0).computedStyle();
                     RefPtr<CSSMutableStyleDeclaration> style = computedStyle->copyInheritableProperties();
+                    // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote, to help
+                    // us differentiate those styles from ones that the user has applied.  This helps us
+                    // get the color of content pasted into blockquotes right.
+                    removeEnclosingMailBlockquoteStyle(style.get(), const_cast<Node*>(node));
+                    
                     defaultStyle->diff(style.get());
                     if (style->length() > 0) {
                         // FIXME: Handle case where style->cssText() has illegal characters in it, like "
@@ -170,18 +203,16 @@ static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnot
             const Element* el = static_cast<const Element*>(node);
             markup += el->nodeNamePreservingCase().deprecatedString();
             String additionalStyle;
-            if (defaultStyle && el->isHTMLElement()) {
+            if (defaultStyle && el->isHTMLElement() && !isMailBlockquote(node)) {
                 RefPtr<CSSComputedStyleDeclaration> computedStyle = Position(const_cast<Element*>(el), 0).computedStyle();
                 RefPtr<CSSMutableStyleDeclaration> style = computedStyle->copyInheritableProperties();
-                RefPtr<CSSRuleList> matchedRules = node->document()->styleSelector()->styleRulesForElement(const_cast<Element*>(el), true);
-                if (matchedRules) {
-                    for (unsigned i = 0; i < matchedRules->length(); i++) {
-                        if (matchedRules->item(i)->type() == CSSRule::STYLE_RULE) {
-                            RefPtr<CSSMutableStyleDeclaration> s = static_cast<CSSStyleRule*>(matchedRules->item(i))->style();
-                            style->merge(s.get(), true);
-                        }
-                    }
-                }
+                style->merge(styleFromMatchedRulesForElement(const_cast<Element*>(el)).get());
+                
+                // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote, to help
+                // us differentiate those styles from ones that the user has applied.  This helps us
+                // get the color of content pasted into blockquotes right.
+                removeEnclosingMailBlockquoteStyle(style.get(), const_cast<Node*>(node));
+                
                 defaultStyle->diff(style.get());
                 if (style->length() > 0) {
                     CSSMutableStyleDeclaration *inlineStyleDecl = static_cast<const HTMLElement*>(el)->inlineStyleDecl();
@@ -497,15 +528,8 @@ DeprecatedString createMarkup(const Range *range, Vector<Node*>* nodes, EAnnotat
     if (root && *Selection::selectionFromContentsOfNode(root).toRange() == *range) {
         CSSMutableStyleDeclaration* inlineStyleDecl = static_cast<HTMLElement*>(root)->inlineStyleDecl();
         RefPtr<CSSMutableStyleDeclaration> style = inlineStyleDecl ? inlineStyleDecl->copy() : new CSSMutableStyleDeclaration();
-        RefPtr<CSSRuleList> matchedRules = root->document()->styleSelector()->styleRulesForElement(static_cast<Element*>(root), true);
-        if (matchedRules) {
-            for (unsigned i = 0; i < matchedRules->length(); i++) {
-                if (matchedRules->item(i)->type() == CSSRule::STYLE_RULE) {
-                    RefPtr<CSSMutableStyleDeclaration> s = static_cast<CSSStyleRule*>(matchedRules->item(i))->style();
-                    style->merge(s.get(), true);
-                }
-            }
-        }
+        style->merge(styleFromMatchedRulesForElement(static_cast<Element*>(root)).get());
+        
         defaultStyle->diff(style.get());
         
         // Bring the background attribute over, but not as an attribute because a background attribute on a div