Diff
Modified: trunk/LayoutTests/ChangeLog (98898 => 98899)
--- trunk/LayoutTests/ChangeLog 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/ChangeLog 2011-10-31 23:09:12 UTC (rev 98899)
@@ -1,3 +1,26 @@
+2011-10-29 Ryosuke Niwa <[email protected]>
+
+ WebKit nests pre on copy and paste when the pre is the root editable element
+ https://bugs.webkit.org/show_bug.cgi?id=70800
+
+ Reviewed by Darin Adler.
+
+ Added tests for copying and pasting contents inside pre. WebKit should not nest pre's.
+
+ * editing/execCommand/insert-list-with-noneditable-content-expected.txt: A redundant
+ contenteditable attribute is removed.
+ * editing/pasteboard/4930986-2-expected.txt: Trailing space in style attribute is removed.
+ * editing/pasteboard/contenteditable-pre-2-expected.txt: Added.
+ * editing/pasteboard/contenteditable-pre-2.html: Added.
+ * editing/pasteboard/contenteditable-pre-expected.txt: Added.
+ * editing/pasteboard/contenteditable-pre.html: Added.
+ * editing/pasteboard/copy-null-characters-expected.txt: A redundant contenteditable attribute
+ is removed.
+ * editing/pasteboard/paste-code-in-pre-expected.txt: Pre no longer nests itself erroneously.
+ * editing/pasteboard/paste-pre-001-expected.txt: Ditto.
+ * editing/pasteboard/paste-pre-002-expected.txt: Ditto.
+ * editing/selection/4895428-4-expected.txt: A redundant contenteditable attribute is removed.
+
2011-10-31 Vineet Chaudhary <[email protected]>
text/plain form encoding ignored and incorrectly specified in request header.
Modified: trunk/LayoutTests/editing/execCommand/insert-list-with-noneditable-content-expected.txt (98898 => 98899)
--- trunk/LayoutTests/editing/execCommand/insert-list-with-noneditable-content-expected.txt 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/editing/execCommand/insert-list-with-noneditable-content-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -3,7 +3,6 @@
| <li>
| "Editabl<#selection-anchor>e paragraph containing a "
| <span>
-| contenteditable="false"
| style="background-color: rgb(211, 211, 211); "
| "non-editable"
| " in the middle"
Modified: trunk/LayoutTests/editing/pasteboard/4930986-2-expected.txt (98898 => 98899)
--- trunk/LayoutTests/editing/pasteboard/4930986-2-expected.txt 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/editing/pasteboard/4930986-2-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -1,2 +1,2 @@
This tests to make sure that content that is colored by the user is pasted with that color during a Paste as Quotation.
-<blockquote><span class="Apple-style-span" style="color: red; ">This text should be red (it should be wrapped in a style span).</span></blockquote>
+<blockquote><span class="Apple-style-span" style="color: red;">This text should be red (it should be wrapped in a style span).</span></blockquote>
Added: trunk/LayoutTests/editing/pasteboard/contenteditable-pre-2-expected.txt (0 => 98899)
--- trunk/LayoutTests/editing/pasteboard/contenteditable-pre-2-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/contenteditable-pre-2-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -0,0 +1,14 @@
+This test copies and pastes content inside pre that is an editing host. WebKit should not clone pre.
+To manually test, cut and paste "hello\nworld" WebKit should not nest pre (no red borders).
+
+Before cut paste:
+| <pre>
+| "<#selection-anchor>hello"
+| <br>
+| "world<#selection-focus>"
+
+After cut paste:
+| <pre>
+| "hello"
+| <br>
+| "world<#selection-caret>"
Added: trunk/LayoutTests/editing/pasteboard/contenteditable-pre-2.html (0 => 98899)
--- trunk/LayoutTests/editing/pasteboard/contenteditable-pre-2.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/contenteditable-pre-2.html 2011-10-31 23:09:12 UTC (rev 98899)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p id="description">This test copies and pastes content inside pre that is an editing host. WebKit should not clone pre.
+To manually test, cut and paste "hello\nworld" WebKit should not nest pre (no red borders).</p>
+<style> body > *[contenteditable] {border: solid 2px blue;} pre > pre, div > pre {border: solid 2px red;} </style>
+<div contenteditable><pre>hello<br>world</pre></div>
+<script src=""
+<script>
+
+Markup.description(document.getElementById('description').textContent);
+
+var container = document.querySelector('div');
+container.focus();
+document.execCommand('selectAll', false, null);
+
+Markup.dump(container, 'Before cut paste');
+
+document.execCommand('cut', false, null);
+document.execCommand('paste', false, null);
+
+Markup.dump(container, 'After cut paste');
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/editing/pasteboard/contenteditable-pre-expected.txt (0 => 98899)
--- trunk/LayoutTests/editing/pasteboard/contenteditable-pre-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/contenteditable-pre-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -0,0 +1,10 @@
+This test copies and pastes content inside pre that is an editing host. WebKit should not clone pre.
+To manually test, copy and paste "hello" and then paste it into the boxes below.
+WebKit should not clone pre (nest pre) and the pasted content should not have nested borders.
+
+Pasting into pre; the pre should not be listed below:
+| "hello<#selection-caret>"
+
+Pasting into div; the pasted content should be in pre:
+| <pre>
+| "hello<#selection-caret>"
Added: trunk/LayoutTests/editing/pasteboard/contenteditable-pre.html (0 => 98899)
--- trunk/LayoutTests/editing/pasteboard/contenteditable-pre.html (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/contenteditable-pre.html 2011-10-31 23:09:12 UTC (rev 98899)
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p id="description">This test copies and pastes content inside pre that is an editing host. WebKit should not clone pre.
+To manually test, copy and paste "hello" and then paste it into the boxes below.
+WebKit should not clone pre (nest pre) and the pasted content should not have nested borders.</p>
+<style> #container pre, #container div {border: solid 2px blue;} </style>
+<div id="container">
+<pre contenteditable>hello</pre>
+<div contenteditable></div>
+</div>
+<script src=""
+<script>
+
+Markup.description(document.getElementById('description').textContent);
+
+var container = document.querySelector('#container pre');
+container.focus();
+document.execCommand('selectAll', false, null);
+document.execCommand('copy', false, null);
+document.execCommand('paste', false, null);
+
+Markup.dump(container, "Pasting into pre; the pre should not be listed below");
+
+var container = document.querySelector('#container div');
+container.focus();
+document.execCommand('paste', false, null);
+
+Markup.dump(container, "Pasting into div; the pasted content should be in pre");
+
+</script>
+</body>
+</html>
Modified: trunk/LayoutTests/editing/pasteboard/copy-null-characters-expected.txt (98898 => 98899)
--- trunk/LayoutTests/editing/pasteboard/copy-null-characters-expected.txt 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/editing/pasteboard/copy-null-characters-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -24,7 +24,6 @@
| <b>
| "bold"
| <div>
-| contenteditable="true"
| id="source"
| "Copy paste me"
| <span>
Modified: trunk/LayoutTests/editing/pasteboard/paste-code-in-pre-expected.txt (98898 => 98899)
--- trunk/LayoutTests/editing/pasteboard/paste-code-in-pre-expected.txt 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/editing/pasteboard/paste-code-in-pre-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -3,7 +3,4 @@
| <pre>
| contenteditable="true"
| id="pre"
-| <pre>
-| contenteditable="true"
-| id="pre"
-| "<input type='button'>foo<br>bar<b>baz</b><#selection-caret>"
+| "<input type='button'>foo<br>bar<b>baz</b><#selection-caret>"
Modified: trunk/LayoutTests/editing/pasteboard/paste-pre-001-expected.txt (98898 => 98899)
--- trunk/LayoutTests/editing/pasteboard/paste-pre-001-expected.txt 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/editing/pasteboard/paste-pre-001-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -7,4 +7,4 @@
foo
bar
execCutCommand: <div id="test" class="editing"> <pre><br></pre> </div>
-execPasteCommand: <div id="test" class="editing"> <pre><pre>foo bar</pre></pre> </div>
+execPasteCommand: <div id="test" class="editing"> <pre>foo bar</pre> </div>
Modified: trunk/LayoutTests/editing/pasteboard/paste-pre-002-expected.txt (98898 => 98899)
--- trunk/LayoutTests/editing/pasteboard/paste-pre-002-expected.txt 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/editing/pasteboard/paste-pre-002-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -2,4 +2,4 @@
foo
bar
execCopyCommand: <div id="test" class="editing"> <pre>foo bar</pre> </div>
-execPasteCommand: <div id="test" class="editing"> <pre><pre>foo bar</pre></pre> </div>
+execPasteCommand: <div id="test" class="editing"> <pre>foo bar</pre> </div>
Modified: trunk/LayoutTests/editing/selection/4895428-4-expected.txt (98898 => 98899)
--- trunk/LayoutTests/editing/selection/4895428-4-expected.txt 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/LayoutTests/editing/selection/4895428-4-expected.txt 2011-10-31 23:09:12 UTC (rev 98899)
@@ -19,7 +19,6 @@
| <#selection-anchor>
| <table>
| border="1"
-| contenteditable="false"
| <tbody>
| <tr>
| <td>
Modified: trunk/Source/WebCore/ChangeLog (98898 => 98899)
--- trunk/Source/WebCore/ChangeLog 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/Source/WebCore/ChangeLog 2011-10-31 23:09:12 UTC (rev 98899)
@@ -1,3 +1,28 @@
+2011-10-29 Ryosuke Niwa <[email protected]>
+
+ WebKit nests pre on copy and paste when the pre is the root editable element
+ https://bugs.webkit.org/show_bug.cgi?id=70800
+
+ Reviewed by Darin Adler.
+
+ Fixed the bug by removing nested block elements in removeRedundantStylesAndKeepStyleSpanInline.
+
+ Tests: editing/pasteboard/contenteditable-pre-2.html
+ editing/pasteboard/contenteditable-pre.html
+
+ * editing/ApplyStyleCommand.cpp:
+ * editing/ReplaceSelectionCommand.cpp:
+ (WebCore::ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline): Remove block
+ elements if it's identical to its parent and there are no contents between the two. Also remove
+ contenteditable attribute from an element if the parent is already richly editable.
+ (WebCore::ReplaceSelectionCommand::doApply): Remove redundant styles after removing the placeholder
+ br so that the above check doesn't get affected by the placeholder.
+ * editing/htmlediting.cpp:
+ (WebCore::areIdenticalElements): Moved from ApplyStyleCommand.
+ (WebCore::isNonTableCellHTMLBlockElement): Moved from markup.cpp.
+ * editing/htmlediting.h:
+ * editing/markup.cpp:
+
2011-10-31 Vineet Chaudhary <[email protected]>
text/plain form encoding ignored and incorrectly specified in request header.
Modified: trunk/Source/WebCore/editing/ApplyStyleCommand.cpp (98898 => 98899)
--- trunk/Source/WebCore/editing/ApplyStyleCommand.cpp 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/Source/WebCore/editing/ApplyStyleCommand.cpp 2011-10-31 23:09:12 UTC (rev 98899)
@@ -1188,41 +1188,6 @@
return offsetInText > caretMinOffset(node) && offsetInText < caretMaxOffset(node);
}
-static bool areIdenticalElements(Node *first, Node *second)
-{
- // check that tag name and all attribute names and values are identical
-
- if (!first->isElementNode())
- return false;
-
- if (!second->isElementNode())
- return false;
-
- Element *firstElement = static_cast<Element *>(first);
- Element *secondElement = static_cast<Element *>(second);
-
- if (!firstElement->tagQName().matches(secondElement->tagQName()))
- return false;
-
- NamedNodeMap *firstMap = firstElement->attributes();
- NamedNodeMap *secondMap = secondElement->attributes();
-
- unsigned firstLength = firstMap->length();
-
- if (firstLength != secondMap->length())
- return false;
-
- for (unsigned i = 0; i < firstLength; i++) {
- Attribute *attribute = firstMap->attributeItem(i);
- Attribute *secondAttribute = secondMap->getAttributeItem(attribute->name());
-
- if (!secondAttribute || attribute->value() != secondAttribute->value())
- return false;
- }
-
- return true;
-}
-
bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position& start, const Position& end)
{
Node* startNode = start.containerNode();
Modified: trunk/Source/WebCore/editing/ReplaceSelectionCommand.cpp (98898 => 98899)
--- trunk/Source/WebCore/editing/ReplaceSelectionCommand.cpp 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/Source/WebCore/editing/ReplaceSelectionCommand.cpp 2011-10-31 23:09:12 UTC (rev 98899)
@@ -512,11 +512,24 @@
if (isStyleSpanOrSpanWithOnlyStyleAttribute(element)) {
insertedNodes.willRemoveNodePreservingChildren(element);
removeNodePreservingChildren(element);
+ continue;
} else
removeNodeAttribute(element, styleAttr);
} else if (newInlineStyle->style()->length() != inlineStyle->length())
setNodeAttribute(element, styleAttr, newInlineStyle->style()->cssText());
+ // FIXME: Tolerate differences in id, class, and style attributes.
+ if (isNonTableCellHTMLBlockElement(element) && areIdenticalElements(element, element->parentNode())
+ && VisiblePosition(firstPositionInNode(element->parentNode())) == VisiblePosition(firstPositionInNode(element))
+ && VisiblePosition(lastPositionInNode(element->parentNode())) == VisiblePosition(lastPositionInNode(element))) {
+ insertedNodes.willRemoveNodePreservingChildren(element);
+ removeNodePreservingChildren(element);
+ continue;
+ }
+
+ if (element->parentNode()->rendererIsRichlyEditable())
+ removeNodeAttribute(element, contenteditableAttr);
+
// WebKit used to not add display: inline and float: none on copy.
// Keep this code around for backward compatibility
if (isLegacyAppleStyleSpan(element)) {
@@ -976,8 +989,6 @@
node = next;
}
- removeRedundantStylesAndKeepStyleSpanInline(insertedNodes);
-
removeUnrenderedTextNodesAtEnds(insertedNodes);
if (!handledStyleSpans)
@@ -1004,6 +1015,8 @@
}
}
+ removeRedundantStylesAndKeepStyleSpanInline(insertedNodes);
+
// Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be the last two lines of code that access insertedNodes.
m_startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted());
m_endOfInsertedContent = lastPositionInOrAfterNode(insertedNodes.lastLeafInserted());
Modified: trunk/Source/WebCore/editing/htmlediting.cpp (98898 => 98899)
--- trunk/Source/WebCore/editing/htmlediting.cpp 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/Source/WebCore/editing/htmlediting.cpp 2011-10-31 23:09:12 UTC (rev 98899)
@@ -1140,6 +1140,48 @@
return renderer && ((renderer->isTable() && !renderer->isInline()) || (renderer->isImage() && !renderer->isInline()) || renderer->isHR());
}
+bool areIdenticalElements(const Node* first, const Node* second)
+{
+ // check that tag name and all attribute names and values are identical
+
+ if (!first->isElementNode() || !second->isElementNode())
+ return false;
+
+ if (!toElement(first)->tagQName().matches(toElement(second)->tagQName()))
+ return false;
+
+ NamedNodeMap* firstMap = toElement(first)->attributes();
+ NamedNodeMap* secondMap = toElement(second)->attributes();
+ unsigned firstLength = firstMap->length();
+
+ if (firstLength != secondMap->length())
+ return false;
+
+ for (unsigned i = 0; i < firstLength; i++) {
+ Attribute* attribute = firstMap->attributeItem(i);
+ Attribute* secondAttribute = secondMap->getAttributeItem(attribute->name());
+ if (!secondAttribute || attribute->value() != secondAttribute->value())
+ return false;
+ }
+
+ return true;
+}
+
+bool isNonTableCellHTMLBlockElement(const Node* node)
+{
+ return node->hasTagName(listingTag)
+ || node->hasTagName(olTag)
+ || node->hasTagName(preTag)
+ || node->hasTagName(tableTag)
+ || node->hasTagName(ulTag)
+ || node->hasTagName(xmpTag)
+ || node->hasTagName(h1Tag)
+ || node->hasTagName(h2Tag)
+ || node->hasTagName(h3Tag)
+ || node->hasTagName(h4Tag)
+ || node->hasTagName(h5Tag);
+}
+
PassRefPtr<Range> avoidIntersectionWithNode(const Range* range, Node* node)
{
if (!range)
Modified: trunk/Source/WebCore/editing/htmlediting.h (98898 => 98899)
--- trunk/Source/WebCore/editing/htmlediting.h 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/Source/WebCore/editing/htmlediting.h 2011-10-31 23:09:12 UTC (rev 98899)
@@ -109,7 +109,8 @@
bool isNodeRendered(const Node*);
bool isNodeVisiblyContainedWithin(Node*, const Range*);
bool isRenderedAsNonInlineTableImageOrHR(const Node*);
-
+bool areIdenticalElements(const Node*, const Node*);
+bool isNonTableCellHTMLBlockElement(const Node*);
TextDirection directionOfEnclosingBlock(const Position&);
// -------------------------------------------------------------------------
Modified: trunk/Source/WebCore/editing/markup.cpp (98898 => 98899)
--- trunk/Source/WebCore/editing/markup.cpp 2011-10-31 23:08:28 UTC (rev 98898)
+++ trunk/Source/WebCore/editing/markup.cpp 2011-10-31 23:09:12 UTC (rev 98899)
@@ -427,21 +427,6 @@
return lastClosed;
}
-static bool isNonTableCellHTMLBlockElement(const Node* node)
-{
- return node->hasTagName(listingTag)
- || node->hasTagName(olTag)
- || node->hasTagName(preTag)
- || node->hasTagName(tableTag)
- || node->hasTagName(ulTag)
- || node->hasTagName(xmpTag)
- || node->hasTagName(h1Tag)
- || node->hasTagName(h2Tag)
- || node->hasTagName(h3Tag)
- || node->hasTagName(h4Tag)
- || node->hasTagName(h5Tag);
-}
-
static bool isHTMLBlockElement(const Node* node)
{
return node->hasTagName(tdTag)
@@ -449,9 +434,6 @@
|| isNonTableCellHTMLBlockElement(node);
}
-// FIXME: Do we want to handle mail quotes here instead?
-// This is currently handled in highestAncestorToWrapMarkup but it might make more
-// sense to move that into here.
static Node* ancestorToRetainStructureAndAppearanceForBlock(Node* commonAncestorBlock)
{
if (!commonAncestorBlock)