Reviewed by Darin Adler.
<rdar://problem/
4930986> REGRESSION: Paste As Quotation pastes black text instead of blue
Add a second style span at copy time to hold document default styles. This helps us
differentiate between those and user applied styles at paste time, where we'll want
to let Mail's Paste As Quotation blockquote override document default styles, but
not others.
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Changed the unit type used
for -webkit-text-stroke-width from CSS_NUMBER to CSS_PX, to match other properties that
are thick | medium | thin | <length>. Before, there was a mismatch between the unit
type of -webkit-text-stroke-width property values in a CSSComputedStyleDeclaration for
an element and that element's inlineStyleDecl(), causing identical values to always appear
different to diff().
* editing/ReplaceSelectionCommand.cpp:
(WebCore::ReplaceSelectionCommand::handlePasteAsQuotationNode): Fixed. Don't just change
the class to an empty string, completely remove it, it's no longer needed.
(WebCore::handleStyleSpansBeforeInsertion): Moved the optimization from doApply here.
(WebCore::ReplaceSelectionCommand::handleStyleSpans):
Added, replaces removeRedundantStyles.
We aren't (yet) removing all redundant styles, just those on style spans, so I removed the
unused code and renamed the function.
There won't be more than two style spans that we need to consider, the one with the
source document's default styles and styles on the commonAncestor of the copied Range,
so don't look for more than two.
Let elements that wrap the incoming fragment override the source document's styles.
(WebCore::ReplaceSelectionCommand::doApply): Moved code to handleStyleSpansBeforeInsertion
and call the renamed handleStyleSpans.
* editing/ReplaceSelectionCommand.h:
* editing/markup.cpp:
(WebCore::removeDefaultStyles): Added. Don't add document defaults to the style span
that holds user applied styles, since they'll be added to their own style span.
(WebCore::createMarkup):
Add a second style span that holds just the document defaults. This lets us differentiate
between those and user applied styles at paste time.
Mail blockquotes are just another type of special element, moved their handling there. This
also lets paste code make assumptions about the position of the two style spans (they are
*always* parent-child).
LayoutTests:
Reviewed by Darin Adler.
<rdar://problem/
4930986> REGRESSION: Paste As Quotation pastes black text instead of blue
Demonstrates the bug:
* editing/pasteboard/
4930986-1-expected.txt: Added.
* editing/pasteboard/
4930986-1.html: Added.
* editing/pasteboard/
4930986-2-expected.txt: Added.
* editing/pasteboard/
4930986-2.html: Added.
Demonstrates a problem with the first version of the patch:
* editing/pasteboard/
4930986-3-expected.txt: Added.
* editing/pasteboard/
4930986-3.html: Added.
Visual problem fixed. An anonymous renderer changed position, DOM remains unchanged:
* editing/execCommand/
5144139-1.html:
* platform/mac/editing/execCommand/
5144139-1-expected.checksum:
* platform/mac/editing/execCommand/
5144139-1-expected.png:
* platform/mac/editing/execCommand/
5144139-1-expected.txt:
Removed unnecessary style spans, visual result unchanged:
* platform/mac/editing/pasteboard/merge-end-blockquote-expected.checksum:
* platform/mac/editing/pasteboard/merge-end-blockquote-expected.png:
* platform/mac/editing/pasteboard/merge-end-blockquote-expected.txt:
* platform/mac/editing/style/font-family-with-space-expected.checksum:
* platform/mac/editing/style/font-family-with-space-expected.png:
* platform/mac/editing/style/font-family-with-space-expected.txt:
A style span isn't removed because at paste time because we don't anticipate
encountering styles on style spans that are non-inheritable, because we don't
create style spans like that at copy time. Turned this into a text only
test. Test remains visually unchanged:
* editing/pasteboard/
5245519-expected.txt: Added.
* editing/pasteboard/
5245519.html:
* platform/mac/editing/pasteboard/
5245519-expected.checksum: Removed.
* platform/mac/editing/pasteboard/
5245519-expected.png: Removed.
* platform/mac/editing/pasteboard/
5245519-expected.txt: Removed.
Added an extra empty anonymous renderer, DOM and visual result remain unchanged:
* platform/mac/editing/execCommand/create-list-with-hr-expected.checksum:
* platform/mac/editing/execCommand/create-list-with-hr-expected.png:
* platform/mac/editing/execCommand/create-list-with-hr-expected.txt:
* platform/mac/editing/pasteboard/paste-list-001-expected.checksum:
* platform/mac/editing/pasteboard/paste-list-001-expected.png:
* platform/mac/editing/pasteboard/paste-list-001-expected.txt:
* platform/mac/editing/pasteboard/paste-table-001-expected.checksum:
* platform/mac/editing/pasteboard/paste-table-001-expected.png:
* platform/mac/editing/pasteboard/paste-table-001-expected.txt:
* platform/mac/editing/pasteboard/paste-text-003-expected.checksum:
* platform/mac/editing/pasteboard/paste-text-003-expected.png:
* platform/mac/editing/pasteboard/paste-text-003-expected.txt:
Reflects changes to CSSComputedStyleDeclaration::getPropertyCSSValue:
* fast/css/computed-style-expected.txt:
* fast/css/computed-style-without-renderer-expected.txt:
We don't remove styles from style spans that are overridden by all of their
children, even though they are unnecessary. We've never done this, but now
that there can be two style spans at paste time we are more likely to have
a style span left over because of this problem. Mentioned this in the test
case and turned this into a text only test:
* editing/pasteboard/
4840662.html:
* editing/pasteboard/
4840662-expected.txt: Added.
* platform/mac/editing/pasteboard/
4840662-expected.checksum: Removed.
* platform/mac/editing/pasteboard/
4840662-expected.png: Removed.
* platform/mac/editing/pasteboard/
4840662-expected.txt: Removed.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@30649
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2008-02-28 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/4930986> REGRESSION: Paste As Quotation pastes black text instead of blue
+
+ Demonstrates the bug:
+ * editing/pasteboard/4930986-1-expected.txt: Added.
+ * editing/pasteboard/4930986-1.html: Added.
+ * editing/pasteboard/4930986-2-expected.txt: Added.
+ * editing/pasteboard/4930986-2.html: Added.
+
+ Demonstrates a problem with the first version of the patch:
+ * editing/pasteboard/4930986-3-expected.txt: Added.
+ * editing/pasteboard/4930986-3.html: Added.
+
+ Visual problem fixed. An anonymous renderer changed position, DOM remains unchanged:
+ * editing/execCommand/5144139-1.html:
+ * platform/mac/editing/execCommand/5144139-1-expected.checksum:
+ * platform/mac/editing/execCommand/5144139-1-expected.png:
+ * platform/mac/editing/execCommand/5144139-1-expected.txt:
+
+ Removed unnecessary style spans, visual result unchanged:
+ * platform/mac/editing/pasteboard/merge-end-blockquote-expected.checksum:
+ * platform/mac/editing/pasteboard/merge-end-blockquote-expected.png:
+ * platform/mac/editing/pasteboard/merge-end-blockquote-expected.txt:
+ * platform/mac/editing/style/font-family-with-space-expected.checksum:
+ * platform/mac/editing/style/font-family-with-space-expected.png:
+ * platform/mac/editing/style/font-family-with-space-expected.txt:
+
+ A style span isn't removed because at paste time because we don't anticipate
+ encountering styles on style spans that are non-inheritable, because we don't
+ create style spans like that at copy time. Turned this into a text only
+ test. Test remains visually unchanged:
+ * editing/pasteboard/5245519-expected.txt: Added.
+ * editing/pasteboard/5245519.html:
+ * platform/mac/editing/pasteboard/5245519-expected.checksum: Removed.
+ * platform/mac/editing/pasteboard/5245519-expected.png: Removed.
+ * platform/mac/editing/pasteboard/5245519-expected.txt: Removed.
+
+ Added an extra empty anonymous renderer, DOM and visual result remain unchanged:
+ * platform/mac/editing/execCommand/create-list-with-hr-expected.checksum:
+ * platform/mac/editing/execCommand/create-list-with-hr-expected.png:
+ * platform/mac/editing/execCommand/create-list-with-hr-expected.txt:
+ * platform/mac/editing/pasteboard/paste-list-001-expected.checksum:
+ * platform/mac/editing/pasteboard/paste-list-001-expected.png:
+ * platform/mac/editing/pasteboard/paste-list-001-expected.txt:
+ * platform/mac/editing/pasteboard/paste-table-001-expected.checksum:
+ * platform/mac/editing/pasteboard/paste-table-001-expected.png:
+ * platform/mac/editing/pasteboard/paste-table-001-expected.txt:
+ * platform/mac/editing/pasteboard/paste-text-003-expected.checksum:
+ * platform/mac/editing/pasteboard/paste-text-003-expected.png:
+ * platform/mac/editing/pasteboard/paste-text-003-expected.txt:
+
+ Reflects changes to CSSComputedStyleDeclaration::getPropertyCSSValue:
+ * fast/css/computed-style-expected.txt:
+ * fast/css/computed-style-without-renderer-expected.txt:
+
+ We don't remove styles from style spans that are overridden by all of their
+ children, even though they are unnecessary. We've never done this, but now
+ that there can be two style spans at paste time we are more likely to have
+ a style span left over because of this problem. Mentioned this in the test
+ case and turned this into a text only test:
+ * editing/pasteboard/4840662.html:
+ * editing/pasteboard/4840662-expected.txt: Added.
+ * platform/mac/editing/pasteboard/4840662-expected.checksum: Removed.
+ * platform/mac/editing/pasteboard/4840662-expected.png: Removed.
+ * platform/mac/editing/pasteboard/4840662-expected.txt: Removed.
+
2008-02-27 Dan Bernstein <mitz@apple.com>
Reviewed by John Sullivan.
-<p>This tests for a bug when creating a list from a table. The table should be inside a a list item. <b>This demonstrates a bug: the table should be below the list marker, not above it.</b></p>
+<p>This tests for a bug when creating a list from a table. The table should be inside a a list item.</p>
<div contenteditable="true" id="div"><table border="1"><tr><td>foo</td></tr></table></div>
<script>
--- /dev/null
+This tests for a crash when pasting into a link that is display:block. 'bar' is pasted between 'foo' and 'baz', and must be part of the link in order to acheive the expected paragraph structure. It should be part of the link but of the default font style. 'bar' shouldn't be underlined and the second style span is unnecessary, since its only property is overridden by its only child.
+<a id="anchor" href="http://www.google.com/" style="display:block;">foo<span class="Apple-style-span" style="color: rgb(0, 0, 0); -webkit-text-decorations-in-effect: none; ">bar<span class="Apple-style-span" style="-webkit-text-decorations-in-effect: none; "><a id="anchor" href="http://www.google.com/" style="display: inline !important; ">baz</a></span></span></a>
-<p>This tests for a crash when pasting into a link that is display:block. 'bar' is pasted between 'foo' and 'baz', and must be part of the link in order to acheive the expected paragraph structure. It should be part of the link but of the default font style.</p>
-<div id="div" contenteditable="true"><a id="anchor" href="http://www.google.com/" style="display:block;">foobaz</a></div>
+<div id="description">This tests for a crash when pasting into a link that is display:block. 'bar' is pasted between 'foo' and 'baz', and must be part of the link in order to acheive the expected paragraph structure. It should be part of the link but of the default font style. <b>'bar' shouldn't be underlined and the second style span is unnecessary, since its only property is overridden by its only child.</b></div>
+<div id="edit" contenteditable="true"><a id="anchor" href="http://www.google.com/" style="display:block;">foobaz</a></div>
<script>
var sel = window.getSelection();
sel.setPosition(text, 3);
document.execCommand("InsertHTML", false, "bar");
+if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ document.body.innerText = document.getElementById("description").innerText + "\n" + document.getElementById("edit").innerHTML;
+}
</script>
--- /dev/null
+This tests to make sure that content that has the document default color is pasted as blue (or whatever the color for quoted content is) during a Paste as Quotation.
+<blockquote>This text should be blue (it should not be wrapped in a style span).</blockquote>
--- /dev/null
+<html>
+<head>
+<style>
+blockquote {
+ color: blue;
+ border-left: 2px solid blue;
+ margin-left: 0px;
+ padding-left: 10px;
+}
+</style>
+</head>
+<body>
+<div id="description">This tests to make sure that content that has the document default color is pasted as blue (or whatever the color for quoted content is) during a Paste as Quotation.</div>
+<div id="edit" contenteditable="true"></div>
+
+<script>
+edit = document.getElementById("edit");
+description = document.getElementById("description");
+edit.focus();
+document.execCommand("InsertHTML", false, "<blockquote class='Apple-paste-as-quotation'><span class='Apple-style-span' style='color: black;'>This text should be blue (it should not be wrapped in a style span).</span></blockquote>");
+if (window.layoutTestController) {
+ window.layoutTestController.dumpAsText();
+ document.body.innerText = description.innerText + "\n" + edit.innerHTML;
+}
+</script>
+</body>
+</html>
--- /dev/null
+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>
--- /dev/null
+<html>
+<head>
+<style>
+blockquote {
+ color: blue;
+ border-left: 2px solid blue;
+ margin-left: 0px;
+ padding-left: 10px;
+}
+</style>
+<script>
+function runTest() {
+ div = document.getElementById("edit");
+ div.focus();
+ document.execCommand("InsertHTML", false, "<blockquote class='Apple-paste-as-quotation'><span class='Apple-style-span' style='color: black;'><span class='Apple-style-span' style='color: red;'>This text should be red (it should be wrapped in a style span).</span></span></blockquote>");
+ if (window.layoutTestController) {
+ window.layoutTestController.dumpAsText();
+ document.body.innerText = document.getElementById("description").innerText + "\n" + div.innerHTML;
+ }
+}
+</script>
+</head>
+<body onload="runTest();">
+<div id="description">This tests to make sure that content that is colored by the user is pasted with that color during a Paste as Quotation.</div>
+<div id="edit" contenteditable="true"></div>
+</body>
+</html>
--- /dev/null
+This tests to make sure that an Apple-paste-as-quotation blockquote can override document default styles even if they are different than the insertion position.
+<blockquote>This text should have the blockquote color (blue). There should be no style spans around it.</blockquote>
--- /dev/null
+<html>
+<head>
+<style>
+blockquote {
+ color: blue;
+ padding-left: 10px;
+ margin-left: 0px;
+ border-left: 2px solid blue;
+}
+</style>
+</head>
+<body>
+<div id="description">This tests to make sure that an Apple-paste-as-quotation blockquote can override document default styles even if they are different than the insertion position.</div>
+<div id="edit" contenteditable="true" style="color: red;"></div>
+
+<script>
+edit = document.getElementById("edit");
+description = document.getElementById("description");
+edit.focus();
+document.execCommand("InsertHTML", false, "<blockquote class='Apple-paste-as-quotation'><span class='Apple-style-span' style='color:black;'>This text should have the blockquote color (blue). There should be no style spans around it.</span></blockquote>");
+if (window.layoutTestController) {
+ window.layoutTestController.dumpAsText();
+ document.body.innerText = description.innerText + "\n" + edit.innerHTML;
+}
+</script>
+</body>
+</html>
--- /dev/null
+This tests for a crash when pasting content that contains Apple-style-spans that don't have renderers.' You should see 'Hello World!' We don't currently remove the empty invisible style span at paste time because it doesn't anticipate encountering non-inheritable styles on style spans, because we never create those at copy time.
+Hello <span style="display: none; " class="Apple-style-span"></span>World!
-<p>This tests for a crash when pasting content that contains Apple-style-spans that don't have renderers.' You should see 'Hello World!'</p>
-<div id="div" contenteditable="true"><br></div>
+<div id="description">This tests for a crash when pasting content that contains Apple-style-spans that don't have renderers.' You should see 'Hello World!' We don't currently remove the empty invisible style span at paste time because it doesn't anticipate encountering non-inheritable styles on style spans, because we never create those at copy time.</div>
+<div id="edit" contenteditable="true"><br></div>
<script>
-var div = document.getElementById("div");
-div.focus();
-document.execCommand("InsertHTML", false, "Hello <span style='display:none;' class='Apple-style-span'></span>World!")
+edit = document.getElementById("edit");
+description = document.getElementById("description");
+edit.focus();
+document.execCommand("InsertHTML", false, "Hello <span style='display:none;' class='Apple-style-span'></span>World!");
+if (window.layoutTestController) {
+ window.layoutTestController.dumpAsText();
+ document.body.innerText = description.innerText + "\n" + edit.innerHTML;
+}
</script>
-webkit-text-fill-color: rgb(0, 0, 0);
-webkit-text-security: none;
-webkit-text-stroke-color: rgb(0, 0, 0);
--webkit-text-stroke-width: 0;
+-webkit-text-stroke-width: 0px;
-webkit-user-drag: auto;
-webkit-user-modify: read-only;
-webkit-user-select: text;
-webkit-text-fill-color: rgb(0, 0, 0)
-webkit-text-security: none
-webkit-text-stroke-color: rgb(0, 0, 0)
- -webkit-text-stroke-width: 0
+ -webkit-text-stroke-width: 0px
-webkit-user-drag: auto
-webkit-user-modify: read-only
-webkit-user-select: text
-7a27d6fc595f0e6999bb2ad18397bff3
\ No newline at end of file
+ea40b5cb64b647b0194c8dc8db064b6d
\ No newline at end of file
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x576
- RenderBlock {P} at (0,0) size 784x36
- RenderText {#text} at (0,0) size 581x18
+ RenderBlock {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 577x18
text run at (0,0) width 333: "This tests for a bug when creating a list from a table. "
- text run at (333,0) width 248: "The table should be inside a a list item. "
- RenderInline {B} at (0,0) size 777x36
- RenderText {#text} at (581,0) size 777x36
- text run at (581,0) width 196: "This demonstrates a bug: the"
- text run at (0,18) width 340: "table should be below the list marker, not above it."
- RenderBlock {DIV} at (0,52) size 784x46
+ text run at (333,0) width 244: "The table should be inside a a list item."
+ RenderBlock {DIV} at (0,34) size 784x46
RenderBlock {UL} at (0,0) size 784x46
RenderListItem {LI} at (40,0) size 744x46
- RenderTable {TABLE} at (0,0) size 31x28 [border: (1px outset #808080)]
+ RenderBlock (anonymous) at (0,0) size 744x18
+ RenderListMarker at (-17,0) size 7x18: bullet
+ RenderTable {TABLE} at (0,18) size 31x28 [border: (1px outset #808080)]
RenderTableSection {TBODY} at (1,1) size 29x26
RenderTableRow {TR} at (0,2) size 29x22
RenderTableCell {TD} at (2,2) size 25x22 [border: (1px inset #808080)] [r=0 c=0 rs=1 cs=1]
RenderText {#text} at (2,2) size 21x18
text run at (2,2) width 21: "foo"
- RenderBlock (anonymous) at (0,28) size 744x18
- RenderListMarker at (-17,0) size 7x18: bullet
+ RenderBlock (anonymous) at (0,46) size 744x0
RenderBlock (anonymous) at (0,62) size 784x0
selection start: position 0 of child 0 {TABLE} of child 0 {LI} of child 0 {UL} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
selection end: position 1 of child 0 {TABLE} of child 0 {LI} of child 0 {UL} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
-7d8ed4a08a6169f34146cce72d34f4c2
\ No newline at end of file
+7803bac727a902ee0e75044ecace1578
\ No newline at end of file
RenderBlock {DIV} at (0,52) size 784x28
RenderBlock {UL} at (0,0) size 784x28
RenderListItem {LI} at (40,0) size 744x28
+ RenderBlock (anonymous) at (0,0) size 744x0
RenderBlock {HR} at (0,0) size 744x2 [border: (1px inset #000000)]
RenderBlock (anonymous) at (0,10) size 744x18
RenderListMarker at (-17,0) size 7x18: bullet
+++ /dev/null
-0f761deb6f4379cc7e8321b7caff46d8
\ No newline at end of file
+++ /dev/null
-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 784x36
- RenderText {#text} at (0,0) size 781x36
- text run at (0,0) width 421: "This tests for a crash when pasting into a link that is display:block. "
- text run at (421,0) width 360: "'bar' is pasted between 'foo' and 'baz', and must be part of"
- text run at (0,18) width 384: "the link in order to acheive the expected paragraph structure. "
- text run at (384,18) width 347: "It should be part of the link but of the default font style."
- RenderBlock {DIV} at (0,52) size 784x18
- RenderBlock {A} at (0,0) size 784x18 [color=#0000EE]
- RenderText {#text} at (0,0) size 21x18
- text run at (0,0) width 21: "foo"
- RenderInline {SPAN} at (0,0) size 42x18 [color=#000000]
- RenderText {#text} at (21,0) size 20x18
- text run at (21,0) width 20: "bar"
- RenderInline {A} at (0,0) size 22x18 [color=#0000EE]
- RenderText {#text} at (41,0) size 22x18
- text run at (41,0) width 22: "baz"
- RenderBlock (anonymous) at (0,18) size 784x0
-caret: position 3 of child 0 {#text} of child 1 {SPAN} of child 0 {A} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
+++ /dev/null
-37cc348638ebafbdca4889bdfb9746e4
\ No newline at end of file
+++ /dev/null
-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 784x36
- RenderText {#text} at (0,0) size 776x36
- text run at (0,0) width 776: "This tests for a crash when pasting content that contains Apple-style-spans that don't have renderers.' You should see 'Hello"
- text run at (0,18) width 48: "World!'"
- RenderBlock {DIV} at (0,52) size 784x18
- RenderText {#text} at (0,0) size 39x18
- text run at (0,0) width 39: "Hello "
- RenderText {#text} at (39,0) size 45x18
- text run at (39,0) width 45: "World!"
-caret: position 6 of child 1 {#text} of child 2 {DIV} of child 0 {BODY} of child 0 {HTML} of document
-1b9b9519702657687d74ee0998ba0616
\ No newline at end of file
+3e9438db2edbee3025b3d9bdd073772e
\ No newline at end of file
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 3 of #text > SPAN > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document to 3 of #text > SPAN > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 3 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document to 3 of #text > DIV > BLOCKQUOTE > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
layer at (0,0) size 800x600
RenderBlock {DIV} at (0,0) size 704x18
RenderText {#text} at (0,0) size 81x18
text run at (0,0) width 81: "Blockquoted"
- RenderInline {SPAN} at (0,0) size 21x18
- RenderText {#text} at (81,0) size 21x18
- text run at (81,0) width 21: "foo"
+ RenderText {#text} at (81,0) size 21x18
+ text run at (81,0) width 21: "foo"
RenderBlock {DIV} at (0,18) size 704x18
- RenderInline {SPAN} at (0,0) size 20x18
- RenderText {#text} at (0,0) size 20x18
- text run at (0,0) width 20: "bar"
+ RenderText {#text} at (0,0) size 20x18
+ text run at (0,0) width 20: "bar"
RenderText {#text} at (20,0) size 33x18
text run at (20,0) width 33: " Text"
-caret: position 3 of child 0 {#text} of child 0 {SPAN} of child 1 {DIV} of child 0 {BLOCKQUOTE} of child 10 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 3 of child 0 {#text} of child 1 {DIV} of child 0 {BLOCKQUOTE} of child 10 {DIV} of child 1 {BODY} of child 0 {HTML} of document
-be0dd0567e71d7ca65d1f3971bc1e8ab
\ No newline at end of file
+16cc7c7f609fb21bb3ead24836c06afd
\ No newline at end of file
RenderListMarker at (-31,0) size 24x28: "3"
RenderText {#text} at (0,0) size 211x28
text run at (0,0) width 211: "I should be number 3."
+ RenderBlock (anonymous) at (0,112) size 716x0
caret: position 21 of child 0 {#text} of child 2 {LI} of child 1 {OL} of child 5 {LI} of child 4 {OL} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
-15977586b524fa1983f2edca33ac179d
\ No newline at end of file
+8a3262c6ed008c4f6685ea78a6007181
\ No newline at end of file
RenderTableCell {TD} at (85,26) size 201x22 [border: (1px inset #808080)] [r=1 c=1 rs=1 cs=1]
RenderText {#text} at (2,2) size 197x18
text run at (2,2) width 197: "I should be in the right column."
+ RenderBlock (anonymous) at (0,108) size 756x0
+ RenderText {#text} at (0,0) size 0x0
caret: position 32 of child 0 {#text} of child 1 {TD} of child 1 {TR} of child 0 {TBODY} of child 2 {TABLE} of child 3 {P} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
-75d9836b9195747b9f3ddac2ae3e59a5
\ No newline at end of file
+dcb89e929b2f320f3c8febe7aaafeb07
\ No newline at end of file
RenderBlock {DIV} at (14,42) size 756x56 [border: (2px solid #FF0000)]
RenderText {#text} at (14,14) size 434x28
text run at (14,14) width 434: "Which taken at the flood leads on to fortune."
+ RenderBlock (anonymous) at (14,98) size 756x0
RenderBlock {DIV} at (14,98) size 756x252 [border: (2px solid #FF0000)]
RenderBlock (anonymous) at (14,14) size 728x0
RenderBlock {DIV} at (14,14) size 728x56 [border: (2px solid #FF0000)]
RenderBlock {DIV} at (14,70) size 728x56 [border: (2px solid #FF0000)]
RenderText {#text} at (14,14) size 434x28
text run at (14,14) width 434: "Which taken at the flood leads on to fortune."
+ RenderBlock (anonymous) at (14,126) size 728x0
RenderBlock {DIV} at (14,126) size 728x112 [border: (2px solid #FF0000)]
RenderBlock (anonymous) at (14,14) size 700x28
RenderText {#text} at (0,0) size 80x28
-ad2fb64e1da980ee74eec20e181c44d5
\ No newline at end of file
+84f6f77ad7ddecc3796b10bad7285ec7
\ No newline at end of file
text run at (0,0) width 245: "This text should be Times New Roman bold."
RenderInline {SPAN} at (0,0) size 245x15
RenderInline {SPAN} at (0,0) size 245x15
- RenderInline {DIV} at (0,0) size 245x15
- RenderText {#text} at (245,0) size 245x15
- text run at (245,0) width 245: "This text should be Times New Roman bold."
+ RenderText {#text} at (245,0) size 245x15
+ text run at (245,0) width 245: "This text should be Times New Roman bold."
RenderText {#text} at (0,0) size 0x0
RenderText {#text} at (0,0) size 0x0
-caret: position 41 of child 0 {#text} of child 0 {DIV} of child 1 {SPAN} of child 0 {SPAN} of child 0 {BODY} of child 0 {HTML} of document
+caret: position 41 of child 0 {#text} of child 1 {SPAN} of child 0 {SPAN} of child 0 {BODY} of child 0 {HTML} of document
+2008-02-28 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/4930986> REGRESSION: Paste As Quotation pastes black text instead of blue
+
+ Add a second style span at copy time to hold document default styles. This helps us
+ differentiate between those and user applied styles at paste time, where we'll want
+ to let Mail's Paste As Quotation blockquote override document default styles, but
+ not others.
+
+ * css/CSSComputedStyleDeclaration.cpp:
+ (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Changed the unit type used
+ for -webkit-text-stroke-width from CSS_NUMBER to CSS_PX, to match other properties that
+ are thick | medium | thin | <length>. Before, there was a mismatch between the unit
+ type of -webkit-text-stroke-width property values in a CSSComputedStyleDeclaration for
+ an element and that element's inlineStyleDecl(), causing identical values to always appear
+ different to diff().
+ * editing/ReplaceSelectionCommand.cpp:
+ (WebCore::ReplaceSelectionCommand::handlePasteAsQuotationNode): Fixed. Don't just change
+ the class to an empty string, completely remove it, it's no longer needed.
+ (WebCore::handleStyleSpansBeforeInsertion): Moved the optimization from doApply here.
+ (WebCore::ReplaceSelectionCommand::handleStyleSpans):
+ Added, replaces removeRedundantStyles.
+ We aren't (yet) removing all redundant styles, just those on style spans, so I removed the
+ unused code and renamed the function.
+ There won't be more than two style spans that we need to consider, the one with the
+ source document's default styles and styles on the commonAncestor of the copied Range,
+ so don't look for more than two.
+ Let elements that wrap the incoming fragment override the source document's styles.
+ (WebCore::ReplaceSelectionCommand::doApply): Moved code to handleStyleSpansBeforeInsertion
+ and call the renamed handleStyleSpans.
+ * editing/ReplaceSelectionCommand.h:
+ * editing/markup.cpp:
+ (WebCore::removeDefaultStyles): Added. Don't add document defaults to the style span
+ that holds user applied styles, since they'll be added to their own style span.
+ (WebCore::createMarkup):
+ Add a second style span that holds just the document defaults. This lets us differentiate
+ between those and user applied styles at paste time.
+ Mail blockquotes are just another type of special element, moved their handling there. This
+ also lets paste code make assumptions about the position of the two style spans (they are
+ *always* parent-child).
+
2008-02-28 Brent Fulgham <bfulgham@gmail.com>
http://bugs.webkit.org/show_bug.cgi?id=17576
case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
return currentColorOrValidColor(style, style->textStrokeColor());
case CSS_PROP__WEBKIT_TEXT_STROKE_WIDTH:
- return new CSSPrimitiveValue(style->textStrokeWidth(), CSSPrimitiveValue::CSS_NUMBER);
+ return new CSSPrimitiveValue(style->textStrokeWidth(), CSSPrimitiveValue::CSS_PX);
case CSS_PROP_TEXT_TRANSFORM:
return new CSSPrimitiveValue(style->textTransform());
case CSS_PROP_TOP:
#include "ApplyStyleCommand.h"
#include "BeforeTextInsertedEvent.h"
#include "CSSComputedStyleDeclaration.h"
+#include "CSSProperty.h"
#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
#include "Document.h"
}
}
-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) && 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());
- }
-
- // Compute and save the non-redundant styles for all HTML elements.
- // Don't do any mutation here, because that would cause the diffs to trigger layouts.
- Vector<RefPtr<CSSMutableStyleDeclaration> > styles;
- Vector<RefPtr<HTMLElement> > elements;
- for (node = m_firstNodeInserted.get(); node; node = node->traverseNextNode()) {
- if (node->isHTMLElement() && isStyleSpan(node)) {
- elements.append(static_cast<HTMLElement*>(node));
-
- RefPtr<CSSMutableStyleDeclaration> parentStyle = computedStyle(node->parentNode())->copyInheritableProperties();
- RefPtr<CSSMutableStyleDeclaration> style = computedStyle(node)->copyInheritableProperties();
- parentStyle->diff(style.get());
-
- // Remove any inherited block properties that are now in the span's style. This cuts out meaningless properties
- // and prevents properties from magically affecting blocks later if the style is cloned for a new block element
- // during a future editing operation.
- style->removeBlockProperties();
-
- styles.append(style.release());
- }
- if (node == m_lastLeafInserted)
- break;
- }
-
- size_t count = styles.size();
- for (size_t i = 0; i < count; ++i) {
- HTMLElement* element = elements[i].get();
-
- // Handle case where the element was already removed by earlier processing.
- // It's possible this no longer occurs, but it did happen in an earlier version
- // that processed elements in a less-determistic order, and I can't prove it
- // does not occur.
- if (!element->inDocument())
- continue;
-
- // Remove empty style spans.
- if (isStyleSpan(element) && !element->hasChildNodes()) {
- removeNodeAndPruneAncestors(element);
- continue;
- }
-
- // Remove redundant style tags and style spans.
- CSSMutableStyleDeclaration* style = styles[i].get();
- if (style->length() == 0
- && (isStyleSpan(element)
- || element->hasTagName(bTag)
- || element->hasTagName(fontTag)
- || element->hasTagName(iTag)
- || element->hasTagName(uTag))) {
- removeNodePreservingChildren(element);
- continue;
- }
-
- // Clear redundant styles from elements.
- CSSMutableStyleDeclaration* inlineStyleDecl = element->inlineStyleDecl();
- if (inlineStyleDecl) {
- CSSComputedStyleDeclaration::removeComputedInheritablePropertiesFrom(inlineStyleDecl);
- inlineStyleDecl->merge(style, true);
- setNodeAttribute(element, styleAttr, inlineStyleDecl->cssText());
- }
- }
-}
-
void ReplaceSelectionCommand::handlePasteAsQuotationNode()
{
Node* node = m_firstNodeInserted.get();
if (isMailPasteAsQuotationNode(node))
- static_cast<Element*>(node)->setAttribute(classAttr, "");
+ removeNodeAttribute(static_cast<Element*>(node), classAttr);
}
VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent()
return VisiblePosition(nextCandidate(positionBeforeNode(m_firstNodeInserted.get())));
}
+// Remove style spans before insertion if they are unnecessary. It's faster because we'll
+// avoid doing a layout.
+static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos)
+{
+ Node* topNode = fragment.firstChild();
+
+ // Handling this case is more complicated (see handleStyleSpans) and doesn't receive the optimization.
+ if (isMailPasteAsQuotationNode(topNode))
+ return false;
+
+ // Either there are no style spans in the fragment or a WebKit client has added content to the fragment
+ // before inserting it. Look for and handle style spans after insertion.
+ if (!isStyleSpan(topNode))
+ return false;
+
+ Node* sourceDocumentStyleSpan = topNode;
+ RefPtr<Node> copiedRangeStyleSpan = sourceDocumentStyleSpan->firstChild();
+
+ RefPtr<CSSMutableStyleDeclaration> styleAtInsertionPos = rangeCompliantEquivalent(insertionPos).computedStyle()->copyInheritableProperties();
+ String styleText = styleAtInsertionPos->cssText();
+
+ if (styleText == static_cast<Element*>(sourceDocumentStyleSpan)->getAttribute(styleAttr)) {
+ fragment.removeNodePreservingChildren(sourceDocumentStyleSpan);
+ if (!isStyleSpan(copiedRangeStyleSpan.get()))
+ return true;
+ }
+
+ if (isStyleSpan(copiedRangeStyleSpan.get()) && styleText == static_cast<Element*>(copiedRangeStyleSpan.get())->getAttribute(styleAttr)) {
+ fragment.removeNodePreservingChildren(copiedRangeStyleSpan.get());
+ return true;
+ }
+
+ return false;
+}
+
+// At copy time, WebKit wraps copied content in a span that contains the source document's
+// default styles. If the copied Range inherits any other styles from its ancestors, we put
+// those styles on a second span.
+// This function removes redundant styles from those spans, and removes the spans if all their
+// styles are redundant.
+// We should remove the Apple-style-span class when we're done, see <rdar://problem/5685600>.
+// We should remove styles from spans that are overridden by all of their children, either here
+// or at copy time.
+void ReplaceSelectionCommand::handleStyleSpans()
+{
+ Node* sourceDocumentStyleSpan = 0;
+ Node* copiedRangeStyleSpan = 0;
+ // The style span that contains the source document's default style should be at
+ // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation),
+ // so search for the top level style span instead of assuming it's at the top.
+ for (Node* node = m_firstNodeInserted.get(); node; node = node->traverseNextNode()) {
+ if (isStyleSpan(node)) {
+ sourceDocumentStyleSpan = node;
+ // If the copied Range's common ancestor had user applied inheritable styles
+ // on it, they'll be on a second style span, just below the one that holds the
+ // document defaults.
+ if (isStyleSpan(node->firstChild()))
+ copiedRangeStyleSpan = node->firstChild();
+ break;
+ }
+ }
+
+ // There might not be any style spans if we're pasting from another application or if
+ // we are here because of a document.execCommand("InsertHTML", ...) call.
+ if (!sourceDocumentStyleSpan)
+ return;
+
+ RefPtr<CSSMutableStyleDeclaration> sourceDocumentStyle = static_cast<HTMLElement*>(sourceDocumentStyleSpan)->getInlineStyleDecl()->copy();
+ Node* context = sourceDocumentStyleSpan->parentNode();
+
+ // If Mail wraps the fragment with a Paste as Quotation blockquote, styles from that element are
+ // allowed to override those from the source document, see <rdar://problem/4930986>.
+ if (isMailPasteAsQuotationNode(context)) {
+ RefPtr<CSSMutableStyleDeclaration> blockquoteStyle = computedStyle(context)->copyInheritableProperties();
+ RefPtr<CSSMutableStyleDeclaration> parentStyle = computedStyle(context->parentNode())->copyInheritableProperties();
+ parentStyle->diff(blockquoteStyle.get());
+
+ DeprecatedValueListConstIterator<CSSProperty> end;
+ for (DeprecatedValueListConstIterator<CSSProperty> it = blockquoteStyle->valuesIterator(); it != end; ++it) {
+ const CSSProperty& property = *it;
+ sourceDocumentStyle->removeProperty(property.id());
+ }
+
+ context = context->parentNode();
+ }
+
+ RefPtr<CSSMutableStyleDeclaration> contextStyle = computedStyle(context)->copyInheritableProperties();
+ String contextStyleText = contextStyle->cssText();
+ String sourceDocumentStyleText = sourceDocumentStyle->cssText();
+ contextStyle->diff(sourceDocumentStyle.get());
+
+ // Remove block properties in the span's style. This prevents properties that probably have no effect
+ // currently from affecting blocks later if the style is cloned for a new block element during a future
+ // editing operation.
+ // FIXME: They *can* have an effect currently if blocks beneath the style span aren't individually marked
+ // with block styles by the editing engine used to style them. WebKit doesn't do this, but others might.
+ sourceDocumentStyle->removeBlockProperties();
+
+ // The styles on sourceDocumentStyleSpan are all redundant, and there is no copiedRangeStyleSpan
+ // to consider. We're finished.
+ if (sourceDocumentStyle->length() == 0 && !copiedRangeStyleSpan) {
+ removeNodePreservingChildren(sourceDocumentStyleSpan);
+ return;
+ }
+
+ // There are non-redundant styles on sourceDocumentStyleSpan, but there is no
+ // copiedRangeStyleSpan. Clear the redundant styles from sourceDocumentStyleSpan
+ // and return.
+ if (sourceDocumentStyle->length() > 0 && !copiedRangeStyleSpan) {
+ setNodeAttribute(static_cast<Element*>(sourceDocumentStyleSpan), styleAttr, sourceDocumentStyle->cssText());
+ return;
+ }
+
+ RefPtr<CSSMutableStyleDeclaration> copiedRangeStyle = static_cast<HTMLElement*>(copiedRangeStyleSpan)->getInlineStyleDecl()->copy();
+
+ // We're going to put sourceDocumentStyleSpan's non-redundant styles onto copiedRangeStyleSpan,
+ // as long as they aren't overridden by ones on copiedRangeStyleSpan.
+ sourceDocumentStyle->merge(copiedRangeStyle.get(), true);
+ copiedRangeStyle = sourceDocumentStyle;
+
+ removeNodePreservingChildren(sourceDocumentStyleSpan);
+
+ // Remove redundant styles.
+ context = copiedRangeStyleSpan->parentNode();
+ contextStyle = computedStyle(context)->copyInheritableProperties();
+ contextStyle->diff(copiedRangeStyle.get());
+
+ // See the comments above about removing block properties.
+ copiedRangeStyle->removeBlockProperties();
+
+ // All the styles on copiedRangeStyleSpan are redundant, remove it.
+ if (copiedRangeStyle->length() == 0) {
+ removeNodePreservingChildren(copiedRangeStyleSpan);
+ return;
+ }
+
+ // Clear the redundant styles from the span's style attribute.
+ setNodeAttribute(static_cast<Element*>(copiedRangeStyleSpan), styleAttr, copiedRangeStyle->cssText());
+}
+
void ReplaceSelectionCommand::doApply()
{
Selection selection = endingSelection();
bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);
- Node* mailBlockquoteEnclosingSelectionStart = nearestMailBlockquote(visibleStart.deepEquivalent().node());
Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().node());
// FIXME: Improve typing style.
// See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
frame->clearTypingStyle();
- setTypingStyle(0);
-
- // Remove the top level style span if its unnecessary before inserting it into the document, its faster.
- RefPtr<CSSMutableStyleDeclaration> styleAtInsertionPos = insertionPos.computedStyle()->copyInheritableProperties();
- if (isStyleSpan(fragment.firstChild())) {
- Node* styleSpan = fragment.firstChild();
- String styleText = static_cast<Element*>(styleSpan)->getAttribute(styleAttr);
- if (styleText == styleAtInsertionPos->cssText())
- fragment.removeNodePreservingChildren(styleSpan);
- }
+ setTypingStyle(0);
+
+ bool handledStyleSpans = handleStyleSpansBeforeInsertion(fragment, insertionPos);
// We're finished if there is nothing to add.
if (fragment.isEmpty() || !fragment.firstChild())
negateStyleRulesThatAffectAppearance();
- removeRedundantStyles(mailBlockquoteEnclosingSelectionStart);
+ if (!handledStyleSpans)
+ handleStyleSpans();
if (!m_firstNodeInserted)
return;
void removeUnrenderedTextNodesAtEnds();
void negateStyleRulesThatAffectAppearance();
- void removeRedundantStyles(Node*);
-
+ void handleStyleSpans();
void handlePasteAsQuotationNode();
virtual void removeNodePreservingChildren(Node*);
blockquoteStyle->diff(style);
}
+static void removeDefaultStyles(CSSMutableStyleDeclaration* style, Document* document)
+{
+ if (!document || !document->documentElement())
+ return;
+
+ RefPtr<CSSMutableStyleDeclaration> documentStyle = computedStyle(document->documentElement())->copyInheritableProperties();
+ documentStyle->diff(style);
+}
+
static bool shouldAddNamespaceElem(const Element* elem)
{
// Don't add namespace attribute if it is already defined for this elem.
specialCommonAncestor = commonAncestorBlock;
}
+ bool selectedOneOrMoreParagraphs = startOfParagraph(visibleStart) != startOfParagraph(visibleEnd) ||
+ isStartOfParagraph(visibleStart) && isEndOfParagraph(visibleEnd);
+
+ // Retain the Mail quote level by including all ancestor mail block quotes.
+ if (lastClosed && annotate && selectedOneOrMoreParagraphs) {
+ for (Node *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode())
+ if (isMailBlockquote(ancestor))
+ specialCommonAncestor = ancestor;
+ }
+
Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;
if (checkAncestor->renderer()) {
RefPtr<CSSMutableStyleDeclaration> checkAncestorStyle = computedStyle(checkAncestor)->copyInheritableProperties();
}
}
+ static const String styleSpanOpen = String("<span class=\"" AppleStyleSpanClass "\" style=\"");
+ static const String styleSpanClose("</span>");
+
// Add a wrapper span with the styles that all of the nodes in the markup inherit.
Node* parentOfLastClosed = lastClosed ? lastClosed->parentNode() : 0;
if (parentOfLastClosed && parentOfLastClosed->renderer()) {
// get the color of content pasted into blockquotes right.
removeEnclosingMailBlockquoteStyle(style.get(), parentOfLastClosed);
+ // Document default styles will be added on another wrapper span.
+ removeDefaultStyles(style.get(), document);
+
// Since we are converting blocks to inlines, remove any inherited block properties that are in the style.
// This cuts out meaningless properties and prevents properties from magically affecting blocks later
// if the style is cloned for a new block element during a future editing operation.
if (style->length() > 0) {
Vector<UChar> openTag;
- const String spanClassStyle = String("<span class=\"" AppleStyleSpanClass "\" style=\"");
- append(openTag, spanClassStyle);
+ append(openTag, styleSpanOpen);
appendAttributeValue(openTag, style->cssText());
openTag.append('\"');
openTag.append('>');
preMarkups.append(String::adopt(openTag));
- static const String spanCloseTag("</span>");
- markups.append(spanCloseTag);
+ markups.append(styleSpanClose);
+ }
+ }
+
+ if (lastClosed && lastClosed != document->documentElement()) {
+ // Add a style span with the document's default styles. We add these in a separate
+ // span so that at paste time we can differentiate between document defaults and user
+ // applied styles.
+ RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle(document->documentElement())->copyInheritableProperties();
+
+ if (defaultStyle->length() > 0) {
+ Vector<UChar> openTag;
+ append(openTag, styleSpanOpen);
+ appendAttributeValue(openTag, defaultStyle->cssText());
+ openTag.append('\"');
+ openTag.append('>');
+ preMarkups.append(String::adopt(openTag));
+ markups.append(styleSpanClose);
}
}
// FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally.
if (annotate && needInterchangeNewlineAfter(visibleEnd.previous()))
markups.append(interchangeNewlineString);
-
- bool selectedOneOrMoreParagraphs = startOfParagraph(visibleStart) != startOfParagraph(visibleEnd) ||
- isStartOfParagraph(visibleStart) && isEndOfParagraph(visibleEnd);
-
- // Retain the Mail quote level by including all ancestor mail block quotes.
- if (lastClosed && annotate && selectedOneOrMoreParagraphs) {
- for (Node *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
- if (isMailBlockquote(ancestor)) {
- preMarkups.append(getStartMarkup(ancestor, updatedRange.get(), annotate));
- markups.append(getEndMarkup(ancestor));
- }
- }
- }
-
+
if (deleteButton)
deleteButton->enable();