<!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 &quot;none&quot;.
(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  &lt;rniwa@webkit.org&gt;
+
+        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  &lt;cdumez@apple.com&gt;
</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(&quot;strikethrough&quot;, &quot;test&quot;, &quot;test&quot;);
</span><span class="cx"> 
</span><span class="cx"> testSingleToggle(&quot;strikethrough&quot;, &quot;&lt;u&gt;test&lt;/u&gt;&quot;, &quot;&lt;u&gt;&lt;strike&gt;test&lt;/strike&gt;&lt;/u&gt;&quot;);
</span><del>-testSingleToggle(&quot;underline&quot;, &quot;&lt;strike&gt;test&lt;/strike&gt;&quot;, &quot;&lt;u&gt;&lt;strike&gt;test&lt;/strike&gt;&lt;/u&gt;&quot;);
</del><ins>+testSingleToggle(&quot;underline&quot;, &quot;&lt;strike&gt;test&lt;/strike&gt;&quot;, &quot;&lt;strike&gt;&lt;u&gt;test&lt;/u&gt;&lt;/strike&gt;&quot;);
</ins><span class="cx"> 
</span><span class="cx"> testSingleToggle(&quot;strikethrough&quot;, '&lt;span style=&quot;text-decoration: overline;&quot;&gt;test&lt;/span&gt;', '&lt;span style=&quot;text-decoration: overline;&quot;&gt;&lt;strike&gt;test&lt;/strike&gt;&lt;/span&gt;');
</span><span class="cx"> testSingleToggle(&quot;underline&quot;, '&lt;span style=&quot;text-decoration: overline;&quot;&gt;test&lt;/span&gt;', '&lt;span style=&quot;text-decoration: overline;&quot;&gt;&lt;u&gt;test&lt;/u&gt;&lt;/span&gt;');
</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(&quot;underline&quot;, &quot;test&quot;, &quot;&lt;span style=\&quot;text-decoration: underline;\&quot;&gt;test&lt;/span&gt;&quot;);
</span><span class="cx"> testSingleToggle(&quot;underline&quot;, &quot;&lt;span style=\&quot;text-decoration: underline;\&quot;&gt;test&lt;/span&gt;&quot;, &quot;test&quot;);
</span><del>-testSingleToggle(&quot;underline&quot;, &quot;&lt;span style=\&quot;text-decoration: underline line-through overline;\&quot;&gt;test&lt;/span&gt;&quot;, &quot;&lt;span style=\&quot;text-decoration: overline line-through;\&quot;&gt;test&lt;/span&gt;&quot;);
</del><ins>+testSingleToggle(&quot;underline&quot;, &quot;&lt;span style=\&quot;text-decoration: underline line-through overline;\&quot;&gt;test&lt;/span&gt;&quot;,
+    &quot;&lt;span style=\&quot;text-decoration: line-through overline;\&quot;&gt;test&lt;/span&gt;&quot;);
</ins><span class="cx"> testSingleToggle(&quot;strikethrough&quot;, &quot;test&quot;, &quot;&lt;span style=\&quot;text-decoration: line-through;\&quot;&gt;test&lt;/span&gt;&quot;);
</span><span class="cx"> testSingleToggle(&quot;strikethrough&quot;, &quot;&lt;span style=\&quot;text-decoration: line-through;\&quot;&gt;test&lt;/span&gt;&quot;, &quot;test&quot;);
</span><span class="cx"> testSingleToggle(&quot;strikethrough&quot;, &quot;&lt;span style=\&quot;text-decoration: underline line-through overline;\&quot;&gt;test&lt;/span&gt;&quot;, &quot;&lt;span style=\&quot;text-decoration: underline overline;\&quot;&gt;test&lt;/span&gt;&quot;);
</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 &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+document.execCommand(&quot;styleWithCSS&quot;, false, false);
+
+Toggling strikeThrough
+PASS content(&quot;&lt;s&gt;&lt;u&gt;a&lt;/u&gt;b&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;) is &quot;&lt;u&gt;a&lt;/u&gt;b&quot;
+PASS content(&quot;&lt;s&gt;&lt;u&gt;a&lt;/u&gt;b&lt;u&gt;c&lt;/u&gt;&lt;/s&gt;&quot;); select(0, 3); toggle(&quot;strikeThrough&quot;) is &quot;&lt;u&gt;a&lt;/u&gt;b&lt;u&gt;c&lt;/u&gt;&quot;
+PASS content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(0, 3); toggle(&quot;strikeThrough&quot;) is &quot;a&lt;u&gt;b&lt;/u&gt;c&quot;
+PASS content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(1, 3); toggle(&quot;strikeThrough&quot;) is &quot;&lt;strike&gt;a&lt;/strike&gt;&lt;u&gt;b&lt;/u&gt;c&quot;
+PASS content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;) is &quot;a&lt;u&gt;b&lt;/u&gt;&lt;strike&gt;c&lt;/strike&gt;&quot;
+PASS content(&quot;&lt;s&gt;&lt;u&gt;ab&lt;/u&gt;&lt;/s&gt;c&quot;); select(1, 3); toggle(&quot;strikeThrough&quot;) is &quot;&lt;u&gt;&lt;strike&gt;a&lt;/strike&gt;b&lt;/u&gt;c&quot;
+PASS content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;&lt;/s&gt;c&quot;); select(1, 3); toggle(&quot;strikeThrough&quot;) is &quot;&lt;strike&gt;a&lt;/strike&gt;&lt;u&gt;b&lt;/u&gt;c&quot;
+PASS content(&quot;a&lt;s&gt;&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;) is &quot;&lt;strike&gt;a&lt;/strike&gt;&lt;s&gt;&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;
+PASS content(&quot;a&lt;strike&gt;&lt;u&gt;b&lt;/u&gt;c&lt;/strike&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;) is &quot;&lt;strike&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/strike&gt;&quot;
+PASS content(&quot;a&lt;u&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;) is &quot;&lt;strike&gt;a&lt;/strike&gt;&lt;u&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/u&gt;&quot;
+PASS content(&quot;a&lt;s&gt;&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;) is &quot;&lt;strike&gt;a&lt;/strike&gt;&lt;s&gt;&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/s&gt;&quot;
+PASS content(&quot;a&lt;strike&gt;&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/strike&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;) is &quot;&lt;strike&gt;a&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/strike&gt;&quot;
+
+Toggling underline
+PASS content(&quot;&lt;u&gt;&lt;s&gt;a&lt;/s&gt;b&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;) is &quot;&lt;s&gt;a&lt;/s&gt;b&quot;
+PASS content(&quot;&lt;u&gt;&lt;s&gt;a&lt;/s&gt;b&lt;s&gt;c&lt;/s&gt;&lt;/u&gt;&quot;); select(0, 3); toggle(&quot;underline&quot;) is &quot;&lt;s&gt;a&lt;/s&gt;b&lt;s&gt;c&lt;/s&gt;&quot;
+PASS content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(0, 3); toggle(&quot;underline&quot;) is &quot;a&lt;s&gt;b&lt;/s&gt;c&quot;
+PASS content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(1, 3); toggle(&quot;underline&quot;) is &quot;&lt;u&gt;a&lt;/u&gt;&lt;s&gt;b&lt;/s&gt;c&quot;
+PASS content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;) is &quot;a&lt;s&gt;b&lt;/s&gt;&lt;u&gt;c&lt;/u&gt;&quot;
+PASS content(&quot;&lt;u&gt;&lt;s&gt;ab&lt;/s&gt;&lt;/u&gt;c&quot;); select(1, 3); toggle(&quot;underline&quot;) is &quot;&lt;s&gt;&lt;u&gt;a&lt;/u&gt;b&lt;/s&gt;c&quot;
+PASS content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;&lt;/u&gt;c&quot;); select(1, 3); toggle(&quot;underline&quot;) is &quot;&lt;u&gt;a&lt;/u&gt;&lt;s&gt;b&lt;/s&gt;c&quot;
+PASS content(&quot;a&lt;u&gt;&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;) is &quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;
+PASS content(&quot;a&lt;s&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;) is &quot;&lt;u&gt;a&lt;/u&gt;&lt;s&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/s&gt;&quot;
+PASS content(&quot;a&lt;u&gt;&lt;b&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/b&gt;&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;) is &quot;&lt;u&gt;a&lt;b&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/b&gt;&lt;/u&gt;&quot;
+document.execCommand(&quot;styleWithCSS&quot;, false, true);
+
+Toggling strikeThrough
+PASS content('&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;');
+select(0, 2); toggle(&quot;strikeThrough&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b'
+PASS content('&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: underline&quot;&gt;c&lt;/span&gt;&lt;/span&gt;');
+select(0, 3); toggle(&quot;strikeThrough&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: underline;&quot;&gt;c&lt;/span&gt;'
+PASS content('&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(0, 3); toggle(&quot;strikeThrough&quot;) is 'a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c'
+PASS content('&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(1, 3); toggle(&quot;strikeThrough&quot;) is '&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c'
+PASS content('&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(0, 2); toggle(&quot;strikeThrough&quot;) is 'a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;c&lt;/span&gt;'
+PASS content('&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;ab&lt;/span&gt;&lt;/span&gt;c');
+select(1, 3); toggle(&quot;strikeThrough&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;c'
+PASS content('a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(0, 2); toggle(&quot;strikeThrough&quot;) is '&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;'
+PASS content('a&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;');
+select(0, 2); toggle(&quot;strikeThrough&quot;) is '&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;'
+PASS content('a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;bc&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;');
+select(0, 2); toggle(&quot;strikeThrough&quot;) is '&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;b&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: underline line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;'
+
+Toggling underline
+PASS content('&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;');
+select(0, 2); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b'
+PASS content('&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: line-through;&quot;&gt;c&lt;/span&gt;&lt;/span&gt;');
+select(0, 3); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: line-through;&quot;&gt;c&lt;/span&gt;'
+PASS content('&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(0, 3); toggle(&quot;underline&quot;) is 'a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c'
+PASS content('&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(1, 3); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c'
+PASS content('&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(0, 2); toggle(&quot;underline&quot;) is 'a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;c&lt;/span&gt;'
+PASS content('&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;ab&lt;/span&gt;&lt;/span&gt;c');
+select(1, 3); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;c'
+PASS content('&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;&lt;/span&gt;c');
+select(1, 3); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c'
+PASS content('a&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;');
+select(0, 2); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;'
+PASS content('a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;');
+select(0, 2); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;'
+PASS content('a&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;bc&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;');
+select(0, 2); toggle(&quot;underline&quot;) is '&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;b&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;'
+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>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;p id=&quot;description&quot;&gt;&lt;/p&gt;
+&lt;div id=&quot;console&quot;&gt;&lt;/div&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description(&quot;Test to make sure we can toggle underline and strike through separately.&quot;)
+
+var testContainer = document.createElement(&quot;div&quot;);
+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(&quot;styleWithCSS&quot;, false, false);
+    document.execCommand(toggleCommand, false, null);
+    if (testContainer.innerHTML === expectedContents) {
+        testPassed(&quot;one &quot; + toggleCommand + &quot; command converted &quot; + initialContents + &quot; to &quot; + expectedContents);
+    } else {
+        testFailed(&quot;one &quot; + toggleCommand + &quot; command converted &quot; + initialContents + &quot; to &quot; + testContainer.innerHTML + &quot;, expected &quot; + expectedContents);
+    }
+}
+
+function content(markup) {
+    testContainer.innerHTML = markup;
+}
+
+function select(offset, extent) {
+    getSelection().collapse(testContainer, 0);
+    for (var i = 0; i &lt; offset; i++)
+        getSelection().modify('move', 'forward', 'character');
+    for (var i = offset; i &lt; extent; i++)
+        getSelection().modify('extend', 'forward', 'character');
+}
+
+function toggle(command) {
+    document.execCommand(command, false, null);
+    return testContainer.innerHTML;
+}
+
+evalAndLog('document.execCommand(&quot;styleWithCSS&quot;, false, false);');
+
+debug('');
+debug('Toggling strikeThrough');
+shouldBe('content(&quot;&lt;s&gt;&lt;u&gt;a&lt;/u&gt;b&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;u&gt;a&lt;/u&gt;b&quot;');
+shouldBe('content(&quot;&lt;s&gt;&lt;u&gt;a&lt;/u&gt;b&lt;u&gt;c&lt;/u&gt;&lt;/s&gt;&quot;); select(0, 3); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;u&gt;a&lt;/u&gt;b&lt;u&gt;c&lt;/u&gt;&quot;');
+shouldBe('content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(0, 3); toggle(&quot;strikeThrough&quot;)', '&quot;a&lt;u&gt;b&lt;/u&gt;c&quot;');
+shouldBe('content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(1, 3); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;strike&gt;a&lt;/strike&gt;&lt;u&gt;b&lt;/u&gt;c&quot;');
+shouldBe('content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;)', '&quot;a&lt;u&gt;b&lt;/u&gt;&lt;strike&gt;c&lt;/strike&gt;&quot;');
+shouldBe('content(&quot;&lt;s&gt;&lt;u&gt;ab&lt;/u&gt;&lt;/s&gt;c&quot;); select(1, 3); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;u&gt;&lt;strike&gt;a&lt;/strike&gt;b&lt;/u&gt;c&quot;');
+shouldBe('content(&quot;&lt;s&gt;a&lt;u&gt;b&lt;/u&gt;&lt;/s&gt;c&quot;); select(1, 3); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;strike&gt;a&lt;/strike&gt;&lt;u&gt;b&lt;/u&gt;c&quot;');
+shouldBe('content(&quot;a&lt;s&gt;&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;strike&gt;a&lt;/strike&gt;&lt;s&gt;&lt;u&gt;b&lt;/u&gt;c&lt;/s&gt;&quot;');
+shouldBe('content(&quot;a&lt;strike&gt;&lt;u&gt;b&lt;/u&gt;c&lt;/strike&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;strike&gt;a&lt;u&gt;b&lt;/u&gt;c&lt;/strike&gt;&quot;');
+shouldBe('content(&quot;a&lt;u&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;strike&gt;a&lt;/strike&gt;&lt;u&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/u&gt;&quot;');
+shouldBe('content(&quot;a&lt;s&gt;&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;strike&gt;a&lt;/strike&gt;&lt;s&gt;&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/s&gt;&quot;');
+shouldBe('content(&quot;a&lt;strike&gt;&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/strike&gt;&quot;); select(0, 2); toggle(&quot;strikeThrough&quot;)', '&quot;&lt;strike&gt;a&lt;b&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/b&gt;&lt;/strike&gt;&quot;');
+
+debug('');
+debug('Toggling underline');
+shouldBe('content(&quot;&lt;u&gt;&lt;s&gt;a&lt;/s&gt;b&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;)', '&quot;&lt;s&gt;a&lt;/s&gt;b&quot;');
+shouldBe('content(&quot;&lt;u&gt;&lt;s&gt;a&lt;/s&gt;b&lt;s&gt;c&lt;/s&gt;&lt;/u&gt;&quot;); select(0, 3); toggle(&quot;underline&quot;)', '&quot;&lt;s&gt;a&lt;/s&gt;b&lt;s&gt;c&lt;/s&gt;&quot;');
+shouldBe('content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(0, 3); toggle(&quot;underline&quot;)', '&quot;a&lt;s&gt;b&lt;/s&gt;c&quot;');
+shouldBe('content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(1, 3); toggle(&quot;underline&quot;)', '&quot;&lt;u&gt;a&lt;/u&gt;&lt;s&gt;b&lt;/s&gt;c&quot;');
+shouldBe('content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;)', '&quot;a&lt;s&gt;b&lt;/s&gt;&lt;u&gt;c&lt;/u&gt;&quot;');
+shouldBe('content(&quot;&lt;u&gt;&lt;s&gt;ab&lt;/s&gt;&lt;/u&gt;c&quot;); select(1, 3); toggle(&quot;underline&quot;)', '&quot;&lt;s&gt;&lt;u&gt;a&lt;/u&gt;b&lt;/s&gt;c&quot;');
+shouldBe('content(&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;&lt;/u&gt;c&quot;); select(1, 3); toggle(&quot;underline&quot;)', '&quot;&lt;u&gt;a&lt;/u&gt;&lt;s&gt;b&lt;/s&gt;c&quot;');
+shouldBe('content(&quot;a&lt;u&gt;&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;)', '&quot;&lt;u&gt;a&lt;s&gt;b&lt;/s&gt;c&lt;/u&gt;&quot;');
+shouldBe('content(&quot;a&lt;s&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/s&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;)', '&quot;&lt;u&gt;a&lt;/u&gt;&lt;s&gt;&lt;u&gt;bc&lt;/u&gt;&lt;/s&gt;&quot;');
+shouldBe('content(&quot;a&lt;u&gt;&lt;b&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/b&gt;&lt;/u&gt;&quot;); select(0, 2); toggle(&quot;underline&quot;)', '&quot;&lt;u&gt;a&lt;b&gt;&lt;s&gt;bc&lt;/s&gt;&lt;/b&gt;&lt;/u&gt;&quot;');
+
+evalAndLog('document.execCommand(&quot;styleWithCSS&quot;, false, true);');
+
+debug('');
+debug('Toggling strikeThrough');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;strikeThrough&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: underline&quot;&gt;c&lt;/span&gt;&lt;/span&gt;\');\n'
+    + 'select(0, 3); toggle(&quot;strikeThrough&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: underline;&quot;&gt;c&lt;/span&gt;\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(0, 3); toggle(&quot;strikeThrough&quot;)',
+    '\'a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(1, 3); toggle(&quot;strikeThrough&quot;)',
+    '\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;strikeThrough&quot;)',
+    '\'a&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;c&lt;/span&gt;\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;ab&lt;/span&gt;&lt;/span&gt;c\');\n'
+    + 'select(1, 3); toggle(&quot;strikeThrough&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;c\'');
+shouldBe('content(\'a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;strikeThrough&quot;)',
+    '\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;span style=&quot;text-decoration: underline line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\'');
+shouldBe('content(\'a&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;strikeThrough&quot;)',
+    '\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;\'');
+shouldBe('content(\'a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;bc&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;strikeThrough&quot;)',
+    '\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;b&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: underline line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;\'');
+
+debug('');
+debug('Toggling underline');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: line-through;&quot;&gt;c&lt;/span&gt;&lt;/span&gt;\');\n'
+    + 'select(0, 3); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;a&lt;/span&gt;b&lt;span style=&quot;text-decoration: line-through;&quot;&gt;c&lt;/span&gt;\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(0, 3); toggle(&quot;underline&quot;)',
+    '\'a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(1, 3); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;underline&quot;)',
+    '\'a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;c&lt;/span&gt;\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;ab&lt;/span&gt;&lt;/span&gt;c\');\n'
+    + 'select(1, 3); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;b&lt;/span&gt;c\'');
+shouldBe('content(\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;&lt;/span&gt;c\');\n'
+    + 'select(1, 3); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c\'');
+shouldBe('content(\'a&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;span style=&quot;text-decoration: line-through underline;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;\'');
+shouldBe('content(\'a&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;bc&lt;/span&gt;&lt;/span&gt;\'');
+shouldBe('content(\'a&lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;bc&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;\');\n'
+    + 'select(0, 2); toggle(&quot;underline&quot;)',
+    '\'&lt;span style=&quot;text-decoration: underline;&quot;&gt;a&lt;b&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;span style=&quot;text-decoration: underline line-through;&quot;&gt;b&lt;/span&gt;c&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;\'');
+
+document.body.removeChild(testContainer);
+
+var successfullyParsed = true;
+
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</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 &lt;u&gt;&lt;b&gt;&lt;strike&gt;test&lt;/strike&gt;&lt;/b&gt;&lt;/u&gt; to &lt;u&gt;&lt;b&gt;test&lt;/b&gt;&lt;/u&gt;
</span><span class="cx"> PASS two strikethrough commands converted test to test
</span><span class="cx"> PASS one strikethrough command converted &lt;u&gt;test&lt;/u&gt; to &lt;u&gt;&lt;strike&gt;test&lt;/strike&gt;&lt;/u&gt;
</span><del>-PASS one underline command converted &lt;strike&gt;test&lt;/strike&gt; to &lt;u&gt;&lt;strike&gt;test&lt;/strike&gt;&lt;/u&gt;
</del><ins>+PASS one underline command converted &lt;strike&gt;test&lt;/strike&gt; to &lt;strike&gt;&lt;u&gt;test&lt;/u&gt;&lt;/strike&gt;
</ins><span class="cx"> PASS one strikethrough command converted &lt;span style=&quot;text-decoration: overline;&quot;&gt;test&lt;/span&gt; to &lt;span style=&quot;text-decoration: overline;&quot;&gt;&lt;strike&gt;test&lt;/strike&gt;&lt;/span&gt;
</span><span class="cx"> PASS one underline command converted &lt;span style=&quot;text-decoration: overline;&quot;&gt;test&lt;/span&gt; to &lt;span style=&quot;text-decoration: overline;&quot;&gt;&lt;u&gt;test&lt;/u&gt;&lt;/span&gt;
</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 &lt;span style=&quot;text-decoration: underline;&quot;&gt;test&lt;/span&gt;
</span><span class="cx"> PASS one underline command converted &lt;span style=&quot;text-decoration: underline;&quot;&gt;test&lt;/span&gt; to test
</span><del>-PASS one underline command converted &lt;span style=&quot;text-decoration: underline line-through overline;&quot;&gt;test&lt;/span&gt; to &lt;span style=&quot;text-decoration: overline line-through;&quot;&gt;test&lt;/span&gt;
</del><ins>+PASS one underline command converted &lt;span style=&quot;text-decoration: underline line-through overline;&quot;&gt;test&lt;/span&gt; to &lt;span style=&quot;text-decoration: line-through overline;&quot;&gt;test&lt;/span&gt;
</ins><span class="cx"> PASS one strikethrough command converted test to &lt;span style=&quot;text-decoration: line-through;&quot;&gt;test&lt;/span&gt;
</span><span class="cx"> PASS one strikethrough command converted &lt;span style=&quot;text-decoration: line-through;&quot;&gt;test&lt;/span&gt; to test
</span><span class="cx"> PASS one strikethrough command converted &lt;span style=&quot;text-decoration: underline line-through overline;&quot;&gt;test&lt;/span&gt; to &lt;span style=&quot;text-decoration: underline overline;&quot;&gt;test&lt;/span&gt;
</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 &quot;test&quot; is both bold and blue:
</span><span class="cx"> | &lt;span&gt;
</span><del>-|   style=&quot;color: blue; font-weight: 900;&quot;
</del><ins>+|   style=&quot;font-weight: 900; color: blue;&quot;
</ins><span class="cx"> |   &quot;&lt;#selection-anchor&gt;test&lt;#selection-focus&gt;&quot;
</span><span class="cx"> 
</span><span class="cx"> Redo should only remove font-weight and leave &quot;test&quot; 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  &lt;rniwa@webkit.org&gt;
+
+        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 &quot;none&quot;.
+        (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  &lt;eric.carlson@apple.com&gt;
</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() &amp;&amp; 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&lt;Node&gt; block = enclosingBlock(paragraphStart.deepEquivalent().deprecatedNode());
</span><span class="cx">             if (!m_removeOnly) {
</span><span class="cx">                 RefPtr&lt;Node&gt; 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-&gt;conflictsWithInlineStyleOfElement(element);
</span><span class="cx"> 
</span><del>-    Vector&lt;CSSPropertyID&gt; properties;
-    if (!style-&gt;conflictsWithInlineStyleOfElement(element, extractedStyle, properties))
</del><ins>+    RefPtr&lt;MutableStyleProperties&gt; newInlineStyle;
+    if (!style-&gt;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 &lt; properties.size(); i++)
-        removeCSSProperty(element, properties[i]);
-
-    // No need to serialize &lt;foo style=&quot;&quot;&gt; if we just removed the last css property
-    if (element-&gt;inlineStyle()-&gt;isEmpty())
</del><ins>+    if (newInlineStyle-&gt;isEmpty())
</ins><span class="cx">         removeNodeAttribute(element, styleAttr);
</span><ins>+    else
+        setNodeAttribute(element, styleAttr, newInlineStyle-&gt;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&amp; 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 &lt;B&gt; and &lt;I&gt;, 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()-&gt;asText();
</ins><span class="cx">     StringBuilder cssText;
</span><span class="cx">     cssText.append(cssStyle);
</span><span class="cx">     if (const StyleProperties* decl = block-&gt;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-&gt;inlineStyle()) {
-                String existingText = existingStyle-&gt;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-&gt;inlineStyle()) {
+                auto inlineStyle = EditingStyle::create(existingStyle);
+                inlineStyle-&gt;overrideWithStyle(styleToMerge);
+                setNodeAttribute(styleContainer, styleAttr, inlineStyle-&gt;style()-&gt;asText());
</ins><span class="cx">             } else
</span><del>-                setNodeAttribute(styleContainer, styleAttr, styleChange.cssStyle());
</del><ins>+                setNodeAttribute(styleContainer, styleAttr, styleToMerge-&gt;asText());
</ins><span class="cx">         } else {
</span><span class="cx">             RefPtr&lt;Element&gt; styleElement = createStyleSpanElement(document());
</span><del>-            styleElement-&gt;setAttribute(styleAttr, styleChange.cssStyle());
</del><ins>+            styleElement-&gt;setAttribute(styleAttr, styleToMerge-&gt;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&amp; tagName);
</span><span class="cx"> 
</span><span class="cx">     virtual ~HTMLElementEquivalent() { }
</span><del>-    virtual bool matches(const Element* element) const { return !m_tagName || element-&gt;hasTagName(*m_tagName); }
</del><ins>+    virtual bool matches(const Element&amp; 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-&gt;getPropertyCSSValue(m_propertyID); }
-    virtual bool valueIsPresentInStyle(Element*, StyleProperties*) const;
</del><ins>+    virtual bool propertyExistsInStyle(const EditingStyle&amp; style) const { return style.m_mutableStyle &amp;&amp; style.m_mutableStyle-&gt;getPropertyCSSValue(m_propertyID); }
+    virtual bool valueIsPresentInStyle(Element&amp;, const EditingStyle&amp;) 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&amp; element, const EditingStyle&amp; style) const
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;CSSValue&gt; value = style-&gt;getPropertyCSSValue(m_propertyID);
</del><ins>+    RefPtr&lt;CSSValue&gt; value = style.m_mutableStyle-&gt;getPropertyCSSValue(m_propertyID);
</ins><span class="cx">     return matches(element) &amp;&amp; is&lt;CSSPrimitiveValue&gt;(value.get()) &amp;&amp; downcast&lt;CSSPrimitiveValue&gt;(*value).getValueID() == m_primitiveValue-&gt;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&amp; tagName);
</del><ins>+    HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName&amp; 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&amp; style) const override
+    {
+        if (changeInStyle(style) != TextDecorationChange::None)
+            return true;
</ins><span class="cx"> 
</span><del>-HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName&amp; 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-&gt;getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) || style-&gt;getPropertyCSSValue(CSSPropertyTextDecoration);
-}
</del><ins>+        auto&amp; 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&lt;CSSValue&gt; styleValue = style-&gt;getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
-    if (!styleValue)
-        styleValue = style-&gt;getPropertyCSSValue(CSSPropertyTextDecoration);
-    return matches(element) &amp;&amp; is&lt;CSSValueList&gt;(styleValue.get()) &amp;&amp; downcast&lt;CSSValueList&gt;(*styleValue).hasValue(m_primitiveValue.get());
-}
</del><ins>+    bool valueIsPresentInStyle(Element&amp; element, const EditingStyle&amp; style) const override
+    {
+        if (!matches(element))
+            return false;
+        auto change = changeInStyle(style);
+        if (change != TextDecorationChange::None)
+            return change == TextDecorationChange::Add;
+        RefPtr&lt;CSSValue&gt; styleValue = style.m_mutableStyle-&gt;getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
+        if (!styleValue)
+            styleValue = style.m_mutableStyle-&gt;getPropertyCSSValue(CSSPropertyTextDecoration);
+        return is&lt;CSSValueList&gt;(styleValue.get()) &amp;&amp; downcast&lt;CSSValueList&gt;(*styleValue).hasValue(m_primitiveValue.get());
+    }
</ins><span class="cx"> 
</span><ins>+private:
+    TextDecorationChange changeInStyle(const EditingStyle&amp; 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&amp; tagName, const QualifiedName&amp; attrName);
</span><span class="cx">     HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName&amp; attrName);
</span><span class="cx"> 
</span><del>-    bool matches(const Element* elem) const { return HTMLElementEquivalent::matches(elem) &amp;&amp; elem-&gt;hasAttribute(m_attrName); }
</del><ins>+    bool matches(const Element&amp; element) const { return HTMLElementEquivalent::matches(element) &amp;&amp; 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&amp;, const EditingStyle&amp;) const;
</ins><span class="cx">     virtual void addToStyle(Element*, EditingStyle*) const;
</span><span class="cx">     virtual PassRefPtr&lt;CSSValue&gt; attributeValueAsCSSValue(Element*) const;
</span><span class="cx">     inline const QualifiedName&amp; 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&amp; element, const EditingStyle&amp; style) const
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;CSSValue&gt; value = attributeValueAsCSSValue(element);
-    RefPtr&lt;CSSValue&gt; styleValue = style-&gt;getPropertyCSSValue(m_propertyID);
</del><ins>+    RefPtr&lt;CSSValue&gt; value = attributeValueAsCSSValue(&amp;element);
+    RefPtr&lt;CSSValue&gt; styleValue = style.m_mutableStyle-&gt;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&lt;unsigned&gt;(TextDecorationChange::None))
+    , m_strikeThroughChange(static_cast&lt;unsigned&gt;(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&amp; 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-&gt;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&amp; 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-&gt;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-&gt;isEmpty()) &amp;&amp; m_fontSizeDelta == NoFontDelta;
</del><ins>+    return (!m_mutableStyle || m_mutableStyle-&gt;isEmpty()) &amp;&amp; m_fontSizeDelta == NoFontDelta
+        &amp;&amp; underlineChange() == TextDecorationChange::None &amp;&amp; strikeThroughChange() == TextDecorationChange::None;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool EditingStyle::textDirection(WritingDirection&amp; 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&amp; valueList, TextDecorationChange change, Ref&lt;CSSPrimitiveValue&gt;&amp;&amp; value)
+{
+    switch (change) {
+    case TextDecorationChange::None:
+        break;
+    case TextDecorationChange::Add:
+        valueList.append(WTF::move(value));
+        break;
+    case TextDecorationChange::Remove:
+        valueList.removeAll(&amp;value.get());
+        break;
+    }
+}
+
+void EditingStyle::overrideTypingStyleAt(const EditingStyle&amp; style, const Position&amp; 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 &amp;&amp; strikeThroughChange == TextDecorationChange::None)
+        return;
+
+    if (!m_mutableStyle)
+        m_mutableStyle = MutableStyleProperties::create();
+
+    Ref&lt;CSSPrimitiveValue&gt; underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+    Ref&lt;CSSPrimitiveValue&gt; lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
+    RefPtr&lt;CSSValue&gt; value = m_mutableStyle-&gt;getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
+    RefPtr&lt;CSSValueList&gt; valueList;
+    if (value &amp;&amp; value-&gt;isValueList()) {
+        valueList = downcast&lt;CSSValueList&gt;(*value).copy();
+        applyTextDecorationChangeToValueList(*valueList, underlineChange, WTF::move(underline));
+        applyTextDecorationChangeToValueList(*valueList, strikeThroughChange, WTF::move(lineThrough));
+    } else {
+        valueList = CSSValueList::createSpaceSeparated();
+        if (underlineChange == TextDecorationChange::Add)
+            valueList-&gt;append(WTF::move(underline));
+        if (strikeThroughChange == TextDecorationChange::Add)
+            valueList-&gt;append(WTF::move(lineThrough));
+    }
+    m_mutableStyle-&gt;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&lt;EditingStyle&gt; EditingStyle::copy() const
</span><span class="lines">@@ -550,6 +622,8 @@
</span><span class="cx">     if (m_mutableStyle)
</span><span class="cx">         copy-&gt;m_mutableStyle = m_mutableStyle-&gt;mutableCopy();
</span><span class="cx">     copy-&gt;m_shouldUseFixedDefaultFontSize = m_shouldUseFixedDefaultFontSize;
</span><ins>+    copy-&gt;m_underlineChange = m_underlineChange;
+    copy-&gt;m_strikeThroughChange = m_strikeThroughChange;
</ins><span class="cx">     copy-&gt;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&lt;CSSPropertyID&gt;* conflictingProperties) const
</del><ins>+static RefPtr&lt;CSSValueList&gt; textDecorationValueList(const StyleProperties&amp; properties)
</ins><span class="cx"> {
</span><ins>+    RefPtr&lt;CSSValue&gt; value = properties.getPropertyCSSValue(CSSPropertyTextDecoration);
+    if (!is&lt;CSSValueList&gt;(value.get()))
+        return nullptr;
+    return downcast&lt;CSSValueList&gt;(value.get());
+}
+
+bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr&lt;MutableStyleProperties&gt;* newInlineStylePtr, EditingStyle* extractedStyle) const
+{
</ins><span class="cx">     ASSERT(element);
</span><del>-    ASSERT(!conflictingProperties || conflictingProperties-&gt;isEmpty());
</del><span class="cx"> 
</span><span class="cx">     const StyleProperties* inlineStyle = element-&gt;inlineStyle();
</span><del>-    if (!m_mutableStyle || !inlineStyle)
</del><ins>+    if (!inlineStyle)
</ins><span class="cx">         return false;
</span><ins>+    bool conflicts = false;
+    RefPtr&lt;MutableStyleProperties&gt; newInlineStyle;
+    if (newInlineStylePtr) {
+        newInlineStyle = inlineStyle-&gt;mutableCopy();
+        *newInlineStylePtr = newInlineStyle;
+    }
</ins><span class="cx"> 
</span><del>-    unsigned propertyCount = m_mutableStyle-&gt;propertyCount();
</del><ins>+    bool shouldRemoveUnderline = underlineChange() == TextDecorationChange::Remove;
+    bool shouldRemoveStrikeThrough = strikeThroughChange() == TextDecorationChange::Remove;
+    if (shouldRemoveUnderline || shouldRemoveStrikeThrough) {
+        if (RefPtr&lt;CSSValueList&gt; valueList = textDecorationValueList(*inlineStyle)) {
+            RefPtr&lt;CSSValueList&gt; newValueList = valueList-&gt;copy();
+            RefPtr&lt;CSSValueList&gt; extractedValueList = CSSValueList::createSpaceSeparated();
+
+            Ref&lt;CSSPrimitiveValue&gt; underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+            if (shouldRemoveUnderline &amp;&amp; valueList-&gt;hasValue(underline.ptr())) {
+                if (!newInlineStyle)
+                    return true;
+                newValueList-&gt;removeAll(underline.ptr());
+                extractedValueList-&gt;append(WTF::move(underline));
+            }
+
+            Ref&lt;CSSPrimitiveValue&gt; lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
+            if (shouldRemoveStrikeThrough &amp;&amp; valueList-&gt;hasValue(lineThrough.ptr())) {
+                if (!newInlineStyle)
+                    return true;
+                newValueList-&gt;removeAll(lineThrough.ptr());
+                extractedValueList-&gt;append(WTF::move(lineThrough));
+            }
+
+            if (extractedValueList-&gt;length()) {
+                conflicts = true;
+                if (newValueList-&gt;length())
+                    newInlineStyle-&gt;setProperty(CSSPropertyTextDecoration, newValueList);
+                else
+                    newInlineStyle-&gt;removeProperty(CSSPropertyTextDecoration);
+
+                if (extractedStyle) {
+                    bool isImportant = inlineStyle-&gt;propertyIsImportant(CSSPropertyTextDecoration);
+                    extractedStyle-&gt;setProperty(CSSPropertyTextDecoration, extractedValueList-&gt;cssText(), isImportant);
+                }
+            }
+        }
+    }
+
+    unsigned propertyCount = m_mutableStyle ? m_mutableStyle-&gt;propertyCount() : 0;
</ins><span class="cx">     for (unsigned i = 0; i &lt; propertyCount; ++i) {
</span><span class="cx">         CSSPropertyID propertyID = m_mutableStyle-&gt;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 &amp;&amp; inlineStyle-&gt;getPropertyCSSValue(CSSPropertyTextDecoration)) {
</span><del>-            if (!conflictingProperties)
</del><ins>+            if (!newInlineStyle)
</ins><span class="cx">                 return true;
</span><del>-            conflictingProperties-&gt;append(CSSPropertyTextDecoration);
</del><ins>+            conflicts = true;
+            newInlineStyle-&gt;removeProperty(CSSPropertyTextDecoration);
</ins><span class="cx">             if (extractedStyle)
</span><span class="cx">                 extractedStyle-&gt;setProperty(CSSPropertyTextDecoration, inlineStyle-&gt;getPropertyValue(CSSPropertyTextDecoration), inlineStyle-&gt;propertyIsImportant(CSSPropertyTextDecoration));
</span><del>-            continue;
</del><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!inlineStyle-&gt;getPropertyCSSValue(propertyID))
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><span class="cx">         if (propertyID == CSSPropertyUnicodeBidi &amp;&amp; inlineStyle-&gt;getPropertyCSSValue(CSSPropertyDirection)) {
</span><del>-            if (!conflictingProperties)
</del><ins>+            if (!newInlineStyle)
</ins><span class="cx">                 return true;
</span><del>-            conflictingProperties-&gt;append(CSSPropertyDirection);
</del><ins>+            conflicts = true;
+            newInlineStyle-&gt;removeProperty(CSSPropertyDirection);
</ins><span class="cx">             if (extractedStyle)
</span><span class="cx">                 extractedStyle-&gt;setProperty(propertyID, inlineStyle-&gt;getPropertyValue(propertyID), inlineStyle-&gt;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-&gt;append(propertyID);
-
</del><ins>+        conflicts = true;
+        newInlineStyle-&gt;removeProperty(propertyID);
</ins><span class="cx">         if (extractedStyle)
</span><span class="cx">             extractedStyle-&gt;setProperty(propertyID, inlineStyle-&gt;getPropertyValue(propertyID), inlineStyle-&gt;propertyIsImportant(propertyID));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return conflictingProperties &amp;&amp; !conflictingProperties-&gt;isEmpty();
</del><ins>+    return conflicts;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static const Vector&lt;std::unique_ptr&lt;HTMLElementEquivalent&gt;&gt;&amp; 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&lt;std::unique_ptr&lt;HTMLElementEquivalent&gt;&gt;&amp; HTMLElementEquivalents = htmlElementEquivalents();
</span><del>-    for (size_t i = 0; i &lt; HTMLElementEquivalents.size(); ++i) {
-        const HTMLElementEquivalent* equivalent = HTMLElementEquivalents[i].get();
-        if (equivalent-&gt;matches(element) &amp;&amp; equivalent-&gt;propertyExistsInStyle(m_mutableStyle.get())
-            &amp;&amp; (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent-&gt;valueIsPresentInStyle(element, m_mutableStyle.get()))) {
</del><ins>+    for (auto&amp; equivalent : HTMLElementEquivalents) {
+        if (equivalent-&gt;matches(*element) &amp;&amp; equivalent-&gt;propertyExistsInStyle(*this)
+            &amp;&amp; (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent-&gt;valueIsPresentInStyle(*element, *this))) {
</ins><span class="cx">             if (extractedStyle)
</span><span class="cx">                 equivalent-&gt;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&lt;std::unique_ptr&lt;HTMLAttributeEquivalent&gt;&gt;&amp; HTMLAttributeEquivalents = htmlAttributeEquivalents();
</span><del>-    for (size_t i = 0; i &lt; HTMLAttributeEquivalents.size(); ++i) {
-        if (HTMLAttributeEquivalents[i]-&gt;matches(element) &amp;&amp; HTMLAttributeEquivalents[i]-&gt;propertyExistsInStyle(m_mutableStyle.get())
-            &amp;&amp; !HTMLAttributeEquivalents[i]-&gt;valueIsPresentInStyle(element, m_mutableStyle.get()))
</del><ins>+    for (auto&amp; equivalent : HTMLAttributeEquivalents) {
+        if (equivalent-&gt;matches(*element) &amp;&amp; equivalent-&gt;propertyExistsInStyle(*this) &amp;&amp; !equivalent-&gt;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 &amp;&amp; equivalent-&gt;attributeName() == HTMLNames::dirAttr)
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        if (!equivalent-&gt;matches(element) || !equivalent-&gt;propertyExistsInStyle(m_mutableStyle.get())
-            || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle &amp;&amp; equivalent-&gt;valueIsPresentInStyle(element, m_mutableStyle.get())))
</del><ins>+        if (!equivalent-&gt;matches(*element) || !equivalent-&gt;propertyExistsInStyle(*this)
+            || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle &amp;&amp; equivalent-&gt;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)-&gt;isEmpty();
</del><ins>+
+    bool shouldAddUnderline = underlineChange() == TextDecorationChange::Add;
+    bool shouldAddLineThrough = strikeThroughChange() == TextDecorationChange::Add;
+    if (shouldAddUnderline || shouldAddLineThrough) {
+        bool hasUnderline = false;
+        bool hasLineThrough = false;
+        if (RefPtr&lt;CSSValue&gt; value = computedStyle.propertyValue(CSSPropertyTextDecoration)) {
+            if (value-&gt;isValueList()) {
+                const CSSValueList&amp; valueList = downcast&lt;CSSValueList&gt;(*value);
+                hasUnderline = valueList.hasValue(&amp;cssValuePool().createIdentifierValue(CSSValueUnderline).get());
+                hasLineThrough = valueList.hasValue(&amp;cssValuePool().createIdentifierValue(CSSValueLineThrough).get());
+            }
+        }
+        if ((shouldAddUnderline &amp;&amp; !hasUnderline) || (shouldAddLineThrough &amp;&amp; !hasLineThrough))
+            return false;
+    }
+
+    return !m_mutableStyle || getPropertiesNotIn(*m_mutableStyle, computedStyle)-&gt;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&lt;std::unique_ptr&lt;HTMLElementEquivalent&gt;&gt;&amp; HTMLElementEquivalents = htmlElementEquivalents();
</span><span class="cx">         size_t i;
</span><span class="cx">         for (i = 0; i &lt; HTMLElementEquivalents.size(); ++i) {
</span><del>-            if (HTMLElementEquivalents[i]-&gt;matches(element)) {
</del><ins>+            if (HTMLElementEquivalents[i]-&gt;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&lt;std::unique_ptr&lt;HTMLAttributeEquivalent&gt;&gt;&amp; HTMLAttributeEquivalents = htmlAttributeEquivalents();
</span><span class="cx">     for (size_t i = 0; i &lt; HTMLAttributeEquivalents.size(); ++i) {
</span><del>-        if (HTMLAttributeEquivalents[i]-&gt;matches(element) &amp;&amp; HTMLAttributeEquivalents[i]-&gt;attributeName() != HTMLNames::dirAttr)
</del><ins>+        if (HTMLAttributeEquivalents[i]-&gt;matches(*element) &amp;&amp; HTMLAttributeEquivalents[i]-&gt;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&amp; style)
</ins><span class="cx"> {
</span><del>-    return equivalent-&gt;matches(element) &amp;&amp; (!element-&gt;inlineStyle() || !equivalent-&gt;propertyExistsInStyle(element-&gt;inlineStyle()))
-        &amp;&amp; (mode == EditingStyle::OverrideValues || !equivalent-&gt;propertyExistsInStyle(style));
</del><ins>+    if (!equivalent-&gt;matches(*element))
+        return false;
+    if (mode != EditingStyle::OverrideValues &amp;&amp; equivalent-&gt;propertyExistsInStyle(style))
+        return false;
+
+    return !element-&gt;inlineStyle() || !equivalent-&gt;propertyExistsInStyle(EditingStyle::create(element-&gt;inlineStyle()).get());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static PassRefPtr&lt;MutableStyleProperties&gt; 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&lt;std::unique_ptr&lt;HTMLElementEquivalent&gt;&gt;&amp; elementEquivalents = htmlElementEquivalents();
</span><span class="cx">     for (size_t i = 0; i &lt; 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]-&gt;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 &lt; attributeEquivalents.size(); ++i) {
</span><span class="cx">         if (attributeEquivalents[i]-&gt;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]-&gt;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&amp; mergedValue, const CSSValueList&amp; valueToMerge)
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;CSSPrimitiveValue&gt; underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
-    RefPtr&lt;CSSPrimitiveValue&gt; lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
</del><ins>+    Ref&lt;CSSPrimitiveValue&gt; underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+    Ref&lt;CSSPrimitiveValue&gt; lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
</ins><span class="cx"> 
</span><del>-    if (valueToMerge-&gt;hasValue(underline.get()) &amp;&amp; !mergedValue-&gt;hasValue(underline.get()))
-        mergedValue-&gt;append(underline.releaseNonNull());
</del><ins>+    if (valueToMerge.hasValue(underline.ptr()) &amp;&amp; !mergedValue.hasValue(underline.ptr()))
+        mergedValue.append(WTF::move(underline));
</ins><span class="cx"> 
</span><del>-    if (valueToMerge-&gt;hasValue(lineThrough.get()) &amp;&amp; !mergedValue-&gt;hasValue(lineThrough.get()))
-        mergedValue-&gt;append(lineThrough.releaseNonNull());
</del><ins>+    if (valueToMerge.hasValue(lineThrough.ptr()) &amp;&amp; !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&lt;CSSValue&gt; value = m_mutableStyle-&gt;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) &amp;&amp; property.value()-&gt;isValueList() &amp;&amp; value) {
</del><ins>+        if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect)
+            &amp;&amp; is&lt;CSSValueList&gt;(*property.value()) &amp;&amp; value) {
</ins><span class="cx">             if (is&lt;CSSValueList&gt;(*value)) {
</span><del>-                mergeTextDecorationValues(downcast&lt;CSSValueList&gt;(value.get()), downcast&lt;CSSValueList&gt;(property.value()));
</del><ins>+                RefPtr&lt;CSSValueList&gt; newValue = downcast&lt;CSSValueList&gt;(*value).copy();
+                mergeTextDecorationValues(*newValue, downcast&lt;CSSValueList&gt;(*property.value()));
+                m_mutableStyle-&gt;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 &amp;&amp; !value))
</span><del>-            m_mutableStyle-&gt;setProperty(property.id(), property.value()-&gt;cssText(), property.isImportant());
</del><ins>+            m_mutableStyle-&gt;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() ? &amp;position.anchorNode()-&gt;document() : 0;
-    if (!style || !style-&gt;style() || !document || !document-&gt;frame())
</del><ins>+    Document* document = position.deprecatedNode() ? &amp;position.deprecatedNode()-&gt;document() : 0;
+    if (!style || style-&gt;isEmpty() || !document || !document-&gt;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&lt;MutableStyleProperties&gt; mutableStyle = getPropertiesNotIn(*style-&gt;style(), computedStyle);
</del><ins>+    RefPtr&lt;MutableStyleProperties&gt; mutableStyle = style-&gt;style() ?
+        getPropertiesNotIn(*style-&gt;style(), computedStyle) : MutableStyleProperties::create();
</ins><span class="cx"> 
</span><span class="cx">     reconcileTextDecorationProperties(mutableStyle.get());
</span><del>-    if (!document-&gt;frame()-&gt;editor().shouldStyleWithCSS())
</del><ins>+    bool shouldStyleWithCSS = document-&gt;frame()-&gt;editor().shouldStyleWithCSS();
+    if (!shouldStyleWithCSS)
</ins><span class="cx">         extractTextStyles(document, *mutableStyle, computedStyle.useFixedFontDefaultSize());
</span><span class="cx"> 
</span><ins>+    bool shouldAddUnderline = style-&gt;underlineChange() == TextDecorationChange::Add;
+    bool shouldAddStrikeThrough = style-&gt;strikeThroughChange() == TextDecorationChange::Add;
+    if (shouldAddUnderline || shouldAddStrikeThrough) {
+        RefPtr&lt;CSSValue&gt; value = computedStyle.propertyValue(CSSPropertyWebkitTextDecorationsInEffect);
+        if (!is&lt;CSSValueList&gt;(value.get()))
+            value = computedStyle.propertyValue(CSSPropertyTextDecoration);
+
+        RefPtr&lt;CSSValueList&gt; valueList;
+        if (is&lt;CSSValueList&gt;(value.get()))
+            valueList = downcast&lt;CSSValueList&gt;(value.get());
+
+        Ref&lt;CSSValue&gt; underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
+        bool hasUnderline = valueList &amp;&amp; valueList-&gt;hasValue(underline.ptr());
+
+        Ref&lt;CSSValue&gt; lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
+        bool hasLineThrough = valueList &amp;&amp; valueList-&gt;hasValue(lineThrough.ptr());
+
+        if (shouldStyleWithCSS) {
+            valueList = valueList ? valueList-&gt;copy() : CSSValueList::createSpaceSeparated();
+            if (shouldAddUnderline &amp;&amp; !hasUnderline)
+                valueList-&gt;append(WTF::move(underline));
+            if (shouldAddStrikeThrough &amp;&amp; !hasLineThrough)
+                valueList-&gt;append(WTF::move(lineThrough));
+            mutableStyle-&gt;setProperty(CSSPropertyTextDecoration, valueList.get());
+        } else {
+            m_applyUnderline = shouldAddUnderline &amp;&amp; !hasUnderline;
+            m_applyLineThrough = shouldAddStrikeThrough &amp;&amp; !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-&gt;removeProperty(CSSPropertyWhiteSpace);
</span><span class="lines">@@ -1423,10 +1603,27 @@
</span><span class="cx">     if (mutableStyle-&gt;getPropertyCSSValue(CSSPropertyUnicodeBidi) &amp;&amp; !style-&gt;style()-&gt;getPropertyCSSValue(CSSPropertyDirection))
</span><span class="cx">         mutableStyle-&gt;setProperty(CSSPropertyDirection, style-&gt;style()-&gt;getPropertyValue(CSSPropertyDirection));
</span><span class="cx"> 
</span><del>-    // Save the result for later
-    m_cssStyle = mutableStyle-&gt;asText().stripWhiteSpace();
</del><ins>+    if (!mutableStyle-&gt;isEmpty())
+        m_cssStyle = mutableStyle;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool StyleChange::operator==(const StyleChange&amp; 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 &amp;&amp; !other.m_cssStyle)
+        || (m_cssStyle &amp;&amp; other.m_cssStyle &amp;&amp; m_cssStyle-&gt;asText() == other.m_cssStyle-&gt;asText());
+}
+
</ins><span class="cx"> static void setTextDecorationProperty(MutableStyleProperties&amp; style, const CSSValueList* newTextDecoration, CSSPropertyID propertyID)
</span><span class="cx"> {
</span><span class="cx">     if (newTextDecoration-&gt;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 &quot;CSSPropertyNames.h&quot;
</span><span class="cx"> #include &quot;CSSValueKeywords.h&quot;
</span><ins>+#include &quot;StyleProperties.h&quot;
</ins><span class="cx"> #include &quot;WritingDirection.h&quot;
</span><span class="cx"> #include &lt;wtf/Forward.h&gt;
</span><ins>+#include &lt;wtf/HashMap.h&gt;
</ins><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><span class="cx"> #include &lt;wtf/RefPtr.h&gt;
</span><span class="cx"> #include &lt;wtf/TriState.h&gt;
</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&lt;EditingStyle&gt; {
</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&lt;EditingStyle&gt; 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&lt;MutableStyleProperties&gt;);
</span><span class="cx">     void overrideWithStyle(const StyleProperties*);
</span><ins>+    void overrideTypingStyleAt(const EditingStyle&amp;, const Position&amp;);
</ins><span class="cx">     void clear();
</span><span class="cx">     PassRefPtr&lt;EditingStyle&gt; copy() const;
</span><span class="cx">     PassRefPtr&lt;EditingStyle&gt; 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&amp;) const;
</span><span class="cx">     bool conflictsWithInlineStyleOfElement(StyledElement* element) const { return conflictsWithInlineStyleOfElement(element, 0, 0); }
</span><del>-    bool conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector&lt;CSSPropertyID&gt;&amp; conflictingProperties) const
</del><ins>+    bool conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr&lt;MutableStyleProperties&gt;&amp; newInlineStyle,
+        EditingStyle* extractedStyle) const
</ins><span class="cx">     {
</span><del>-        return conflictsWithInlineStyleOfElement(element, extractedStyle, &amp;conflictingProperties);
</del><ins>+        return conflictsWithInlineStyleOfElement(element, &amp;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&lt;unsigned&gt;(change); }
+    TextDecorationChange underlineChange() const { return static_cast&lt;TextDecorationChange&gt;(m_underlineChange); }
+    void setStrikeThroughChange(TextDecorationChange change) { m_strikeThroughChange = static_cast&lt;unsigned&gt;(change); }
+    TextDecorationChange strikeThroughChange() const { return static_cast&lt;TextDecorationChange&gt;(m_strikeThroughChange); }
</ins><span class="cx"> 
</span><span class="cx">     static PassRefPtr&lt;EditingStyle&gt; styleAtSelectionStart(const VisibleSelection&amp;, bool shouldUseBackgroundColorInEffect = false);
</span><span class="cx">     static WritingDirection textDirectionForSelection(const VisibleSelection&amp;, EditingStyle* typingStyle, bool&amp; hasNestedOrMultipleEmbeddings);
</span><span class="lines">@@ -153,37 +169,33 @@
</span><span class="cx">     EditingStyle(const Position&amp;, PropertiesToInclude);
</span><span class="cx">     explicit EditingStyle(const StyleProperties*);
</span><span class="cx">     EditingStyle(CSSPropertyID, const String&amp; 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&amp; value, bool important = false);
</span><span class="cx">     void extractFontSizeDelta();
</span><span class="cx">     template&lt;typename T&gt; TriState triStateOfStyle(T&amp; styleToCompare, ShouldIgnoreTextOnlyProperties) const;
</span><del>-    bool conflictsWithInlineStyleOfElement(StyledElement*, EditingStyle* extractedStyle, Vector&lt;CSSPropertyID&gt;* conflictingProperties) const;
</del><ins>+    bool conflictsWithInlineStyleOfElement(StyledElement*, RefPtr&lt;MutableStyleProperties&gt;* 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&lt;MutableStyleProperties&gt; 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&amp;);
</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&amp; other)
-    {
-        return m_cssStyle == other.m_cssStyle
-            &amp;&amp; m_applyBold == other.m_applyBold
-            &amp;&amp; m_applyItalic == other.m_applyItalic
-            &amp;&amp; m_applyUnderline == other.m_applyUnderline
-            &amp;&amp; m_applyLineThrough == other.m_applyLineThrough
-            &amp;&amp; m_applySubscript == other.m_applySubscript
-            &amp;&amp; m_applySuperscript == other.m_applySuperscript
-            &amp;&amp; m_applyFontColor == other.m_applyFontColor
-            &amp;&amp; m_applyFontFace == other.m_applyFontFace
-            &amp;&amp; m_applyFontSize == other.m_applyFontSize;
-    }
</del><ins>+    bool operator==(const StyleChange&amp;);
</ins><span class="cx">     bool operator!=(const StyleChange&amp; 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&amp;, 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&lt;MutableStyleProperties&gt; 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&lt;EditingStyle&gt;&amp;&amp; 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-&gt;isEmpty() || !canEditRichly())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    if (client() &amp;&amp; client()-&gt;shouldApplyStyle(style, m_frame.selection().toNormalizedRange().get()))
-        applyStyle(style, editingAction);
</del><ins>+    if (!client() || !client()-&gt;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&lt;EditingStyle&gt;&amp;&amp; style, EditAction editingAction)
+{
+    if (!style || style-&gt;isEmpty() || !canEditRichly())
+        return;
+
+    // FIXME: This is wrong for text decorations since m_mutableStyle is empty.
+    if (!client() || !client()-&gt;shouldApplyStyle(style-&gt;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-&gt;isEmpty() || !canEditRichly())
</span><span class="lines">@@ -2952,23 +2981,21 @@
</span><span class="cx">     return client() &amp;&amp; client()-&gt;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&amp; style, EditAction editingAction)
</ins><span class="cx"> {
</span><del>-    if (!style || style-&gt;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&lt;EditingStyle&gt; typingStyle;
</span><del>-    if (m_frame.selection().typingStyle()) {
-        typingStyle = m_frame.selection().typingStyle()-&gt;copy();
-        typingStyle-&gt;overrideWithStyle(style);
-    } else
-        typingStyle = EditingStyle::create(style);
</del><ins>+    if (auto existingTypingStyle = m_frame.selection().typingStyle())
+        typingStyle = existingTypingStyle-&gt;copy();
+    else
+        typingStyle = EditingStyle::create();
+    typingStyle-&gt;overrideTypingStyleAt(style, m_frame.selection().selection().visibleStart().deepEquivalent());
</ins><span class="cx"> 
</span><del>-    typingStyle-&gt;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&lt;EditingStyle&gt; blockStyle = typingStyle-&gt;extractAndRemoveBlockProperties();
</span><span class="cx">     if (!blockStyle-&gt;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&amp; properties, EditAction editingAction)
+{
+    return computeAndSetTypingStyle(EditingStyle::create(&amp;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&amp;, DataTransferAccessPolicy);
</span><span class="cx">     
</span><span class="cx">     WEBCORE_EXPORT void applyStyle(StyleProperties*, EditAction = EditActionUnspecified);
</span><ins>+    void applyStyle(RefPtr&lt;EditingStyle&gt;&amp;&amp;, 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&lt;EditingStyle&gt;&amp;&amp;, EditAction);
</ins><span class="cx">     void applyParagraphStyleToSelection(StyleProperties*, EditAction);
</span><span class="cx"> 
</span><span class="cx">     void appliedEditing(PassRefPtr&lt;CompositeEditCommand&gt;);
</span><span class="lines">@@ -361,7 +363,8 @@
</span><span class="cx">     const VisibleSelection&amp; mark() const; // Mark, to be used as emacs uses it.
</span><span class="cx">     void setMark(const VisibleSelection&amp;);
</span><span class="cx"> 
</span><del>-    WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties* , EditAction = EditActionUnspecified);
</del><ins>+    void computeAndSetTypingStyle(EditingStyle&amp; , EditAction = EditActionUnspecified);
+    WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties&amp; , 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-&gt;document().frame();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static bool applyCommandToFrame(Frame&amp; frame, EditorCommandSource source, EditAction action, StyleProperties* style)
</del><ins>+static bool applyCommandToFrame(Frame&amp; frame, EditorCommandSource source, EditAction action, RefPtr&lt;EditingStyle&gt;&amp;&amp; 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&amp; frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String&amp; propertyValue)
</del><ins>+static bool isStylePresent(Editor&amp; editor, CSSPropertyID propertyID, const char* onValue)
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;MutableStyleProperties&gt; style = MutableStyleProperties::create();
-    style-&gt;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&amp; frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
</del><ins>+static bool executeApplyStyle(Frame&amp; frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String&amp; propertyValue)
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;MutableStyleProperties&gt; style = MutableStyleProperties::create();
-    style-&gt;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 &lt;b&gt;&lt;u&gt;hello&lt;/u&gt;world&lt;/b&gt; 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&amp; frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValue* value)
</del><ins>+static bool executeApplyStyle(Frame&amp; frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;EditingStyle&gt; selectionStyle = EditingStyle::styleAtSelectionStart(frame.selection().selection());
-    if (!selectionStyle || !selectionStyle-&gt;style())
-        return false;
-
-    RefPtr&lt;CSSValue&gt; selectedCSSValue = selectionStyle-&gt;style()-&gt;getPropertyCSSValue(propertyID);
-    String newStyle = ASCIILiteral(&quot;none&quot;);
-    if (is&lt;CSSValueList&gt;(*selectedCSSValue)) {
-        RefPtr&lt;CSSValueList&gt; selectedCSSValueList = downcast&lt;CSSValueList&gt;(selectedCSSValue.get());
-        if (!selectedCSSValueList-&gt;removeAll(value))
-            selectedCSSValueList-&gt;append(*value);
-        if (selectedCSSValueList-&gt;length())
-            newStyle = selectedCSSValueList-&gt;cssText();
-
-    } else if (selectedCSSValue-&gt;cssText() == &quot;none&quot;)
-        newStyle = value-&gt;cssText();
-
-    // FIXME: We shouldn't be having to convert new style into text.  We should have setPropertyCSSValue.
-    RefPtr&lt;MutableStyleProperties&gt; newMutableStyle = MutableStyleProperties::create();
-    newMutableStyle-&gt;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&amp; 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&lt;EditingStyle&gt; style = EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue);
-    return applyCommandToFrame(frame, source, action, style-&gt;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&amp; frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String&amp; 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&amp; editor, CSSPropertyID propertyID, const char* onValue)
+{
+    return isStylePresent(editor, propertyID, onValue) ? TextDecorationChange::Remove : TextDecorationChange::Add;
+}
+
</ins><span class="cx"> static bool executeStrikethrough(Frame&amp; frame, Event*, EditorCommandSource source, const String&amp;)
</span><span class="cx"> {
</span><del>-    RefPtr&lt;CSSPrimitiveValue&gt; lineThrough = CSSPrimitiveValue::createIdentifier(CSSValueLineThrough);
-    return executeToggleStyleInList(frame, source, EditActionUnderline, CSSPropertyWebkitTextDecorationsInEffect, lineThrough.get());
</del><ins>+    RefPtr&lt;EditingStyle&gt; style = EditingStyle::create();
+    style-&gt;setStrikeThroughChange(textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, &quot;line-through&quot;));
+    // 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&amp; frame, Event*, EditorCommandSource, const String&amp; value)
</span><span class="lines">@@ -1125,8 +1101,10 @@
</span><span class="cx"> 
</span><span class="cx"> static bool executeUnderline(Frame&amp; frame, Event*, EditorCommandSource source, const String&amp;)
</span><span class="cx"> {
</span><del>-    RefPtr&lt;CSSPrimitiveValue&gt; underline = CSSPrimitiveValue::createIdentifier(CSSValueUnderline);
-    return executeToggleStyleInList(frame, source, EditActionUnderline, CSSPropertyWebkitTextDecorationsInEffect, underline.get());
</del><ins>+    RefPtr&lt;EditingStyle&gt; style = EditingStyle::create();
+    TextDecorationChange change = textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, &quot;underline&quot;);
+    style-&gt;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&amp; frame, Event*, EditorCommandSource, const String&amp;)
</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  &lt;rniwa@webkit.org&gt;
+
+        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  &lt;mrobinson@igalia.com&gt;
</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&lt;MutableStyleProperties&gt; properties(core(style)-&gt;copyProperties());
</span><del>-    _private-&gt;coreFrame-&gt;editor().computeAndSetTypingStyle(properties.ptr(), undoAction);
</del><ins>+    _private-&gt;coreFrame-&gt;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>