<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[183770] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/183770">183770</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2015-05-04 13:42:41 -0700 (Mon, 04 May 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Toggling underline or strike through affects each other
https://bugs.webkit.org/show_bug.cgi?id=27818
Reviewed by Darin Adler.
Source/WebCore:
This patch introduces a new mechanism to apply and remove text decorations. This is necessary because text
decorations are always additive and we can't differentiate whether we're adding or removing a text decoration.
Conceptually, we need four values for text decorations: adding underline, removing underline, adding
line-through, and removing line-through but we have only three: underline, line-through, none.
After this patch, there are three mechanism by which text decorations states are kept tracked. While applying
or removing text decorations, we use newly added m_underlineChange and m_strikeThroughChange in EditingStyle.
For the typing style, we use -webkit-text-decorations-in-effect to store the state since we need to preserve
every type of text decorations such as overline in addition to underline and line-through. Once applied, all
text decorations should be expressed in terms of the standard text-decoration property.
Test: editing/execCommand/toggle-mixed-text-decorations.html
* editing/ApplyStyleCommand.cpp:
(WebCore::ApplyStyleCommand::applyBlockStyle):
(WebCore::ApplyStyleCommand::removeCSSStyle): conflictsWithInlineStyleOfElement now creates a new inline style
instead of a list of properties to remove.
(WebCore::ApplyStyleCommand::addBlockStyle):
(WebCore::ApplyStyleCommand::applyInlineStyleChange): Merge inline styles instead of adding as string.
Otherwise it would generate style content attribute with multiple text-decoration properties.
* editing/EditingStyle.cpp:
(WebCore::HTMLElementEquivalent::matches):
(WebCore::HTMLElementEquivalent::propertyExistsInStyle): Takes an EditingStyle instead of StyleProperties.
(WebCore::HTMLElementEquivalent::valueIsPresentInStyle):
(WebCore::HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent):
(WebCore::HTMLTextDecorationEquivalent::propertyExistsInStyle): Respect newly added m_strikeThroughChange and
m_underlineChange in EditingStyle.
(WebCore::HTMLTextDecorationEquivalent::valueIsPresentInStyle): Ditto.
(WebCore::HTMLTextDecorationEquivalent::changeInStyle): Added. Retrieves the change enum for the associated
type of text-decoration (underline or strike through).
(WebCore::HTMLAttributeEquivalent::matches):
(WebCore::HTMLAttributeEquivalent::valueIsPresentInStyle):
(WebCore::EditingStyle::EditingStyle): Initialize m_underlineChange and m_strikeThroughChange. Also use the
delegating constructor elsewhere. Also added the missing call to extractFontSizeDelta() in the variant that
takes CSSPropertyID and String, and added a variant that takes CSSPropertyID and CSSValueID.
(WebCore::EditingStyle::isEmpty): Return false when m_underlineChange and m_strikeThroughChange are not "none".
(WebCore::applyTextDecorationChangeToValueList): Added.
(WebCore::EditingStyle::overrideTypingStyleAt): Added. Used by Editor::computeAndSetTypingStyle to set a new
typing style. Resolve m_underlineChange and m_strikeThroughChange into -webkit-text-decorations-in-effect.
(WebCore::EditingStyle::clear): Clear m_underlineChange and m_strikeThroughChange.
(WebCore::EditingStyle::copy): Copy m_underlineChange and m_strikeThroughChange.
(WebCore::textDecorationValueList): Added.
(WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Now takes a pointer to MutableStyleProperties
instead of a vector. This was necessary we can't simply remove text-decoration property in ApplyStyleCommand's
removeCSSStyle as that would result in unrelated text decorations also getting removed. Also added the code
for m_underlineChange and m_strikeThroughChange. Only removing text decoration changes can cause a conflict
since text decorations are always additive.
(WebCore::EditingStyle::conflictsWithImplicitStyleOfElement): Check isEmpty() instead of the nullity of
m_mutableStyle to respect m_underlineChange and m_strikeThroughChange.
(WebCore::EditingStyle::conflictsWithImplicitStyleOfAttributes):
(WebCore::EditingStyle::extractConflictingImplicitStyleOfAttributes):
(WebCore::EditingStyle::styleIsPresentInComputedStyleOfNode): Respect the values of m_underlineChange and
m_strikeThroughChange. Here, the style is considered present if it has text decorations that are being added.
(WebCore::EditingStyle::elementIsStyledSpanOrHTMLEquivalent):
(WebCore::elementMatchesAndPropertyIsNotInInlineStyleDecl): Takes EditingStyle instead of StyleProperties to
respect m_underlineChange and m_strikeThroughChange.
(WebCore::EditingStyle::mergeInlineAndImplicitStyleOfElement):
(WebCore::mergeTextDecorationValues):
(WebCore::EditingStyle::mergeStyle): Make a copy of CSSValueList before modifying it since CSSValueList's are
shared with other immutable StyleProperties.
(WebCore::StyleChange::StyleChange): Set m_applyUnderline, m_applyLineThrough, and m_cssStyle if either
m_underlineChange or m_strikeThroughChange are TextDecorationChange::Add in EditingStyle if the current position
doesn't already have the matching style.
(WebCore::StyleChange::operator==): Moved from the header file. Also added the logic to compare m_cssStyle now
that it's a StyleProperties instead of String.
* editing/EditingStyle.h: Added TextDecorationChange.
(WebCore::EditingStyle::create): Added a variant that takes CSSPropertyID and CSSValueID.
(WebCore::EditingStyle::conflictsWithInlineStyleOfElement):
(WebCore::EditingStyle::setUnderlineChange): Added.
(WebCore::EditingStyle::underlineChange): Added.
(WebCore::EditingStyle::setStrikeThroughChange): Added.
(WebCore::EditingStyle::strikeThroughChange): Added.
(WebCore::StyleChange::cssStyle): Now returns StyleProperties* instead of String so that ApplyStyleCommand's
applyInlineStyleChange could merge inline styles instead of just appending it to the end.
(WebCore::StyleChange::operator==): Moved into the cpp file.
* editing/Editor.cpp:
(WebCore::Editor::applyStyle): Added. This variant takes EditingStyle instead of StyleProperties.
(WebCore::Editor::applyStyleToSelection): Ditto.
(WebCore::Editor::computeAndSetTypingStyle): Added a variant for EditingStyle. Also use overrideTypingStyleAt
to set -webkit-text-decorations-in-effect based on m_underlineChange and m_strikeThroughChange
* editing/Editor.h:
* editing/EditorCommand.cpp:
(WebCore::applyCommandToFrame):
(WebCore::isStylePresent): Extracted from executeToggleStyle.
(WebCore::executeApplyStyle):
(WebCore::executeToggleStyle):
(WebCore::executeToggleStyleInList): Deleted.
(WebCore::textDecorationChangeForToggling): Added. Used in executeStrikethrough and executeUnderline.
(WebCore::executeStrikethrough):
(WebCore::executeUnderline):
Source/WebKit/mac:
* WebView/WebFrame.mm:
(-[WebFrame _setTypingStyle:withUndoAction:]):
LayoutTests:
Added a regression test and rebaselined various tests as explained below.
* editing/execCommand/script-tests/toggle-style-2.js: The order in which u and strike elements appear have switched.
* editing/execCommand/script-tests/toggle-text-decorations.js: Ditto for line-through and overline.
* editing/execCommand/toggle-mixed-text-decorations-expected.txt: Added.
* editing/execCommand/toggle-mixed-text-decorations.html: Added.
* editing/execCommand/toggle-style-2-expected.txt: Rebaselined.
* editing/execCommand/toggle-text-decorations-expected.txt: Rebaselined.
* editing/undo/remove-css-property-and-remove-style-expected.txt: The order in which color and font-weight properties
appear have switched.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestseditingexecCommandscriptteststogglestyle2js">trunk/LayoutTests/editing/execCommand/script-tests/toggle-style-2.js</a></li>
<li><a href="#trunkLayoutTestseditingexecCommandscriptteststoggletextdecorationsjs">trunk/LayoutTests/editing/execCommand/script-tests/toggle-text-decorations.js</a></li>
<li><a href="#trunkLayoutTestseditingexecCommandtogglestyle2expectedtxt">trunk/LayoutTests/editing/execCommand/toggle-style-2-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingexecCommandtoggletextdecorationsexpectedtxt">trunk/LayoutTests/editing/execCommand/toggle-text-decorations-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingundoremovecsspropertyandremovestyleexpectedtxt">trunk/LayoutTests/editing/undo/remove-css-property-and-remove-style-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreeditingApplyStyleCommandcpp">trunk/Source/WebCore/editing/ApplyStyleCommand.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingEditingStylecpp">trunk/Source/WebCore/editing/EditingStyle.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingEditingStyleh">trunk/Source/WebCore/editing/EditingStyle.h</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorcpp">trunk/Source/WebCore/editing/Editor.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorh">trunk/Source/WebCore/editing/Editor.h</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorCommandcpp">trunk/Source/WebCore/editing/EditorCommand.cpp</a></li>
<li><a href="#trunkSourceWebKitmacChangeLog">trunk/Source/WebKit/mac/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitmacWebViewWebFramemm">trunk/Source/WebKit/mac/WebView/WebFrame.mm</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestseditingexecCommandtogglemixedtextdecorationsexpectedtxt">trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingexecCommandtogglemixedtextdecorationshtml">trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/LayoutTests/ChangeLog        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2015-05-04 Ryosuke Niwa <rniwa@webkit.org>
+
+ Toggling underline or strike through affects each other
+ https://bugs.webkit.org/show_bug.cgi?id=27818
+
+ Reviewed by Darin Adler.
+
+ Added a regression test and rebaselined various tests as explained below.
+
+ * editing/execCommand/script-tests/toggle-style-2.js: The order in which u and strike elements appear have switched.
+ * editing/execCommand/script-tests/toggle-text-decorations.js: Ditto for line-through and overline.
+ * editing/execCommand/toggle-mixed-text-decorations-expected.txt: Added.
+ * editing/execCommand/toggle-mixed-text-decorations.html: Added.
+ * editing/execCommand/toggle-style-2-expected.txt: Rebaselined.
+ * editing/execCommand/toggle-text-decorations-expected.txt: Rebaselined.
+ * editing/undo/remove-css-property-and-remove-style-expected.txt: The order in which color and font-weight properties
+ appear have switched.
+
</ins><span class="cx"> 2015-05-04 Chris Dumez <cdumez@apple.com>
</span><span class="cx">
</span><span class="cx"> REGRESSION (r178156): CSS Parser incorrectly rejects valid calc() in padding-right property
</span></span></pre></div>
<a id="trunkLayoutTestseditingexecCommandscriptteststogglestyle2js"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/execCommand/script-tests/toggle-style-2.js (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/execCommand/script-tests/toggle-style-2.js        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/LayoutTests/editing/execCommand/script-tests/toggle-style-2.js        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx"> testDoubleToggle("strikethrough", "test", "test");
</span><span class="cx">
</span><span class="cx"> testSingleToggle("strikethrough", "<u>test</u>", "<u><strike>test</strike></u>");
</span><del>-testSingleToggle("underline", "<strike>test</strike>", "<u><strike>test</strike></u>");
</del><ins>+testSingleToggle("underline", "<strike>test</strike>", "<strike><u>test</u></strike>");
</ins><span class="cx">
</span><span class="cx"> testSingleToggle("strikethrough", '<span style="text-decoration: overline;">test</span>', '<span style="text-decoration: overline;"><strike>test</strike></span>');
</span><span class="cx"> testSingleToggle("underline", '<span style="text-decoration: overline;">test</span>', '<span style="text-decoration: overline;"><u>test</u></span>');
</span></span></pre></div>
<a id="trunkLayoutTestseditingexecCommandscriptteststoggletextdecorationsjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/execCommand/script-tests/toggle-text-decorations.js (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/execCommand/script-tests/toggle-text-decorations.js        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/LayoutTests/editing/execCommand/script-tests/toggle-text-decorations.js        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -19,7 +19,8 @@
</span><span class="cx">
</span><span class="cx"> testSingleToggle("underline", "test", "<span style=\"text-decoration: underline;\">test</span>");
</span><span class="cx"> testSingleToggle("underline", "<span style=\"text-decoration: underline;\">test</span>", "test");
</span><del>-testSingleToggle("underline", "<span style=\"text-decoration: underline line-through overline;\">test</span>", "<span style=\"text-decoration: overline line-through;\">test</span>");
</del><ins>+testSingleToggle("underline", "<span style=\"text-decoration: underline line-through overline;\">test</span>",
+ "<span style=\"text-decoration: line-through overline;\">test</span>");
</ins><span class="cx"> testSingleToggle("strikethrough", "test", "<span style=\"text-decoration: line-through;\">test</span>");
</span><span class="cx"> testSingleToggle("strikethrough", "<span style=\"text-decoration: line-through;\">test</span>", "test");
</span><span class="cx"> testSingleToggle("strikethrough", "<span style=\"text-decoration: underline line-through overline;\">test</span>", "<span style=\"text-decoration: underline overline;\">test</span>");
</span></span></pre></div>
<a id="trunkLayoutTestseditingexecCommandtogglemixedtextdecorationsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations-expected.txt (0 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations-expected.txt         (rev 0)
+++ trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations-expected.txt        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -0,0 +1,79 @@
</span><ins>+Test to make sure we can toggle underline and strike through separately.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+document.execCommand("styleWithCSS", false, false);
+
+Toggling strikeThrough
+PASS content("<s><u>a</u>b</s>"); select(0, 2); toggle("strikeThrough") is "<u>a</u>b"
+PASS content("<s><u>a</u>b<u>c</u></s>"); select(0, 3); toggle("strikeThrough") is "<u>a</u>b<u>c</u>"
+PASS content("<s>a<u>b</u>c</s>"); select(0, 3); toggle("strikeThrough") is "a<u>b</u>c"
+PASS content("<s>a<u>b</u>c</s>"); select(1, 3); toggle("strikeThrough") is "<strike>a</strike><u>b</u>c"
+PASS content("<s>a<u>b</u>c</s>"); select(0, 2); toggle("strikeThrough") is "a<u>b</u><strike>c</strike>"
+PASS content("<s><u>ab</u></s>c"); select(1, 3); toggle("strikeThrough") is "<u><strike>a</strike>b</u>c"
+PASS content("<s>a<u>b</u></s>c"); select(1, 3); toggle("strikeThrough") is "<strike>a</strike><u>b</u>c"
+PASS content("a<s><u>b</u>c</s>"); select(0, 2); toggle("strikeThrough") is "<strike>a</strike><s><u>b</u>c</s>"
+PASS content("a<strike><u>b</u>c</strike>"); select(0, 2); toggle("strikeThrough") is "<strike>a<u>b</u>c</strike>"
+PASS content("a<u><s>bc</s></u>"); select(0, 2); toggle("strikeThrough") is "<strike>a</strike><u><s>bc</s></u>"
+PASS content("a<s><b><u>bc</u></b></s>"); select(0, 2); toggle("strikeThrough") is "<strike>a</strike><s><b><u>bc</u></b></s>"
+PASS content("a<strike><b><u>bc</u></b></strike>"); select(0, 2); toggle("strikeThrough") is "<strike>a<b><u>bc</u></b></strike>"
+
+Toggling underline
+PASS content("<u><s>a</s>b</u>"); select(0, 2); toggle("underline") is "<s>a</s>b"
+PASS content("<u><s>a</s>b<s>c</s></u>"); select(0, 3); toggle("underline") is "<s>a</s>b<s>c</s>"
+PASS content("<u>a<s>b</s>c</u>"); select(0, 3); toggle("underline") is "a<s>b</s>c"
+PASS content("<u>a<s>b</s>c</u>"); select(1, 3); toggle("underline") is "<u>a</u><s>b</s>c"
+PASS content("<u>a<s>b</s>c</u>"); select(0, 2); toggle("underline") is "a<s>b</s><u>c</u>"
+PASS content("<u><s>ab</s></u>c"); select(1, 3); toggle("underline") is "<s><u>a</u>b</s>c"
+PASS content("<u>a<s>b</s></u>c"); select(1, 3); toggle("underline") is "<u>a</u><s>b</s>c"
+PASS content("a<u><s>b</s>c</u>"); select(0, 2); toggle("underline") is "<u>a<s>b</s>c</u>"
+PASS content("a<s><u>bc</u></s>"); select(0, 2); toggle("underline") is "<u>a</u><s><u>bc</u></s>"
+PASS content("a<u><b><s>bc</s></b></u>"); select(0, 2); toggle("underline") is "<u>a<b><s>bc</s></b></u>"
+document.execCommand("styleWithCSS", false, true);
+
+Toggling strikeThrough
+PASS content('<span style="text-decoration: line-through;"><span style="text-decoration: underline">a</span>b</span>');
+select(0, 2); toggle("strikeThrough") is '<span style="text-decoration: underline;">a</span>b'
+PASS content('<span style="text-decoration: line-through;"><span style="text-decoration: underline;">a</span>b<span style="text-decoration: underline">c</span></span>');
+select(0, 3); toggle("strikeThrough") is '<span style="text-decoration: underline;">a</span>b<span style="text-decoration: underline;">c</span>'
+PASS content('<span style="text-decoration: line-through;">a<span style="text-decoration: underline;">b</span>c</span>');
+select(0, 3); toggle("strikeThrough") is 'a<span style="text-decoration: underline;">b</span>c'
+PASS content('<span style="text-decoration: line-through;">a<span style="text-decoration: underline;">b</span>c</span>');
+select(1, 3); toggle("strikeThrough") is '<span style="text-decoration: line-through;">a</span><span style="text-decoration: underline;">b</span>c'
+PASS content('<span style="text-decoration: line-through;">a<span style="text-decoration: underline;">b</span>c</span>');
+select(0, 2); toggle("strikeThrough") is 'a<span style="text-decoration: underline;">b</span><span style="text-decoration: line-through;">c</span>'
+PASS content('<span style="text-decoration: line-through;"><span style="text-decoration: underline;">ab</span></span>c');
+select(1, 3); toggle("strikeThrough") is '<span style="text-decoration: underline;"><span style="text-decoration: line-through;">a</span>b</span>c'
+PASS content('a<span style="text-decoration: line-through;"><span style="text-decoration: underline;">b</span>c</span>');
+select(0, 2); toggle("strikeThrough") is '<span style="text-decoration: line-through;">a<span style="text-decoration: underline line-through;">b</span>c</span>'
+PASS content('a<span style="text-decoration: underline;"><span style="text-decoration: line-through;">bc</span></span>');
+select(0, 2); toggle("strikeThrough") is '<span style="text-decoration: line-through;">a</span><span style="text-decoration: underline;"><span style="text-decoration: line-through;">bc</span></span>'
+PASS content('a<span style="text-decoration: line-through;"><b><span style="text-decoration: underline;">bc</span></b></span>');
+select(0, 2); toggle("strikeThrough") is '<span style="text-decoration: line-through;">a<b><span style="text-decoration: underline;"><span style="text-decoration: underline line-through;">b</span>c</span></b></span>'
+
+Toggling underline
+PASS content('<span style="text-decoration: underline;"><span style="text-decoration: line-through;">a</span>b</span>');
+select(0, 2); toggle("underline") is '<span style="text-decoration: line-through;">a</span>b'
+PASS content('<span style="text-decoration: underline;"><span style="text-decoration: line-through;">a</span>b<span style="text-decoration: line-through;">c</span></span>');
+select(0, 3); toggle("underline") is '<span style="text-decoration: line-through;">a</span>b<span style="text-decoration: line-through;">c</span>'
+PASS content('<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span>c</span>');
+select(0, 3); toggle("underline") is 'a<span style="text-decoration: line-through;">b</span>c'
+PASS content('<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span>c</span>');
+select(1, 3); toggle("underline") is '<span style="text-decoration: underline;">a</span><span style="text-decoration: line-through;">b</span>c'
+PASS content('<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span>c</span>');
+select(0, 2); toggle("underline") is 'a<span style="text-decoration: line-through;">b</span><span style="text-decoration: underline;">c</span>'
+PASS content('<span style="text-decoration: underline;"><span style="text-decoration: line-through;">ab</span></span>c');
+select(1, 3); toggle("underline") is '<span style="text-decoration: line-through;"><span style="text-decoration: underline;">a</span>b</span>c'
+PASS content('<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span></span>c');
+select(1, 3); toggle("underline") is '<span style="text-decoration: underline;">a</span><span style="text-decoration: line-through;">b</span>c'
+PASS content('a<span style="text-decoration: underline;"><span style="text-decoration: line-through;">b</span>c</span>');
+select(0, 2); toggle("underline") is '<span style="text-decoration: underline;">a<span style="text-decoration: line-through underline;">b</span>c</span>'
+PASS content('a<span style="text-decoration: line-through;"><span style="text-decoration: underline;">bc</span></span>');
+select(0, 2); toggle("underline") is '<span style="text-decoration: underline;">a</span><span style="text-decoration: line-through;"><span style="text-decoration: underline;">bc</span></span>'
+PASS content('a<span style="text-decoration: underline;"><b><span style="text-decoration: line-through;">bc</span></b></span>');
+select(0, 2); toggle("underline") is '<span style="text-decoration: underline;">a<b><span style="text-decoration: line-through;"><span style="text-decoration: underline line-through;">b</span>c</span></b></span>'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestseditingexecCommandtogglemixedtextdecorationshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations.html (0 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations.html         (rev 0)
+++ trunk/LayoutTests/editing/execCommand/toggle-mixed-text-decorations.html        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -0,0 +1,149 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Test to make sure we can toggle underline and strike through separately.")
+
+var testContainer = document.createElement("div");
+testContainer.contentEditable = true;
+document.body.appendChild(testContainer);
+
+function testSingleToggle(toggleCommand, initialContents, expectedContents)
+{
+ testContainer.innerHTML = initialContents;
+ getSelection().collapse(testContainer, 0);
+ getSelection().modify('')
+ window.getSelection().selectAllChildren(testContainer);
+ document.execCommand("styleWithCSS", false, false);
+ document.execCommand(toggleCommand, false, null);
+ if (testContainer.innerHTML === expectedContents) {
+ testPassed("one " + toggleCommand + " command converted " + initialContents + " to " + expectedContents);
+ } else {
+ testFailed("one " + toggleCommand + " command converted " + initialContents + " to " + testContainer.innerHTML + ", expected " + expectedContents);
+ }
+}
+
+function content(markup) {
+ testContainer.innerHTML = markup;
+}
+
+function select(offset, extent) {
+ getSelection().collapse(testContainer, 0);
+ for (var i = 0; i < offset; i++)
+ getSelection().modify('move', 'forward', 'character');
+ for (var i = offset; i < extent; i++)
+ getSelection().modify('extend', 'forward', 'character');
+}
+
+function toggle(command) {
+ document.execCommand(command, false, null);
+ return testContainer.innerHTML;
+}
+
+evalAndLog('document.execCommand("styleWithCSS", false, false);');
+
+debug('');
+debug('Toggling strikeThrough');
+shouldBe('content("<s><u>a</u>b</s>"); select(0, 2); toggle("strikeThrough")', '"<u>a</u>b"');
+shouldBe('content("<s><u>a</u>b<u>c</u></s>"); select(0, 3); toggle("strikeThrough")', '"<u>a</u>b<u>c</u>"');
+shouldBe('content("<s>a<u>b</u>c</s>"); select(0, 3); toggle("strikeThrough")', '"a<u>b</u>c"');
+shouldBe('content("<s>a<u>b</u>c</s>"); select(1, 3); toggle("strikeThrough")', '"<strike>a</strike><u>b</u>c"');
+shouldBe('content("<s>a<u>b</u>c</s>"); select(0, 2); toggle("strikeThrough")', '"a<u>b</u><strike>c</strike>"');
+shouldBe('content("<s><u>ab</u></s>c"); select(1, 3); toggle("strikeThrough")', '"<u><strike>a</strike>b</u>c"');
+shouldBe('content("<s>a<u>b</u></s>c"); select(1, 3); toggle("strikeThrough")', '"<strike>a</strike><u>b</u>c"');
+shouldBe('content("a<s><u>b</u>c</s>"); select(0, 2); toggle("strikeThrough")', '"<strike>a</strike><s><u>b</u>c</s>"');
+shouldBe('content("a<strike><u>b</u>c</strike>"); select(0, 2); toggle("strikeThrough")', '"<strike>a<u>b</u>c</strike>"');
+shouldBe('content("a<u><s>bc</s></u>"); select(0, 2); toggle("strikeThrough")', '"<strike>a</strike><u><s>bc</s></u>"');
+shouldBe('content("a<s><b><u>bc</u></b></s>"); select(0, 2); toggle("strikeThrough")', '"<strike>a</strike><s><b><u>bc</u></b></s>"');
+shouldBe('content("a<strike><b><u>bc</u></b></strike>"); select(0, 2); toggle("strikeThrough")', '"<strike>a<b><u>bc</u></b></strike>"');
+
+debug('');
+debug('Toggling underline');
+shouldBe('content("<u><s>a</s>b</u>"); select(0, 2); toggle("underline")', '"<s>a</s>b"');
+shouldBe('content("<u><s>a</s>b<s>c</s></u>"); select(0, 3); toggle("underline")', '"<s>a</s>b<s>c</s>"');
+shouldBe('content("<u>a<s>b</s>c</u>"); select(0, 3); toggle("underline")', '"a<s>b</s>c"');
+shouldBe('content("<u>a<s>b</s>c</u>"); select(1, 3); toggle("underline")', '"<u>a</u><s>b</s>c"');
+shouldBe('content("<u>a<s>b</s>c</u>"); select(0, 2); toggle("underline")', '"a<s>b</s><u>c</u>"');
+shouldBe('content("<u><s>ab</s></u>c"); select(1, 3); toggle("underline")', '"<s><u>a</u>b</s>c"');
+shouldBe('content("<u>a<s>b</s></u>c"); select(1, 3); toggle("underline")', '"<u>a</u><s>b</s>c"');
+shouldBe('content("a<u><s>b</s>c</u>"); select(0, 2); toggle("underline")', '"<u>a<s>b</s>c</u>"');
+shouldBe('content("a<s><u>bc</u></s>"); select(0, 2); toggle("underline")', '"<u>a</u><s><u>bc</u></s>"');
+shouldBe('content("a<u><b><s>bc</s></b></u>"); select(0, 2); toggle("underline")', '"<u>a<b><s>bc</s></b></u>"');
+
+evalAndLog('document.execCommand("styleWithCSS", false, true);');
+
+debug('');
+debug('Toggling strikeThrough');
+shouldBe('content(\'<span style="text-decoration: line-through;"><span style="text-decoration: underline">a</span>b</span>\');\n'
+ + 'select(0, 2); toggle("strikeThrough")',
+ '\'<span style="text-decoration: underline;">a</span>b\'');
+shouldBe('content(\'<span style="text-decoration: line-through;"><span style="text-decoration: underline;">a</span>b<span style="text-decoration: underline">c</span></span>\');\n'
+ + 'select(0, 3); toggle("strikeThrough")',
+ '\'<span style="text-decoration: underline;">a</span>b<span style="text-decoration: underline;">c</span>\'');
+shouldBe('content(\'<span style="text-decoration: line-through;">a<span style="text-decoration: underline;">b</span>c</span>\');\n'
+ + 'select(0, 3); toggle("strikeThrough")',
+ '\'a<span style="text-decoration: underline;">b</span>c\'');
+shouldBe('content(\'<span style="text-decoration: line-through;">a<span style="text-decoration: underline;">b</span>c</span>\');\n'
+ + 'select(1, 3); toggle("strikeThrough")',
+ '\'<span style="text-decoration: line-through;">a</span><span style="text-decoration: underline;">b</span>c\'');
+shouldBe('content(\'<span style="text-decoration: line-through;">a<span style="text-decoration: underline;">b</span>c</span>\');\n'
+ + 'select(0, 2); toggle("strikeThrough")',
+ '\'a<span style="text-decoration: underline;">b</span><span style="text-decoration: line-through;">c</span>\'');
+shouldBe('content(\'<span style="text-decoration: line-through;"><span style="text-decoration: underline;">ab</span></span>c\');\n'
+ + 'select(1, 3); toggle("strikeThrough")',
+ '\'<span style="text-decoration: underline;"><span style="text-decoration: line-through;">a</span>b</span>c\'');
+shouldBe('content(\'a<span style="text-decoration: line-through;"><span style="text-decoration: underline;">b</span>c</span>\');\n'
+ + 'select(0, 2); toggle("strikeThrough")',
+ '\'<span style="text-decoration: line-through;">a<span style="text-decoration: underline line-through;">b</span>c</span>\'');
+shouldBe('content(\'a<span style="text-decoration: underline;"><span style="text-decoration: line-through;">bc</span></span>\');\n'
+ + 'select(0, 2); toggle("strikeThrough")',
+ '\'<span style="text-decoration: line-through;">a</span><span style="text-decoration: underline;"><span style="text-decoration: line-through;">bc</span></span>\'');
+shouldBe('content(\'a<span style="text-decoration: line-through;"><b><span style="text-decoration: underline;">bc</span></b></span>\');\n'
+ + 'select(0, 2); toggle("strikeThrough")',
+ '\'<span style="text-decoration: line-through;">a<b><span style="text-decoration: underline;"><span style="text-decoration: underline line-through;">b</span>c</span></b></span>\'');
+
+debug('');
+debug('Toggling underline');
+shouldBe('content(\'<span style="text-decoration: underline;"><span style="text-decoration: line-through;">a</span>b</span>\');\n'
+ + 'select(0, 2); toggle("underline")',
+ '\'<span style="text-decoration: line-through;">a</span>b\'');
+shouldBe('content(\'<span style="text-decoration: underline;"><span style="text-decoration: line-through;">a</span>b<span style="text-decoration: line-through;">c</span></span>\');\n'
+ + 'select(0, 3); toggle("underline")',
+ '\'<span style="text-decoration: line-through;">a</span>b<span style="text-decoration: line-through;">c</span>\'');
+shouldBe('content(\'<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span>c</span>\');\n'
+ + 'select(0, 3); toggle("underline")',
+ '\'a<span style="text-decoration: line-through;">b</span>c\'');
+shouldBe('content(\'<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span>c</span>\');\n'
+ + 'select(1, 3); toggle("underline")',
+ '\'<span style="text-decoration: underline;">a</span><span style="text-decoration: line-through;">b</span>c\'');
+shouldBe('content(\'<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span>c</span>\');\n'
+ + 'select(0, 2); toggle("underline")',
+ '\'a<span style="text-decoration: line-through;">b</span><span style="text-decoration: underline;">c</span>\'');
+shouldBe('content(\'<span style="text-decoration: underline;"><span style="text-decoration: line-through;">ab</span></span>c\');\n'
+ + 'select(1, 3); toggle("underline")',
+ '\'<span style="text-decoration: line-through;"><span style="text-decoration: underline;">a</span>b</span>c\'');
+shouldBe('content(\'<span style="text-decoration: underline;">a<span style="text-decoration: line-through;">b</span></span>c\');\n'
+ + 'select(1, 3); toggle("underline")',
+ '\'<span style="text-decoration: underline;">a</span><span style="text-decoration: line-through;">b</span>c\'');
+shouldBe('content(\'a<span style="text-decoration: underline;"><span style="text-decoration: line-through;">b</span>c</span>\');\n'
+ + 'select(0, 2); toggle("underline")',
+ '\'<span style="text-decoration: underline;">a<span style="text-decoration: line-through underline;">b</span>c</span>\'');
+shouldBe('content(\'a<span style="text-decoration: line-through;"><span style="text-decoration: underline;">bc</span></span>\');\n'
+ + 'select(0, 2); toggle("underline")',
+ '\'<span style="text-decoration: underline;">a</span><span style="text-decoration: line-through;"><span style="text-decoration: underline;">bc</span></span>\'');
+shouldBe('content(\'a<span style="text-decoration: underline;"><b><span style="text-decoration: line-through;">bc</span></b></span>\');\n'
+ + 'select(0, 2); toggle("underline")',
+ '\'<span style="text-decoration: underline;">a<b><span style="text-decoration: line-through;"><span style="text-decoration: underline line-through;">b</span>c</span></b></span>\'');
+
+document.body.removeChild(testContainer);
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestseditingexecCommandtogglestyle2expectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/execCommand/toggle-style-2-expected.txt (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/execCommand/toggle-style-2-expected.txt        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/LayoutTests/editing/execCommand/toggle-style-2-expected.txt        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -10,7 +10,7 @@
</span><span class="cx"> PASS one strikethrough command converted <u><b><strike>test</strike></b></u> to <u><b>test</b></u>
</span><span class="cx"> PASS two strikethrough commands converted test to test
</span><span class="cx"> PASS one strikethrough command converted <u>test</u> to <u><strike>test</strike></u>
</span><del>-PASS one underline command converted <strike>test</strike> to <u><strike>test</strike></u>
</del><ins>+PASS one underline command converted <strike>test</strike> to <strike><u>test</u></strike>
</ins><span class="cx"> PASS one strikethrough command converted <span style="text-decoration: overline;">test</span> to <span style="text-decoration: overline;"><strike>test</strike></span>
</span><span class="cx"> PASS one underline command converted <span style="text-decoration: overline;">test</span> to <span style="text-decoration: overline;"><u>test</u></span>
</span><span class="cx"> PASS successfullyParsed is true
</span></span></pre></div>
<a id="trunkLayoutTestseditingexecCommandtoggletextdecorationsexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/execCommand/toggle-text-decorations-expected.txt (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/execCommand/toggle-text-decorations-expected.txt        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/LayoutTests/editing/execCommand/toggle-text-decorations-expected.txt        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -5,7 +5,7 @@
</span><span class="cx">
</span><span class="cx"> PASS one underline command converted test to <span style="text-decoration: underline;">test</span>
</span><span class="cx"> PASS one underline command converted <span style="text-decoration: underline;">test</span> to test
</span><del>-PASS one underline command converted <span style="text-decoration: underline line-through overline;">test</span> to <span style="text-decoration: overline line-through;">test</span>
</del><ins>+PASS one underline command converted <span style="text-decoration: underline line-through overline;">test</span> to <span style="text-decoration: line-through overline;">test</span>
</ins><span class="cx"> PASS one strikethrough command converted test to <span style="text-decoration: line-through;">test</span>
</span><span class="cx"> PASS one strikethrough command converted <span style="text-decoration: line-through;">test</span> to test
</span><span class="cx"> PASS one strikethrough command converted <span style="text-decoration: underline line-through overline;">test</span> to <span style="text-decoration: underline overline;">test</span>
</span></span></pre></div>
<a id="trunkLayoutTestseditingundoremovecsspropertyandremovestyleexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/undo/remove-css-property-and-remove-style-expected.txt (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/undo/remove-css-property-and-remove-style-expected.txt        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/LayoutTests/editing/undo/remove-css-property-and-remove-style-expected.txt        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">
</span><span class="cx"> Undo should reset the style attribute so that "test" is both bold and blue:
</span><span class="cx"> | <span>
</span><del>-| style="color: blue; font-weight: 900;"
</del><ins>+| style="font-weight: 900; color: blue;"
</ins><span class="cx"> | "<#selection-anchor>test<#selection-focus>"
</span><span class="cx">
</span><span class="cx"> Redo should only remove font-weight and leave "test" blue:
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebCore/ChangeLog        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -1,3 +1,105 @@
</span><ins>+2015-05-04 Ryosuke Niwa <rniwa@webkit.org>
+
+ Toggling underline or strike through affects each other
+ https://bugs.webkit.org/show_bug.cgi?id=27818
+
+ Reviewed by Darin Adler.
+
+ This patch introduces a new mechanism to apply and remove text decorations. This is necessary because text
+ decorations are always additive and we can't differentiate whether we're adding or removing a text decoration.
+ Conceptually, we need four values for text decorations: adding underline, removing underline, adding
+ line-through, and removing line-through but we have only three: underline, line-through, none.
+
+ After this patch, there are three mechanism by which text decorations states are kept tracked. While applying
+ or removing text decorations, we use newly added m_underlineChange and m_strikeThroughChange in EditingStyle.
+ For the typing style, we use -webkit-text-decorations-in-effect to store the state since we need to preserve
+ every type of text decorations such as overline in addition to underline and line-through. Once applied, all
+ text decorations should be expressed in terms of the standard text-decoration property.
+
+ Test: editing/execCommand/toggle-mixed-text-decorations.html
+
+ * editing/ApplyStyleCommand.cpp:
+ (WebCore::ApplyStyleCommand::applyBlockStyle):
+ (WebCore::ApplyStyleCommand::removeCSSStyle): conflictsWithInlineStyleOfElement now creates a new inline style
+ instead of a list of properties to remove.
+ (WebCore::ApplyStyleCommand::addBlockStyle):
+ (WebCore::ApplyStyleCommand::applyInlineStyleChange): Merge inline styles instead of adding as string.
+ Otherwise it would generate style content attribute with multiple text-decoration properties.
+
+ * editing/EditingStyle.cpp:
+ (WebCore::HTMLElementEquivalent::matches):
+ (WebCore::HTMLElementEquivalent::propertyExistsInStyle): Takes an EditingStyle instead of StyleProperties.
+ (WebCore::HTMLElementEquivalent::valueIsPresentInStyle):
+ (WebCore::HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent):
+ (WebCore::HTMLTextDecorationEquivalent::propertyExistsInStyle): Respect newly added m_strikeThroughChange and
+ m_underlineChange in EditingStyle.
+ (WebCore::HTMLTextDecorationEquivalent::valueIsPresentInStyle): Ditto.
+ (WebCore::HTMLTextDecorationEquivalent::changeInStyle): Added. Retrieves the change enum for the associated
+ type of text-decoration (underline or strike through).
+ (WebCore::HTMLAttributeEquivalent::matches):
+ (WebCore::HTMLAttributeEquivalent::valueIsPresentInStyle):
+ (WebCore::EditingStyle::EditingStyle): Initialize m_underlineChange and m_strikeThroughChange. Also use the
+ delegating constructor elsewhere. Also added the missing call to extractFontSizeDelta() in the variant that
+ takes CSSPropertyID and String, and added a variant that takes CSSPropertyID and CSSValueID.
+ (WebCore::EditingStyle::isEmpty): Return false when m_underlineChange and m_strikeThroughChange are not "none".
+ (WebCore::applyTextDecorationChangeToValueList): Added.
+ (WebCore::EditingStyle::overrideTypingStyleAt): Added. Used by Editor::computeAndSetTypingStyle to set a new
+ typing style. Resolve m_underlineChange and m_strikeThroughChange into -webkit-text-decorations-in-effect.
+ (WebCore::EditingStyle::clear): Clear m_underlineChange and m_strikeThroughChange.
+ (WebCore::EditingStyle::copy): Copy m_underlineChange and m_strikeThroughChange.
+ (WebCore::textDecorationValueList): Added.
+ (WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Now takes a pointer to MutableStyleProperties
+ instead of a vector. This was necessary we can't simply remove text-decoration property in ApplyStyleCommand's
+ removeCSSStyle as that would result in unrelated text decorations also getting removed. Also added the code
+ for m_underlineChange and m_strikeThroughChange. Only removing text decoration changes can cause a conflict
+ since text decorations are always additive.
+ (WebCore::EditingStyle::conflictsWithImplicitStyleOfElement): Check isEmpty() instead of the nullity of
+ m_mutableStyle to respect m_underlineChange and m_strikeThroughChange.
+ (WebCore::EditingStyle::conflictsWithImplicitStyleOfAttributes):
+ (WebCore::EditingStyle::extractConflictingImplicitStyleOfAttributes):
+ (WebCore::EditingStyle::styleIsPresentInComputedStyleOfNode): Respect the values of m_underlineChange and
+ m_strikeThroughChange. Here, the style is considered present if it has text decorations that are being added.
+ (WebCore::EditingStyle::elementIsStyledSpanOrHTMLEquivalent):
+ (WebCore::elementMatchesAndPropertyIsNotInInlineStyleDecl): Takes EditingStyle instead of StyleProperties to
+ respect m_underlineChange and m_strikeThroughChange.
+ (WebCore::EditingStyle::mergeInlineAndImplicitStyleOfElement):
+ (WebCore::mergeTextDecorationValues):
+ (WebCore::EditingStyle::mergeStyle): Make a copy of CSSValueList before modifying it since CSSValueList's are
+ shared with other immutable StyleProperties.
+ (WebCore::StyleChange::StyleChange): Set m_applyUnderline, m_applyLineThrough, and m_cssStyle if either
+ m_underlineChange or m_strikeThroughChange are TextDecorationChange::Add in EditingStyle if the current position
+ doesn't already have the matching style.
+ (WebCore::StyleChange::operator==): Moved from the header file. Also added the logic to compare m_cssStyle now
+ that it's a StyleProperties instead of String.
+
+ * editing/EditingStyle.h: Added TextDecorationChange.
+ (WebCore::EditingStyle::create): Added a variant that takes CSSPropertyID and CSSValueID.
+ (WebCore::EditingStyle::conflictsWithInlineStyleOfElement):
+ (WebCore::EditingStyle::setUnderlineChange): Added.
+ (WebCore::EditingStyle::underlineChange): Added.
+ (WebCore::EditingStyle::setStrikeThroughChange): Added.
+ (WebCore::EditingStyle::strikeThroughChange): Added.
+ (WebCore::StyleChange::cssStyle): Now returns StyleProperties* instead of String so that ApplyStyleCommand's
+ applyInlineStyleChange could merge inline styles instead of just appending it to the end.
+ (WebCore::StyleChange::operator==): Moved into the cpp file.
+
+ * editing/Editor.cpp:
+ (WebCore::Editor::applyStyle): Added. This variant takes EditingStyle instead of StyleProperties.
+ (WebCore::Editor::applyStyleToSelection): Ditto.
+ (WebCore::Editor::computeAndSetTypingStyle): Added a variant for EditingStyle. Also use overrideTypingStyleAt
+ to set -webkit-text-decorations-in-effect based on m_underlineChange and m_strikeThroughChange
+
+ * editing/Editor.h:
+ * editing/EditorCommand.cpp:
+ (WebCore::applyCommandToFrame):
+ (WebCore::isStylePresent): Extracted from executeToggleStyle.
+ (WebCore::executeApplyStyle):
+ (WebCore::executeToggleStyle):
+ (WebCore::executeToggleStyleInList): Deleted.
+ (WebCore::textDecorationChangeForToggling): Added. Used in executeStrikethrough and executeUnderline.
+ (WebCore::executeStrikethrough):
+ (WebCore::executeUnderline):
+
</ins><span class="cx"> 2015-05-04 Eric Carlson <eric.carlson@apple.com>
</span><span class="cx">
</span><span class="cx"> [Mac] Fix build breakage caused by API deprecation
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingApplyStyleCommandcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/ApplyStyleCommand.cpp (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/ApplyStyleCommand.cpp        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebCore/editing/ApplyStyleCommand.cpp        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -263,7 +263,7 @@
</span><span class="cx"> VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next());
</span><span class="cx"> while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) {
</span><span class="cx"> StyleChange styleChange(style, paragraphStart.deepEquivalent());
</span><del>- if (styleChange.cssStyle().length() || m_removeOnly) {
</del><ins>+ if (styleChange.cssStyle() || m_removeOnly) {
</ins><span class="cx"> RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().deprecatedNode());
</span><span class="cx"> if (!m_removeOnly) {
</span><span class="cx"> RefPtr<Node> newBlock = moveParagraphContentsToNewBlockIfNecessary(paragraphStart.deepEquivalent());
</span><span class="lines">@@ -945,17 +945,14 @@
</span><span class="cx"> if (mode == RemoveNone)
</span><span class="cx"> return style->conflictsWithInlineStyleOfElement(element);
</span><span class="cx">
</span><del>- Vector<CSSPropertyID> properties;
- if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle, properties))
</del><ins>+ RefPtr<MutableStyleProperties> newInlineStyle;
+ if (!style->conflictsWithInlineStyleOfElement(element, newInlineStyle, extractedStyle))
</ins><span class="cx"> return false;
</span><span class="cx">
</span><del>- // FIXME: We should use a mass-removal function here but we don't have an undoable one yet.
- for (size_t i = 0; i < properties.size(); i++)
- removeCSSProperty(element, properties[i]);
-
- // No need to serialize <foo style=""> if we just removed the last css property
- if (element->inlineStyle()->isEmpty())
</del><ins>+ if (newInlineStyle->isEmpty())
</ins><span class="cx"> removeNodeAttribute(element, styleAttr);
</span><ins>+ else
+ setNodeAttribute(element, styleAttr, newInlineStyle->asText());
</ins><span class="cx">
</span><span class="cx"> if (isSpanWithoutAttributesOrUnstyledStyleSpan(element))
</span><span class="cx"> removeNodePreservingChildren(element);
</span><span class="lines">@@ -1370,12 +1367,13 @@
</span><span class="cx">
</span><span class="cx"> void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElement* block)
</span><span class="cx"> {
</span><ins>+ ASSERT(styleChange.cssStyle());
</ins><span class="cx"> // Do not check for legacy styles here. Those styles, like <B> and <I>, only apply for
</span><span class="cx"> // inline content.
</span><span class="cx"> if (!block)
</span><span class="cx"> return;
</span><span class="cx">
</span><del>- String cssStyle = styleChange.cssStyle();
</del><ins>+ String cssStyle = styleChange.cssStyle()->asText();
</ins><span class="cx"> StringBuilder cssText;
</span><span class="cx"> cssText.append(cssStyle);
</span><span class="cx"> if (const StyleProperties* decl = block->inlineStyle()) {
</span><span class="lines">@@ -1456,21 +1454,17 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (styleChange.cssStyle().length()) {
</del><ins>+ if (auto styleToMerge = styleChange.cssStyle()) {
</ins><span class="cx"> if (styleContainer) {
</span><del>- if (const StyleProperties* existingStyle = styleContainer->inlineStyle()) {
- String existingText = existingStyle->asText();
- StringBuilder cssText;
- cssText.append(existingText);
- if (!existingText.isEmpty())
- cssText.append(' ');
- cssText.append(styleChange.cssStyle());
- setNodeAttribute(styleContainer, styleAttr, cssText.toString());
</del><ins>+ if (auto existingStyle = styleContainer->inlineStyle()) {
+ auto inlineStyle = EditingStyle::create(existingStyle);
+ inlineStyle->overrideWithStyle(styleToMerge);
+ setNodeAttribute(styleContainer, styleAttr, inlineStyle->style()->asText());
</ins><span class="cx"> } else
</span><del>- setNodeAttribute(styleContainer, styleAttr, styleChange.cssStyle());
</del><ins>+ setNodeAttribute(styleContainer, styleAttr, styleToMerge->asText());
</ins><span class="cx"> } else {
</span><span class="cx"> RefPtr<Element> styleElement = createStyleSpanElement(document());
</span><del>- styleElement->setAttribute(styleAttr, styleChange.cssStyle());
</del><ins>+ styleElement->setAttribute(styleAttr, styleToMerge->asText());
</ins><span class="cx"> surroundNodeRangeWithElement(startNode, endNode, styleElement.release());
</span><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditingStylecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/EditingStyle.cpp (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/EditingStyle.cpp        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebCore/editing/EditingStyle.cpp        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -160,10 +160,10 @@
</span><span class="cx"> HTMLElementEquivalent(CSSPropertyID, CSSValueID primitiveValue, const QualifiedName& tagName);
</span><span class="cx">
</span><span class="cx"> virtual ~HTMLElementEquivalent() { }
</span><del>- virtual bool matches(const Element* element) const { return !m_tagName || element->hasTagName(*m_tagName); }
</del><ins>+ virtual bool matches(const Element& element) const { return !m_tagName || element.hasTagName(*m_tagName); }
</ins><span class="cx"> virtual bool hasAttribute() const { return false; }
</span><del>- virtual bool propertyExistsInStyle(const StyleProperties* style) const { return style->getPropertyCSSValue(m_propertyID); }
- virtual bool valueIsPresentInStyle(Element*, StyleProperties*) const;
</del><ins>+ virtual bool propertyExistsInStyle(const EditingStyle& style) const { return style.m_mutableStyle && style.m_mutableStyle->getPropertyCSSValue(m_propertyID); }
+ virtual bool valueIsPresentInStyle(Element&, const EditingStyle&) const;
</ins><span class="cx"> virtual void addToStyle(Element*, EditingStyle*) const;
</span><span class="cx">
</span><span class="cx"> protected:
</span><span class="lines">@@ -194,9 +194,9 @@
</span><span class="cx"> ASSERT(primitiveValue != CSSValueInvalid);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool HTMLElementEquivalent::valueIsPresentInStyle(Element* element, StyleProperties* style) const
</del><ins>+bool HTMLElementEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const
</ins><span class="cx"> {
</span><del>- RefPtr<CSSValue> value = style->getPropertyCSSValue(m_propertyID);
</del><ins>+ RefPtr<CSSValue> value = style.m_mutableStyle->getPropertyCSSValue(m_propertyID);
</ins><span class="cx"> return matches(element) && is<CSSPrimitiveValue>(value.get()) && downcast<CSSPrimitiveValue>(*value).getValueID() == m_primitiveValue->getValueID();
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -207,39 +207,55 @@
</span><span class="cx">
</span><span class="cx"> class HTMLTextDecorationEquivalent : public HTMLElementEquivalent {
</span><span class="cx"> public:
</span><del>- HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName);
</del><ins>+ HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName)
+ : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)
+ , m_isUnderline(primitiveValue == CSSValueUnderline)
+ {
+ }
</ins><span class="cx">
</span><del>- virtual bool propertyExistsInStyle(const StyleProperties*) const;
- virtual bool valueIsPresentInStyle(Element*, StyleProperties*) const;
-};
</del><ins>+ bool propertyExistsInStyle(const EditingStyle& style) const override
+ {
+ if (changeInStyle(style) != TextDecorationChange::None)
+ return true;
</ins><span class="cx">
</span><del>-HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName)
- : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)
- // m_propertyID is used in HTMLElementEquivalent::addToStyle
-{
-}
</del><ins>+ if (!style.m_mutableStyle)
+ return false;
</ins><span class="cx">
</span><del>-bool HTMLTextDecorationEquivalent::propertyExistsInStyle(const StyleProperties* style) const
-{
- return style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) || style->getPropertyCSSValue(CSSPropertyTextDecoration);
-}
</del><ins>+ auto& mutableStyle = *style.m_mutableStyle;
+ return mutableStyle.getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect)
+ || mutableStyle.getPropertyCSSValue(CSSPropertyTextDecoration);
+ }
</ins><span class="cx">
</span><del>-bool HTMLTextDecorationEquivalent::valueIsPresentInStyle(Element* element, StyleProperties* style) const
-{
- RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
- if (!styleValue)
- styleValue = style->getPropertyCSSValue(CSSPropertyTextDecoration);
- return matches(element) && is<CSSValueList>(styleValue.get()) && downcast<CSSValueList>(*styleValue).hasValue(m_primitiveValue.get());
-}
</del><ins>+ bool valueIsPresentInStyle(Element& element, const EditingStyle& style) const override
+ {
+ if (!matches(element))
+ return false;
+ auto change = changeInStyle(style);
+ if (change != TextDecorationChange::None)
+ return change == TextDecorationChange::Add;
+ RefPtr<CSSValue> styleValue = style.m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
+ if (!styleValue)
+ styleValue = style.m_mutableStyle->getPropertyCSSValue(CSSPropertyTextDecoration);
+ return is<CSSValueList>(styleValue.get()) && downcast<CSSValueList>(*styleValue).hasValue(m_primitiveValue.get());
+ }
</ins><span class="cx">
</span><ins>+private:
+ TextDecorationChange changeInStyle(const EditingStyle& style) const
+ {
+ return m_isUnderline ? style.underlineChange() : style.strikeThroughChange();
+ }
+
+ bool m_isUnderline;
+};
+
</ins><span class="cx"> class HTMLAttributeEquivalent : public HTMLElementEquivalent {
</span><span class="cx"> public:
</span><span class="cx"> HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& tagName, const QualifiedName& attrName);
</span><span class="cx"> HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName);
</span><span class="cx">
</span><del>- bool matches(const Element* elem) const { return HTMLElementEquivalent::matches(elem) && elem->hasAttribute(m_attrName); }
</del><ins>+ bool matches(const Element& element) const { return HTMLElementEquivalent::matches(element) && element.hasAttribute(m_attrName); }
</ins><span class="cx"> virtual bool hasAttribute() const { return true; }
</span><del>- virtual bool valueIsPresentInStyle(Element*, StyleProperties*) const;
</del><ins>+ virtual bool valueIsPresentInStyle(Element&, const EditingStyle&) const;
</ins><span class="cx"> virtual void addToStyle(Element*, EditingStyle*) const;
</span><span class="cx"> virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
</span><span class="cx"> inline const QualifiedName& attributeName() const { return m_attrName; }
</span><span class="lines">@@ -260,10 +276,10 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element* element, StyleProperties* style) const
</del><ins>+bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const
</ins><span class="cx"> {
</span><del>- RefPtr<CSSValue> value = attributeValueAsCSSValue(element);
- RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(m_propertyID);
</del><ins>+ RefPtr<CSSValue> value = attributeValueAsCSSValue(&element);
+ RefPtr<CSSValue> styleValue = style.m_mutableStyle->getPropertyCSSValue(m_propertyID);
</ins><span class="cx">
</span><span class="cx"> return compareCSSValuePtr(value, styleValue);
</span><span class="cx"> }
</span><span class="lines">@@ -315,27 +331,25 @@
</span><span class="cx">
</span><span class="cx"> EditingStyle::EditingStyle()
</span><span class="cx"> : m_shouldUseFixedDefaultFontSize(false)
</span><del>- , m_fontSizeDelta(NoFontDelta)
</del><ins>+ , m_underlineChange(static_cast<unsigned>(TextDecorationChange::None))
+ , m_strikeThroughChange(static_cast<unsigned>(TextDecorationChange::None))
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> EditingStyle::EditingStyle(Node* node, PropertiesToInclude propertiesToInclude)
</span><del>- : m_shouldUseFixedDefaultFontSize(false)
- , m_fontSizeDelta(NoFontDelta)
</del><ins>+ : EditingStyle()
</ins><span class="cx"> {
</span><span class="cx"> init(node, propertiesToInclude);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> EditingStyle::EditingStyle(const Position& position, PropertiesToInclude propertiesToInclude)
</span><del>- : m_shouldUseFixedDefaultFontSize(false)
- , m_fontSizeDelta(NoFontDelta)
</del><ins>+ : EditingStyle()
</ins><span class="cx"> {
</span><span class="cx"> init(position.deprecatedNode(), propertiesToInclude);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> EditingStyle::EditingStyle(const StyleProperties* style)
</span><del>- : m_shouldUseFixedDefaultFontSize(false)
- , m_fontSizeDelta(NoFontDelta)
</del><ins>+ : EditingStyle()
</ins><span class="cx"> {
</span><span class="cx"> if (style)
</span><span class="cx"> m_mutableStyle = style->mutableCopy();
</span><span class="lines">@@ -343,13 +357,20 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value)
</span><del>- : m_mutableStyle(0)
- , m_shouldUseFixedDefaultFontSize(false)
- , m_fontSizeDelta(NoFontDelta)
</del><ins>+ : EditingStyle()
</ins><span class="cx"> {
</span><span class="cx"> setProperty(propertyID, value);
</span><ins>+ extractFontSizeDelta();
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+EditingStyle::EditingStyle(CSSPropertyID propertyID, CSSValueID value)
+ : EditingStyle()
+{
+ m_mutableStyle = MutableStyleProperties::create();
+ m_mutableStyle->setProperty(propertyID, value);
+ extractFontSizeDelta();
+}
+
</ins><span class="cx"> EditingStyle::~EditingStyle()
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="lines">@@ -492,7 +513,8 @@
</span><span class="cx">
</span><span class="cx"> bool EditingStyle::isEmpty() const
</span><span class="cx"> {
</span><del>- return (!m_mutableStyle || m_mutableStyle->isEmpty()) && m_fontSizeDelta == NoFontDelta;
</del><ins>+ return (!m_mutableStyle || m_mutableStyle->isEmpty()) && m_fontSizeDelta == NoFontDelta
+ && underlineChange() == TextDecorationChange::None && strikeThroughChange() == TextDecorationChange::None;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> bool EditingStyle::textDirection(WritingDirection& writingDirection) const
</span><span class="lines">@@ -537,11 +559,61 @@
</span><span class="cx"> return mergeStyle(style, OverrideValues);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static void applyTextDecorationChangeToValueList(CSSValueList& valueList, TextDecorationChange change, Ref<CSSPrimitiveValue>&& value)
+{
+ switch (change) {
+ case TextDecorationChange::None:
+ break;
+ case TextDecorationChange::Add:
+ valueList.append(WTF::move(value));
+ break;
+ case TextDecorationChange::Remove:
+ valueList.removeAll(&value.get());
+ break;
+ }
+}
+
+void EditingStyle::overrideTypingStyleAt(const EditingStyle& style, const Position& position)
+{
+ mergeStyle(style.m_mutableStyle.get(), OverrideValues);
+
+ m_fontSizeDelta += style.m_fontSizeDelta;
+
+ prepareToApplyAt(position, EditingStyle::PreserveWritingDirection);
+
+ auto underlineChange = style.underlineChange();
+ auto strikeThroughChange = style.strikeThroughChange();
+ if (underlineChange == TextDecorationChange::None && strikeThroughChange == TextDecorationChange::None)
+ return;
+
+ if (!m_mutableStyle)
+ m_mutableStyle = MutableStyleProperties::create();
+
+ Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+ Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
+ RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
+ RefPtr<CSSValueList> valueList;
+ if (value && value->isValueList()) {
+ valueList = downcast<CSSValueList>(*value).copy();
+ applyTextDecorationChangeToValueList(*valueList, underlineChange, WTF::move(underline));
+ applyTextDecorationChangeToValueList(*valueList, strikeThroughChange, WTF::move(lineThrough));
+ } else {
+ valueList = CSSValueList::createSpaceSeparated();
+ if (underlineChange == TextDecorationChange::Add)
+ valueList->append(WTF::move(underline));
+ if (strikeThroughChange == TextDecorationChange::Add)
+ valueList->append(WTF::move(lineThrough));
+ }
+ m_mutableStyle->setProperty(CSSPropertyWebkitTextDecorationsInEffect, valueList.get());
+}
+
</ins><span class="cx"> void EditingStyle::clear()
</span><span class="cx"> {
</span><span class="cx"> m_mutableStyle.clear();
</span><span class="cx"> m_shouldUseFixedDefaultFontSize = false;
</span><span class="cx"> m_fontSizeDelta = NoFontDelta;
</span><ins>+ setUnderlineChange(TextDecorationChange::None);
+ setStrikeThroughChange(TextDecorationChange::None);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> PassRefPtr<EditingStyle> EditingStyle::copy() const
</span><span class="lines">@@ -550,6 +622,8 @@
</span><span class="cx"> if (m_mutableStyle)
</span><span class="cx"> copy->m_mutableStyle = m_mutableStyle->mutableCopy();
</span><span class="cx"> copy->m_shouldUseFixedDefaultFontSize = m_shouldUseFixedDefaultFontSize;
</span><ins>+ copy->m_underlineChange = m_underlineChange;
+ copy->m_strikeThroughChange = m_strikeThroughChange;
</ins><span class="cx"> copy->m_fontSizeDelta = m_fontSizeDelta;
</span><span class="cx"> return copy;
</span><span class="cx"> }
</span><span class="lines">@@ -694,16 +768,67 @@
</span><span class="cx"> return state;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const
</del><ins>+static RefPtr<CSSValueList> textDecorationValueList(const StyleProperties& properties)
</ins><span class="cx"> {
</span><ins>+ RefPtr<CSSValue> value = properties.getPropertyCSSValue(CSSPropertyTextDecoration);
+ if (!is<CSSValueList>(value.get()))
+ return nullptr;
+ return downcast<CSSValueList>(value.get());
+}
+
+bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr<MutableStyleProperties>* newInlineStylePtr, EditingStyle* extractedStyle) const
+{
</ins><span class="cx"> ASSERT(element);
</span><del>- ASSERT(!conflictingProperties || conflictingProperties->isEmpty());
</del><span class="cx">
</span><span class="cx"> const StyleProperties* inlineStyle = element->inlineStyle();
</span><del>- if (!m_mutableStyle || !inlineStyle)
</del><ins>+ if (!inlineStyle)
</ins><span class="cx"> return false;
</span><ins>+ bool conflicts = false;
+ RefPtr<MutableStyleProperties> newInlineStyle;
+ if (newInlineStylePtr) {
+ newInlineStyle = inlineStyle->mutableCopy();
+ *newInlineStylePtr = newInlineStyle;
+ }
</ins><span class="cx">
</span><del>- unsigned propertyCount = m_mutableStyle->propertyCount();
</del><ins>+ bool shouldRemoveUnderline = underlineChange() == TextDecorationChange::Remove;
+ bool shouldRemoveStrikeThrough = strikeThroughChange() == TextDecorationChange::Remove;
+ if (shouldRemoveUnderline || shouldRemoveStrikeThrough) {
+ if (RefPtr<CSSValueList> valueList = textDecorationValueList(*inlineStyle)) {
+ RefPtr<CSSValueList> newValueList = valueList->copy();
+ RefPtr<CSSValueList> extractedValueList = CSSValueList::createSpaceSeparated();
+
+ Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+ if (shouldRemoveUnderline && valueList->hasValue(underline.ptr())) {
+ if (!newInlineStyle)
+ return true;
+ newValueList->removeAll(underline.ptr());
+ extractedValueList->append(WTF::move(underline));
+ }
+
+ Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
+ if (shouldRemoveStrikeThrough && valueList->hasValue(lineThrough.ptr())) {
+ if (!newInlineStyle)
+ return true;
+ newValueList->removeAll(lineThrough.ptr());
+ extractedValueList->append(WTF::move(lineThrough));
+ }
+
+ if (extractedValueList->length()) {
+ conflicts = true;
+ if (newValueList->length())
+ newInlineStyle->setProperty(CSSPropertyTextDecoration, newValueList);
+ else
+ newInlineStyle->removeProperty(CSSPropertyTextDecoration);
+
+ if (extractedStyle) {
+ bool isImportant = inlineStyle->propertyIsImportant(CSSPropertyTextDecoration);
+ extractedStyle->setProperty(CSSPropertyTextDecoration, extractedValueList->cssText(), isImportant);
+ }
+ }
+ }
+ }
+
+ unsigned propertyCount = m_mutableStyle ? m_mutableStyle->propertyCount() : 0;
</ins><span class="cx"> for (unsigned i = 0; i < propertyCount; ++i) {
</span><span class="cx"> CSSPropertyID propertyID = m_mutableStyle->propertyAt(i).id();
</span><span class="cx">
</span><span class="lines">@@ -712,35 +837,36 @@
</span><span class="cx"> continue;
</span><span class="cx">
</span><span class="cx"> if (propertyID == CSSPropertyWebkitTextDecorationsInEffect && inlineStyle->getPropertyCSSValue(CSSPropertyTextDecoration)) {
</span><del>- if (!conflictingProperties)
</del><ins>+ if (!newInlineStyle)
</ins><span class="cx"> return true;
</span><del>- conflictingProperties->append(CSSPropertyTextDecoration);
</del><ins>+ conflicts = true;
+ newInlineStyle->removeProperty(CSSPropertyTextDecoration);
</ins><span class="cx"> if (extractedStyle)
</span><span class="cx"> extractedStyle->setProperty(CSSPropertyTextDecoration, inlineStyle->getPropertyValue(CSSPropertyTextDecoration), inlineStyle->propertyIsImportant(CSSPropertyTextDecoration));
</span><del>- continue;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!inlineStyle->getPropertyCSSValue(propertyID))
</span><span class="cx"> continue;
</span><span class="cx">
</span><span class="cx"> if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) {
</span><del>- if (!conflictingProperties)
</del><ins>+ if (!newInlineStyle)
</ins><span class="cx"> return true;
</span><del>- conflictingProperties->append(CSSPropertyDirection);
</del><ins>+ conflicts = true;
+ newInlineStyle->removeProperty(CSSPropertyDirection);
</ins><span class="cx"> if (extractedStyle)
</span><span class="cx"> extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (!conflictingProperties)
</del><ins>+ if (!newInlineStyle)
</ins><span class="cx"> return true;
</span><span class="cx">
</span><del>- conflictingProperties->append(propertyID);
-
</del><ins>+ conflicts = true;
+ newInlineStyle->removeProperty(propertyID);
</ins><span class="cx"> if (extractedStyle)
</span><span class="cx"> extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return conflictingProperties && !conflictingProperties->isEmpty();
</del><ins>+ return conflicts;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static const Vector<std::unique_ptr<HTMLElementEquivalent>>& htmlElementEquivalents()
</span><span class="lines">@@ -766,14 +892,13 @@
</span><span class="cx">
</span><span class="cx"> bool EditingStyle::conflictsWithImplicitStyleOfElement(HTMLElement* element, EditingStyle* extractedStyle, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
</span><span class="cx"> {
</span><del>- if (!m_mutableStyle)
</del><ins>+ if (isEmpty())
</ins><span class="cx"> return false;
</span><span class="cx">
</span><span class="cx"> const Vector<std::unique_ptr<HTMLElementEquivalent>>& HTMLElementEquivalents = htmlElementEquivalents();
</span><del>- for (size_t i = 0; i < HTMLElementEquivalents.size(); ++i) {
- const HTMLElementEquivalent* equivalent = HTMLElementEquivalents[i].get();
- if (equivalent->matches(element) && equivalent->propertyExistsInStyle(m_mutableStyle.get())
- && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))) {
</del><ins>+ for (auto& equivalent : HTMLElementEquivalents) {
+ if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this)
+ && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(*element, *this))) {
</ins><span class="cx"> if (extractedStyle)
</span><span class="cx"> equivalent->addToStyle(element, extractedStyle);
</span><span class="cx"> return true;
</span><span class="lines">@@ -803,13 +928,12 @@
</span><span class="cx"> bool EditingStyle::conflictsWithImplicitStyleOfAttributes(HTMLElement* element) const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(element);
</span><del>- if (!m_mutableStyle)
</del><ins>+ if (isEmpty())
</ins><span class="cx"> return false;
</span><span class="cx">
</span><span class="cx"> const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
</span><del>- for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
- if (HTMLAttributeEquivalents[i]->matches(element) && HTMLAttributeEquivalents[i]->propertyExistsInStyle(m_mutableStyle.get())
- && !HTMLAttributeEquivalents[i]->valueIsPresentInStyle(element, m_mutableStyle.get()))
</del><ins>+ for (auto& equivalent : HTMLAttributeEquivalents) {
+ if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this) && !equivalent->valueIsPresentInStyle(*element, *this))
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -834,8 +958,8 @@
</span><span class="cx"> if (shouldPreserveWritingDirection == PreserveWritingDirection && equivalent->attributeName() == HTMLNames::dirAttr)
</span><span class="cx"> continue;
</span><span class="cx">
</span><del>- if (!equivalent->matches(element) || !equivalent->propertyExistsInStyle(m_mutableStyle.get())
- || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(element, m_mutableStyle.get())))
</del><ins>+ if (!equivalent->matches(*element) || !equivalent->propertyExistsInStyle(*this)
+ || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(*element, *this)))
</ins><span class="cx"> continue;
</span><span class="cx">
</span><span class="cx"> if (extractedStyle)
</span><span class="lines">@@ -849,10 +973,27 @@
</span><span class="cx">
</span><span class="cx"> bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const
</span><span class="cx"> {
</span><del>- if (!m_mutableStyle)
</del><ins>+ if (isEmpty())
</ins><span class="cx"> return true;
</span><span class="cx"> ComputedStyleExtractor computedStyle(node);
</span><del>- return getPropertiesNotIn(*m_mutableStyle, computedStyle)->isEmpty();
</del><ins>+
+ bool shouldAddUnderline = underlineChange() == TextDecorationChange::Add;
+ bool shouldAddLineThrough = strikeThroughChange() == TextDecorationChange::Add;
+ if (shouldAddUnderline || shouldAddLineThrough) {
+ bool hasUnderline = false;
+ bool hasLineThrough = false;
+ if (RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyTextDecoration)) {
+ if (value->isValueList()) {
+ const CSSValueList& valueList = downcast<CSSValueList>(*value);
+ hasUnderline = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueUnderline).get());
+ hasLineThrough = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueLineThrough).get());
+ }
+ }
+ if ((shouldAddUnderline && !hasUnderline) || (shouldAddLineThrough && !hasLineThrough))
+ return false;
+ }
+
+ return !m_mutableStyle || getPropertiesNotIn(*m_mutableStyle, computedStyle)->isEmpty();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> bool EditingStyle::elementIsStyledSpanOrHTMLEquivalent(const HTMLElement* element)
</span><span class="lines">@@ -864,7 +1005,7 @@
</span><span class="cx"> const Vector<std::unique_ptr<HTMLElementEquivalent>>& HTMLElementEquivalents = htmlElementEquivalents();
</span><span class="cx"> size_t i;
</span><span class="cx"> for (i = 0; i < HTMLElementEquivalents.size(); ++i) {
</span><del>- if (HTMLElementEquivalents[i]->matches(element)) {
</del><ins>+ if (HTMLElementEquivalents[i]->matches(*element)) {
</ins><span class="cx"> elementIsSpanOrElementEquivalent = true;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -877,7 +1018,7 @@
</span><span class="cx"> unsigned matchedAttributes = 0;
</span><span class="cx"> const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
</span><span class="cx"> for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
</span><del>- if (HTMLAttributeEquivalents[i]->matches(element) && HTMLAttributeEquivalents[i]->attributeName() != HTMLNames::dirAttr)
</del><ins>+ if (HTMLAttributeEquivalents[i]->matches(*element) && HTMLAttributeEquivalents[i]->attributeName() != HTMLNames::dirAttr)
</ins><span class="cx"> matchedAttributes++;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -969,10 +1110,14 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl(const HTMLElementEquivalent* equivalent, const StyledElement* element,
</span><del>- EditingStyle::CSSPropertyOverrideMode mode, StyleProperties* style)
</del><ins>+ EditingStyle::CSSPropertyOverrideMode mode, EditingStyle& style)
</ins><span class="cx"> {
</span><del>- return equivalent->matches(element) && (!element->inlineStyle() || !equivalent->propertyExistsInStyle(element->inlineStyle()))
- && (mode == EditingStyle::OverrideValues || !equivalent->propertyExistsInStyle(style));
</del><ins>+ if (!equivalent->matches(*element))
+ return false;
+ if (mode != EditingStyle::OverrideValues && equivalent->propertyExistsInStyle(style))
+ return false;
+
+ return !element->inlineStyle() || !equivalent->propertyExistsInStyle(EditingStyle::create(element->inlineStyle()).get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static PassRefPtr<MutableStyleProperties> extractEditingProperties(const StyleProperties* style, EditingStyle::PropertiesToInclude propertiesToInclude)
</span><span class="lines">@@ -1005,7 +1150,7 @@
</span><span class="cx">
</span><span class="cx"> const Vector<std::unique_ptr<HTMLElementEquivalent>>& elementEquivalents = htmlElementEquivalents();
</span><span class="cx"> for (size_t i = 0; i < elementEquivalents.size(); ++i) {
</span><del>- if (elementMatchesAndPropertyIsNotInInlineStyleDecl(elementEquivalents[i].get(), element, mode, m_mutableStyle.get()))
</del><ins>+ if (elementMatchesAndPropertyIsNotInInlineStyleDecl(elementEquivalents[i].get(), element, mode, *this))
</ins><span class="cx"> elementEquivalents[i]->addToStyle(element, this);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1013,7 +1158,7 @@
</span><span class="cx"> for (size_t i = 0; i < attributeEquivalents.size(); ++i) {
</span><span class="cx"> if (attributeEquivalents[i]->attributeName() == HTMLNames::dirAttr)
</span><span class="cx"> continue; // We don't want to include directionality
</span><del>- if (elementMatchesAndPropertyIsNotInInlineStyleDecl(attributeEquivalents[i].get(), element, mode, m_mutableStyle.get()))
</del><ins>+ if (elementMatchesAndPropertyIsNotInInlineStyleDecl(attributeEquivalents[i].get(), element, mode, *this))
</ins><span class="cx"> attributeEquivalents[i]->addToStyle(element, this);
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -1049,16 +1194,16 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><del>-static void mergeTextDecorationValues(CSSValueList* mergedValue, const CSSValueList* valueToMerge)
</del><ins>+static void mergeTextDecorationValues(CSSValueList& mergedValue, const CSSValueList& valueToMerge)
</ins><span class="cx"> {
</span><del>- RefPtr<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
- RefPtr<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
</del><ins>+ Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+ Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
</ins><span class="cx">
</span><del>- if (valueToMerge->hasValue(underline.get()) && !mergedValue->hasValue(underline.get()))
- mergedValue->append(underline.releaseNonNull());
</del><ins>+ if (valueToMerge.hasValue(underline.ptr()) && !mergedValue.hasValue(underline.ptr()))
+ mergedValue.append(WTF::move(underline));
</ins><span class="cx">
</span><del>- if (valueToMerge->hasValue(lineThrough.get()) && !mergedValue->hasValue(lineThrough.get()))
- mergedValue->append(lineThrough.releaseNonNull());
</del><ins>+ if (valueToMerge.hasValue(lineThrough.ptr()) && !mergedValue.hasValue(lineThrough.ptr()))
+ mergedValue.append(WTF::move(lineThrough));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void EditingStyle::mergeStyle(const StyleProperties* style, CSSPropertyOverrideMode mode)
</span><span class="lines">@@ -1077,16 +1222,19 @@
</span><span class="cx"> RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(property.id());
</span><span class="cx">
</span><span class="cx"> // text decorations never override values.
</span><del>- if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect) && property.value()->isValueList() && value) {
</del><ins>+ if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect)
+ && is<CSSValueList>(*property.value()) && value) {
</ins><span class="cx"> if (is<CSSValueList>(*value)) {
</span><del>- mergeTextDecorationValues(downcast<CSSValueList>(value.get()), downcast<CSSValueList>(property.value()));
</del><ins>+ RefPtr<CSSValueList> newValue = downcast<CSSValueList>(*value).copy();
+ mergeTextDecorationValues(*newValue, downcast<CSSValueList>(*property.value()));
+ m_mutableStyle->setProperty(property.id(), newValue.release(), property.isImportant());
</ins><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="cx"> value = nullptr; // text-decoration: none is equivalent to not having the property.
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (mode == OverrideValues || (mode == DoNotOverrideValues && !value))
</span><del>- m_mutableStyle->setProperty(property.id(), property.value()->cssText(), property.isImportant());
</del><ins>+ m_mutableStyle->setProperty(property.id(), property.value(), property.isImportant());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> int oldFontSizeDelta = m_fontSizeDelta;
</span><span class="lines">@@ -1397,8 +1545,8 @@
</span><span class="cx"> , m_applySubscript(false)
</span><span class="cx"> , m_applySuperscript(false)
</span><span class="cx"> {
</span><del>- Document* document = position.anchorNode() ? &position.anchorNode()->document() : 0;
- if (!style || !style->style() || !document || !document->frame())
</del><ins>+ Document* document = position.deprecatedNode() ? &position.deprecatedNode()->document() : 0;
+ if (!style || style->isEmpty() || !document || !document->frame())
</ins><span class="cx"> return;
</span><span class="cx">
</span><span class="cx"> Node* node = position.containerNode();
</span><span class="lines">@@ -1408,12 +1556,44 @@
</span><span class="cx"> ComputedStyleExtractor computedStyle(node);
</span><span class="cx">
</span><span class="cx"> // FIXME: take care of background-color in effect
</span><del>- RefPtr<MutableStyleProperties> mutableStyle = getPropertiesNotIn(*style->style(), computedStyle);
</del><ins>+ RefPtr<MutableStyleProperties> mutableStyle = style->style() ?
+ getPropertiesNotIn(*style->style(), computedStyle) : MutableStyleProperties::create();
</ins><span class="cx">
</span><span class="cx"> reconcileTextDecorationProperties(mutableStyle.get());
</span><del>- if (!document->frame()->editor().shouldStyleWithCSS())
</del><ins>+ bool shouldStyleWithCSS = document->frame()->editor().shouldStyleWithCSS();
+ if (!shouldStyleWithCSS)
</ins><span class="cx"> extractTextStyles(document, *mutableStyle, computedStyle.useFixedFontDefaultSize());
</span><span class="cx">
</span><ins>+ bool shouldAddUnderline = style->underlineChange() == TextDecorationChange::Add;
+ bool shouldAddStrikeThrough = style->strikeThroughChange() == TextDecorationChange::Add;
+ if (shouldAddUnderline || shouldAddStrikeThrough) {
+ RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyWebkitTextDecorationsInEffect);
+ if (!is<CSSValueList>(value.get()))
+ value = computedStyle.propertyValue(CSSPropertyTextDecoration);
+
+ RefPtr<CSSValueList> valueList;
+ if (is<CSSValueList>(value.get()))
+ valueList = downcast<CSSValueList>(value.get());
+
+ Ref<CSSValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+ bool hasUnderline = valueList && valueList->hasValue(underline.ptr());
+
+ Ref<CSSValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
+ bool hasLineThrough = valueList && valueList->hasValue(lineThrough.ptr());
+
+ if (shouldStyleWithCSS) {
+ valueList = valueList ? valueList->copy() : CSSValueList::createSpaceSeparated();
+ if (shouldAddUnderline && !hasUnderline)
+ valueList->append(WTF::move(underline));
+ if (shouldAddStrikeThrough && !hasLineThrough)
+ valueList->append(WTF::move(lineThrough));
+ mutableStyle->setProperty(CSSPropertyTextDecoration, valueList.get());
+ } else {
+ m_applyUnderline = shouldAddUnderline && !hasUnderline;
+ m_applyLineThrough = shouldAddStrikeThrough && !hasLineThrough;
+ }
+ }
+
</ins><span class="cx"> // Changing the whitespace style in a tab span would collapse the tab into a space.
</span><span class="cx"> if (isTabSpanTextNode(position.deprecatedNode()) || isTabSpanNode((position.deprecatedNode())))
</span><span class="cx"> mutableStyle->removeProperty(CSSPropertyWhiteSpace);
</span><span class="lines">@@ -1423,10 +1603,27 @@
</span><span class="cx"> if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->style()->getPropertyCSSValue(CSSPropertyDirection))
</span><span class="cx"> mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection));
</span><span class="cx">
</span><del>- // Save the result for later
- m_cssStyle = mutableStyle->asText().stripWhiteSpace();
</del><ins>+ if (!mutableStyle->isEmpty())
+ m_cssStyle = mutableStyle;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+bool StyleChange::operator==(const StyleChange& other)
+{
+ if (m_applyBold != other.m_applyBold
+ || m_applyItalic != other.m_applyItalic
+ || m_applyUnderline != other.m_applyUnderline
+ || m_applyLineThrough != other.m_applyLineThrough
+ || m_applySubscript != other.m_applySubscript
+ || m_applySuperscript != other.m_applySuperscript
+ || m_applyFontColor != other.m_applyFontColor
+ || m_applyFontFace != other.m_applyFontFace
+ || m_applyFontSize != other.m_applyFontSize)
+ return false;
+
+ return (!m_cssStyle && !other.m_cssStyle)
+ || (m_cssStyle && other.m_cssStyle && m_cssStyle->asText() == other.m_cssStyle->asText());
+}
+
</ins><span class="cx"> static void setTextDecorationProperty(MutableStyleProperties& style, const CSSValueList* newTextDecoration, CSSPropertyID propertyID)
</span><span class="cx"> {
</span><span class="cx"> if (newTextDecoration->length())
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditingStyleh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/EditingStyle.h (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/EditingStyle.h        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebCore/editing/EditingStyle.h        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -34,8 +34,10 @@
</span><span class="cx">
</span><span class="cx"> #include "CSSPropertyNames.h"
</span><span class="cx"> #include "CSSValueKeywords.h"
</span><ins>+#include "StyleProperties.h"
</ins><span class="cx"> #include "WritingDirection.h"
</span><span class="cx"> #include <wtf/Forward.h>
</span><ins>+#include <wtf/HashMap.h>
</ins><span class="cx"> #include <wtf/RefCounted.h>
</span><span class="cx"> #include <wtf/RefPtr.h>
</span><span class="cx"> #include <wtf/TriState.h>
</span><span class="lines">@@ -61,6 +63,8 @@
</span><span class="cx"> class StyledElement;
</span><span class="cx"> class VisibleSelection;
</span><span class="cx">
</span><ins>+enum class TextDecorationChange { None, Add, Remove };
+
</ins><span class="cx"> class EditingStyle : public RefCounted<EditingStyle> {
</span><span class="cx"> public:
</span><span class="cx">
</span><span class="lines">@@ -95,6 +99,11 @@
</span><span class="cx"> return adoptRef(*new EditingStyle(propertyID, value));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ static Ref<EditingStyle> create(CSSPropertyID propertyID, CSSValueID value)
+ {
+ return adoptRef(*new EditingStyle(propertyID, value));
+ }
+
</ins><span class="cx"> WEBCORE_EXPORT ~EditingStyle();
</span><span class="cx">
</span><span class="cx"> MutableStyleProperties* style() { return m_mutableStyle.get(); }
</span><span class="lines">@@ -102,6 +111,7 @@
</span><span class="cx"> bool isEmpty() const;
</span><span class="cx"> void setStyle(PassRefPtr<MutableStyleProperties>);
</span><span class="cx"> void overrideWithStyle(const StyleProperties*);
</span><ins>+ void overrideTypingStyleAt(const EditingStyle&, const Position&);
</ins><span class="cx"> void clear();
</span><span class="cx"> PassRefPtr<EditingStyle> copy() const;
</span><span class="cx"> PassRefPtr<EditingStyle> extractAndRemoveBlockProperties();
</span><span class="lines">@@ -115,9 +125,10 @@
</span><span class="cx"> TriState triStateOfStyle(EditingStyle*) const;
</span><span class="cx"> TriState triStateOfStyle(const VisibleSelection&) const;
</span><span class="cx"> bool conflictsWithInlineStyleOfElement(StyledElement* element) const { return conflictsWithInlineStyleOfElement(element, 0, 0); }
</span><del>- bool conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>& conflictingProperties) const
</del><ins>+ bool conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr<MutableStyleProperties>& newInlineStyle,
+ EditingStyle* extractedStyle) const
</ins><span class="cx"> {
</span><del>- return conflictsWithInlineStyleOfElement(element, extractedStyle, &conflictingProperties);
</del><ins>+ return conflictsWithInlineStyleOfElement(element, &newInlineStyle, extractedStyle);
</ins><span class="cx"> }
</span><span class="cx"> bool conflictsWithImplicitStyleOfElement(HTMLElement*, EditingStyle* extractedStyle = 0, ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const;
</span><span class="cx"> bool conflictsWithImplicitStyleOfAttributes(HTMLElement*) const;
</span><span class="lines">@@ -144,6 +155,11 @@
</span><span class="cx"> float fontSizeDelta() const { return m_fontSizeDelta; }
</span><span class="cx"> bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; }
</span><span class="cx"> bool shouldUseFixedDefaultFontSize() const { return m_shouldUseFixedDefaultFontSize; }
</span><ins>+
+ void setUnderlineChange(TextDecorationChange change) { m_underlineChange = static_cast<unsigned>(change); }
+ TextDecorationChange underlineChange() const { return static_cast<TextDecorationChange>(m_underlineChange); }
+ void setStrikeThroughChange(TextDecorationChange change) { m_strikeThroughChange = static_cast<unsigned>(change); }
+ TextDecorationChange strikeThroughChange() const { return static_cast<TextDecorationChange>(m_strikeThroughChange); }
</ins><span class="cx">
</span><span class="cx"> static PassRefPtr<EditingStyle> styleAtSelectionStart(const VisibleSelection&, bool shouldUseBackgroundColorInEffect = false);
</span><span class="cx"> static WritingDirection textDirectionForSelection(const VisibleSelection&, EditingStyle* typingStyle, bool& hasNestedOrMultipleEmbeddings);
</span><span class="lines">@@ -153,37 +169,33 @@
</span><span class="cx"> EditingStyle(const Position&, PropertiesToInclude);
</span><span class="cx"> explicit EditingStyle(const StyleProperties*);
</span><span class="cx"> EditingStyle(CSSPropertyID, const String& value);
</span><ins>+ EditingStyle(CSSPropertyID, CSSValueID);
</ins><span class="cx"> void init(Node*, PropertiesToInclude);
</span><span class="cx"> void removeTextFillAndStrokeColorsIfNeeded(RenderStyle*);
</span><span class="cx"> void setProperty(CSSPropertyID, const String& value, bool important = false);
</span><span class="cx"> void extractFontSizeDelta();
</span><span class="cx"> template<typename T> TriState triStateOfStyle(T& styleToCompare, ShouldIgnoreTextOnlyProperties) const;
</span><del>- bool conflictsWithInlineStyleOfElement(StyledElement*, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const;
</del><ins>+ bool conflictsWithInlineStyleOfElement(StyledElement*, RefPtr<MutableStyleProperties>* newInlineStyle, EditingStyle* extractedStyle) const;
</ins><span class="cx"> void mergeInlineAndImplicitStyleOfElement(StyledElement*, CSSPropertyOverrideMode, PropertiesToInclude);
</span><span class="cx"> void mergeStyle(const StyleProperties*, CSSPropertyOverrideMode);
</span><span class="cx">
</span><span class="cx"> RefPtr<MutableStyleProperties> m_mutableStyle;
</span><del>- bool m_shouldUseFixedDefaultFontSize;
- float m_fontSizeDelta;
</del><ins>+ unsigned m_shouldUseFixedDefaultFontSize : 1;
+ unsigned m_underlineChange : 2;
+ unsigned m_strikeThroughChange : 2;
+ float m_fontSizeDelta = NoFontDelta;
</ins><span class="cx">
</span><span class="cx"> friend class HTMLElementEquivalent;
</span><span class="cx"> friend class HTMLAttributeEquivalent;
</span><ins>+ friend class HTMLTextDecorationEquivalent;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> class StyleChange {
</span><span class="cx"> public:
</span><del>- StyleChange()
- : m_applyBold(false)
- , m_applyItalic(false)
- , m_applyUnderline(false)
- , m_applyLineThrough(false)
- , m_applySubscript(false)
- , m_applySuperscript(false)
- { }
-
</del><ins>+ StyleChange() { }
</ins><span class="cx"> StyleChange(EditingStyle*, const Position&);
</span><span class="cx">
</span><del>- String cssStyle() const { return m_cssStyle; }
</del><ins>+ const StyleProperties* cssStyle() const { return m_cssStyle.get(); }
</ins><span class="cx"> bool applyBold() const { return m_applyBold; }
</span><span class="cx"> bool applyItalic() const { return m_applyItalic; }
</span><span class="cx"> bool applyUnderline() const { return m_applyUnderline; }
</span><span class="lines">@@ -198,19 +210,7 @@
</span><span class="cx"> String fontFace() { return m_applyFontFace; }
</span><span class="cx"> String fontSize() { return m_applyFontSize; }
</span><span class="cx">
</span><del>- bool operator==(const StyleChange& other)
- {
- return m_cssStyle == other.m_cssStyle
- && m_applyBold == other.m_applyBold
- && m_applyItalic == other.m_applyItalic
- && m_applyUnderline == other.m_applyUnderline
- && m_applyLineThrough == other.m_applyLineThrough
- && m_applySubscript == other.m_applySubscript
- && m_applySuperscript == other.m_applySuperscript
- && m_applyFontColor == other.m_applyFontColor
- && m_applyFontFace == other.m_applyFontFace
- && m_applyFontSize == other.m_applyFontSize;
- }
</del><ins>+ bool operator==(const StyleChange&);
</ins><span class="cx"> bool operator!=(const StyleChange& other)
</span><span class="cx"> {
</span><span class="cx"> return !(*this == other);
</span><span class="lines">@@ -218,13 +218,13 @@
</span><span class="cx"> private:
</span><span class="cx"> void extractTextStyles(Document*, MutableStyleProperties&, bool shouldUseFixedFontDefaultSize);
</span><span class="cx">
</span><del>- String m_cssStyle;
- bool m_applyBold;
- bool m_applyItalic;
- bool m_applyUnderline;
- bool m_applyLineThrough;
- bool m_applySubscript;
- bool m_applySuperscript;
</del><ins>+ RefPtr<MutableStyleProperties> m_cssStyle;
+ bool m_applyBold = false;
+ bool m_applyItalic = false;
+ bool m_applyUnderline = false;
+ bool m_applyLineThrough = false;
+ bool m_applySubscript = false;
+ bool m_applySuperscript = false;
</ins><span class="cx"> String m_applyFontColor;
</span><span class="cx"> String m_applyFontFace;
</span><span class="cx"> String m_applyFontSize;
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/Editor.cpp (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/Editor.cpp        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebCore/editing/Editor.cpp        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -887,7 +887,7 @@
</span><span class="cx"> // do nothing
</span><span class="cx"> break;
</span><span class="cx"> case VisibleSelection::CaretSelection:
</span><del>- computeAndSetTypingStyle(style, editingAction);
</del><ins>+ computeAndSetTypingStyle(EditingStyle::create(style), editingAction);
</ins><span class="cx"> break;
</span><span class="cx"> case VisibleSelection::RangeSelection:
</span><span class="cx"> if (style)
</span><span class="lines">@@ -895,6 +895,22 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><ins>+
+void Editor::applyStyle(RefPtr<EditingStyle>&& style, EditAction editingAction)
+{
+ switch (m_frame.selection().selection().selectionType()) {
+ case VisibleSelection::NoSelection:
+ // do nothing
+ break;
+ case VisibleSelection::CaretSelection:
+ computeAndSetTypingStyle(*style, editingAction);
+ break;
+ case VisibleSelection::RangeSelection:
+ if (style)
+ applyCommand(ApplyStyleCommand::create(document(), style.get(), editingAction));
+ break;
+ }
+}
</ins><span class="cx">
</span><span class="cx"> bool Editor::shouldApplyStyle(StyleProperties* style, Range* range)
</span><span class="cx"> {
</span><span class="lines">@@ -920,10 +936,23 @@
</span><span class="cx"> if (!style || style->isEmpty() || !canEditRichly())
</span><span class="cx"> return;
</span><span class="cx">
</span><del>- if (client() && client()->shouldApplyStyle(style, m_frame.selection().toNormalizedRange().get()))
- applyStyle(style, editingAction);
</del><ins>+ if (!client() || !client()->shouldApplyStyle(style, m_frame.selection().toNormalizedRange().get()))
+ return;
+ applyStyle(style, editingAction);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+void Editor::applyStyleToSelection(RefPtr<EditingStyle>&& style, EditAction editingAction)
+{
+ if (!style || style->isEmpty() || !canEditRichly())
+ return;
+
+ // FIXME: This is wrong for text decorations since m_mutableStyle is empty.
+ if (!client() || !client()->shouldApplyStyle(style->style(), m_frame.selection().toNormalizedRange().get()))
+ return;
+
+ applyStyle(WTF::move(style), editingAction);
+}
+
</ins><span class="cx"> void Editor::applyParagraphStyleToSelection(StyleProperties* style, EditAction editingAction)
</span><span class="cx"> {
</span><span class="cx"> if (!style || style->isEmpty() || !canEditRichly())
</span><span class="lines">@@ -2952,23 +2981,21 @@
</span><span class="cx"> return client() && client()->shouldChangeSelectedRange(oldSelection.toNormalizedRange().get(), newSelection.toNormalizedRange().get(), affinity, stillSelecting);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void Editor::computeAndSetTypingStyle(StyleProperties* style, EditAction editingAction)
</del><ins>+void Editor::computeAndSetTypingStyle(EditingStyle& style, EditAction editingAction)
</ins><span class="cx"> {
</span><del>- if (!style || style->isEmpty()) {
</del><ins>+ if (style.isEmpty()) {
</ins><span class="cx"> m_frame.selection().clearTypingStyle();
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Calculate the current typing style.
</span><span class="cx"> RefPtr<EditingStyle> typingStyle;
</span><del>- if (m_frame.selection().typingStyle()) {
- typingStyle = m_frame.selection().typingStyle()->copy();
- typingStyle->overrideWithStyle(style);
- } else
- typingStyle = EditingStyle::create(style);
</del><ins>+ if (auto existingTypingStyle = m_frame.selection().typingStyle())
+ typingStyle = existingTypingStyle->copy();
+ else
+ typingStyle = EditingStyle::create();
+ typingStyle->overrideTypingStyleAt(style, m_frame.selection().selection().visibleStart().deepEquivalent());
</ins><span class="cx">
</span><del>- typingStyle->prepareToApplyAt(m_frame.selection().selection().visibleStart().deepEquivalent(), EditingStyle::PreserveWritingDirection);
-
</del><span class="cx"> // Handle block styles, substracting these from the typing style.
</span><span class="cx"> RefPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveBlockProperties();
</span><span class="cx"> if (!blockStyle->isEmpty())
</span><span class="lines">@@ -2978,6 +3005,11 @@
</span><span class="cx"> m_frame.selection().setTypingStyle(typingStyle);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void Editor::computeAndSetTypingStyle(StyleProperties& properties, EditAction editingAction)
+{
+ return computeAndSetTypingStyle(EditingStyle::create(&properties), editingAction);
+}
+
</ins><span class="cx"> void Editor::textFieldDidBeginEditing(Element* e)
</span><span class="cx"> {
</span><span class="cx"> if (client())
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/Editor.h (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/Editor.h        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebCore/editing/Editor.h        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -183,8 +183,10 @@
</span><span class="cx"> bool dispatchCPPEvent(const AtomicString&, DataTransferAccessPolicy);
</span><span class="cx">
</span><span class="cx"> WEBCORE_EXPORT void applyStyle(StyleProperties*, EditAction = EditActionUnspecified);
</span><ins>+ void applyStyle(RefPtr<EditingStyle>&&, EditAction);
</ins><span class="cx"> void applyParagraphStyle(StyleProperties*, EditAction = EditActionUnspecified);
</span><span class="cx"> WEBCORE_EXPORT void applyStyleToSelection(StyleProperties*, EditAction);
</span><ins>+ void applyStyleToSelection(RefPtr<EditingStyle>&&, EditAction);
</ins><span class="cx"> void applyParagraphStyleToSelection(StyleProperties*, EditAction);
</span><span class="cx">
</span><span class="cx"> void appliedEditing(PassRefPtr<CompositeEditCommand>);
</span><span class="lines">@@ -361,7 +363,8 @@
</span><span class="cx"> const VisibleSelection& mark() const; // Mark, to be used as emacs uses it.
</span><span class="cx"> void setMark(const VisibleSelection&);
</span><span class="cx">
</span><del>- WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties* , EditAction = EditActionUnspecified);
</del><ins>+ void computeAndSetTypingStyle(EditingStyle& , EditAction = EditActionUnspecified);
+ WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties& , EditAction = EditActionUnspecified);
</ins><span class="cx"> WEBCORE_EXPORT void applyEditingStyleToBodyElement() const;
</span><span class="cx"> void applyEditingStyleToElement(Element*) const;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorCommandcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/EditorCommand.cpp (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/EditorCommand.cpp        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebCore/editing/EditorCommand.cpp        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -98,77 +98,46 @@
</span><span class="cx"> return node->document().frame();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, StyleProperties* style)
</del><ins>+static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, RefPtr<EditingStyle>&& style)
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
</span><span class="cx"> switch (source) {
</span><span class="cx"> case CommandFromMenuOrKeyBinding:
</span><del>- frame.editor().applyStyleToSelection(style, action);
</del><ins>+ frame.editor().applyStyleToSelection(WTF::move(style), action);
</ins><span class="cx"> return true;
</span><span class="cx"> case CommandFromDOM:
</span><span class="cx"> case CommandFromDOMWithUserInterface:
</span><del>- frame.editor().applyStyle(style);
</del><ins>+ frame.editor().applyStyle(WTF::move(style), EditActionUnspecified);
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> ASSERT_NOT_REACHED();
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
</del><ins>+static bool isStylePresent(Editor& editor, CSSPropertyID propertyID, const char* onValue)
</ins><span class="cx"> {
</span><del>- RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
- style->setProperty(propertyID, propertyValue);
- return applyCommandToFrame(frame, source, action, style.get());
</del><ins>+ // Style is considered present when
+ // Mac: present at the beginning of selection
+ // Windows: present throughout the selection
+ if (editor.behavior().shouldToggleStyleBasedOnStartOfSelection())
+ return editor.selectionStartHasStyle(propertyID, onValue);
+ return editor.selectionHasStyle(propertyID, onValue) == TrueTriState;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
</del><ins>+static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
</ins><span class="cx"> {
</span><del>- RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
- style->setProperty(propertyID, propertyValue);
- return applyCommandToFrame(frame, source, action, style.get());
</del><ins>+ return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-// FIXME: executeToggleStyleInList does not handle complicated cases such as <b><u>hello</u>world</b> properly.
-// This function must use Editor::selectionHasStyle to determine the current style but we cannot fix this
-// until https://bugs.webkit.org/show_bug.cgi?id=27818 is resolved.
-static bool executeToggleStyleInList(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValue* value)
</del><ins>+static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
</ins><span class="cx"> {
</span><del>- RefPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelectionStart(frame.selection().selection());
- if (!selectionStyle || !selectionStyle->style())
- return false;
-
- RefPtr<CSSValue> selectedCSSValue = selectionStyle->style()->getPropertyCSSValue(propertyID);
- String newStyle = ASCIILiteral("none");
- if (is<CSSValueList>(*selectedCSSValue)) {
- RefPtr<CSSValueList> selectedCSSValueList = downcast<CSSValueList>(selectedCSSValue.get());
- if (!selectedCSSValueList->removeAll(value))
- selectedCSSValueList->append(*value);
- if (selectedCSSValueList->length())
- newStyle = selectedCSSValueList->cssText();
-
- } else if (selectedCSSValue->cssText() == "none")
- newStyle = value->cssText();
-
- // FIXME: We shouldn't be having to convert new style into text. We should have setPropertyCSSValue.
- RefPtr<MutableStyleProperties> newMutableStyle = MutableStyleProperties::create();
- newMutableStyle->setProperty(propertyID, newStyle);
- return applyCommandToFrame(frame, source, action, newMutableStyle.get());
</del><ins>+ return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static bool executeToggleStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const char* offValue, const char* onValue)
</span><span class="cx"> {
</span><del>- // Style is considered present when
- // Mac: present at the beginning of selection
- // other: present throughout the selection
-
- bool styleIsPresent;
- if (frame.editor().behavior().shouldToggleStyleBasedOnStartOfSelection())
- styleIsPresent = frame.editor().selectionStartHasStyle(propertyID, onValue);
- else
- styleIsPresent = frame.editor().selectionHasStyle(propertyID, onValue) == TrueTriState;
-
- RefPtr<EditingStyle> style = EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue);
- return applyCommandToFrame(frame, source, action, style->style());
</del><ins>+ bool styleIsPresent = isStylePresent(frame.editor(), propertyID, onValue);
+ return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static bool executeApplyParagraphStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
</span><span class="lines">@@ -1058,10 +1027,17 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static TextDecorationChange textDecorationChangeForToggling(Editor& editor, CSSPropertyID propertyID, const char* onValue)
+{
+ return isStylePresent(editor, propertyID, onValue) ? TextDecorationChange::Remove : TextDecorationChange::Add;
+}
+
</ins><span class="cx"> static bool executeStrikethrough(Frame& frame, Event*, EditorCommandSource source, const String&)
</span><span class="cx"> {
</span><del>- RefPtr<CSSPrimitiveValue> lineThrough = CSSPrimitiveValue::createIdentifier(CSSValueLineThrough);
- return executeToggleStyleInList(frame, source, EditActionUnderline, CSSPropertyWebkitTextDecorationsInEffect, lineThrough.get());
</del><ins>+ RefPtr<EditingStyle> style = EditingStyle::create();
+ style->setStrikeThroughChange(textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "line-through"));
+ // FIXME: Needs a new EditAction!
+ return applyCommandToFrame(frame, source, EditActionUnderline, WTF::move(style));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static bool executeStyleWithCSS(Frame& frame, Event*, EditorCommandSource, const String& value)
</span><span class="lines">@@ -1125,8 +1101,10 @@
</span><span class="cx">
</span><span class="cx"> static bool executeUnderline(Frame& frame, Event*, EditorCommandSource source, const String&)
</span><span class="cx"> {
</span><del>- RefPtr<CSSPrimitiveValue> underline = CSSPrimitiveValue::createIdentifier(CSSValueUnderline);
- return executeToggleStyleInList(frame, source, EditActionUnderline, CSSPropertyWebkitTextDecorationsInEffect, underline.get());
</del><ins>+ RefPtr<EditingStyle> style = EditingStyle::create();
+ TextDecorationChange change = textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "underline");
+ style->setUnderlineChange(change);
+ return applyCommandToFrame(frame, source, EditActionUnderline, WTF::move(style));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static bool executeUndo(Frame& frame, Event*, EditorCommandSource, const String&)
</span></span></pre></div>
<a id="trunkSourceWebKitmacChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/ChangeLog (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/ChangeLog        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebKit/mac/ChangeLog        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2015-05-04 Ryosuke Niwa <rniwa@webkit.org>
+
+ Toggling underline or strike through affects each other
+ https://bugs.webkit.org/show_bug.cgi?id=27818
+
+ Reviewed by Darin Adler.
+
+ * WebView/WebFrame.mm:
+ (-[WebFrame _setTypingStyle:withUndoAction:]):
+
</ins><span class="cx"> 2015-05-01 Martin Robinson <mrobinson@igalia.com>
</span><span class="cx">
</span><span class="cx"> USE(...) macro should expect unprefixed variables
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebViewWebFramemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebView/WebFrame.mm (183769 => 183770)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebView/WebFrame.mm        2015-05-04 20:42:10 UTC (rev 183769)
+++ trunk/Source/WebKit/mac/WebView/WebFrame.mm        2015-05-04 20:42:41 UTC (rev 183770)
</span><span class="lines">@@ -941,7 +941,7 @@
</span><span class="cx"> return;
</span><span class="cx"> // FIXME: We shouldn't have to create a copy here.
</span><span class="cx"> Ref<MutableStyleProperties> properties(core(style)->copyProperties());
</span><del>- _private->coreFrame->editor().computeAndSetTypingStyle(properties.ptr(), undoAction);
</del><ins>+ _private->coreFrame->editor().computeAndSetTypingStyle(properties.get(), undoAction);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> #if ENABLE(DRAG_SUPPORT)
</span></span></pre>
</div>
</div>
</body>
</html>