Changeset 183770 in webkit


Ignore:
Timestamp:
May 4, 2015 1:42:41 PM (9 years ago)
Author:
rniwa@webkit.org
Message:

Toggling underline or strike through affects each other
https://bugs.webkit.org/show_bug.cgi?id=27818

Reviewed by Darin Adler.

Source/WebCore:

This patch introduces a new mechanism to apply and remove text decorations. This is necessary because text
decorations are always additive and we can't differentiate whether we're adding or removing a text decoration.
Conceptually, we need four values for text decorations: adding underline, removing underline, adding
line-through, and removing line-through but we have only three: underline, line-through, none.

After this patch, there are three mechanism by which text decorations states are kept tracked. While applying
or removing text decorations, we use newly added m_underlineChange and m_strikeThroughChange in EditingStyle.
For the typing style, we use -webkit-text-decorations-in-effect to store the state since we need to preserve
every type of text decorations such as overline in addition to underline and line-through. Once applied, all
text decorations should be expressed in terms of the standard text-decoration property.

Test: editing/execCommand/toggle-mixed-text-decorations.html

  • editing/ApplyStyleCommand.cpp:

(WebCore::ApplyStyleCommand::applyBlockStyle):
(WebCore::ApplyStyleCommand::removeCSSStyle): conflictsWithInlineStyleOfElement now creates a new inline style
instead of a list of properties to remove.
(WebCore::ApplyStyleCommand::addBlockStyle):
(WebCore::ApplyStyleCommand::applyInlineStyleChange): Merge inline styles instead of adding as string.
Otherwise it would generate style content attribute with multiple text-decoration properties.

  • editing/EditingStyle.cpp:

(WebCore::HTMLElementEquivalent::matches):
(WebCore::HTMLElementEquivalent::propertyExistsInStyle): Takes an EditingStyle instead of StyleProperties.
(WebCore::HTMLElementEquivalent::valueIsPresentInStyle):
(WebCore::HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent):
(WebCore::HTMLTextDecorationEquivalent::propertyExistsInStyle): Respect newly added m_strikeThroughChange and
m_underlineChange in EditingStyle.
(WebCore::HTMLTextDecorationEquivalent::valueIsPresentInStyle): Ditto.
(WebCore::HTMLTextDecorationEquivalent::changeInStyle): Added. Retrieves the change enum for the associated
type of text-decoration (underline or strike through).
(WebCore::HTMLAttributeEquivalent::matches):
(WebCore::HTMLAttributeEquivalent::valueIsPresentInStyle):
(WebCore::EditingStyle::EditingStyle): Initialize m_underlineChange and m_strikeThroughChange. Also use the
delegating constructor elsewhere. Also added the missing call to extractFontSizeDelta() in the variant that
takes CSSPropertyID and String, and added a variant that takes CSSPropertyID and CSSValueID.
(WebCore::EditingStyle::isEmpty): Return false when m_underlineChange and m_strikeThroughChange are not "none".
(WebCore::applyTextDecorationChangeToValueList): Added.
(WebCore::EditingStyle::overrideTypingStyleAt): Added. Used by Editor::computeAndSetTypingStyle to set a new
typing style. Resolve m_underlineChange and m_strikeThroughChange into -webkit-text-decorations-in-effect.
(WebCore::EditingStyle::clear): Clear m_underlineChange and m_strikeThroughChange.
(WebCore::EditingStyle::copy): Copy m_underlineChange and m_strikeThroughChange.
(WebCore::textDecorationValueList): Added.
(WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Now takes a pointer to MutableStyleProperties
instead of a vector. This was necessary we can't simply remove text-decoration property in ApplyStyleCommand's
removeCSSStyle as that would result in unrelated text decorations also getting removed. Also added the code
for m_underlineChange and m_strikeThroughChange. Only removing text decoration changes can cause a conflict
since text decorations are always additive.
(WebCore::EditingStyle::conflictsWithImplicitStyleOfElement): Check isEmpty() instead of the nullity of
m_mutableStyle to respect m_underlineChange and m_strikeThroughChange.
(WebCore::EditingStyle::conflictsWithImplicitStyleOfAttributes):
(WebCore::EditingStyle::extractConflictingImplicitStyleOfAttributes):
(WebCore::EditingStyle::styleIsPresentInComputedStyleOfNode): Respect the values of m_underlineChange and
m_strikeThroughChange. Here, the style is considered present if it has text decorations that are being added.
(WebCore::EditingStyle::elementIsStyledSpanOrHTMLEquivalent):
(WebCore::elementMatchesAndPropertyIsNotInInlineStyleDecl): Takes EditingStyle instead of StyleProperties to
respect m_underlineChange and m_strikeThroughChange.
(WebCore::EditingStyle::mergeInlineAndImplicitStyleOfElement):
(WebCore::mergeTextDecorationValues):
(WebCore::EditingStyle::mergeStyle): Make a copy of CSSValueList before modifying it since CSSValueList's are
shared with other immutable StyleProperties.
(WebCore::StyleChange::StyleChange): Set m_applyUnderline, m_applyLineThrough, and m_cssStyle if either
m_underlineChange or m_strikeThroughChange are TextDecorationChange::Add in EditingStyle if the current position
doesn't already have the matching style.
(WebCore::StyleChange::operator==): Moved from the header file. Also added the logic to compare m_cssStyle now
that it's a StyleProperties instead of String.

  • editing/EditingStyle.h: Added TextDecorationChange.

(WebCore::EditingStyle::create): Added a variant that takes CSSPropertyID and CSSValueID.
(WebCore::EditingStyle::conflictsWithInlineStyleOfElement):
(WebCore::EditingStyle::setUnderlineChange): Added.
(WebCore::EditingStyle::underlineChange): Added.
(WebCore::EditingStyle::setStrikeThroughChange): Added.
(WebCore::EditingStyle::strikeThroughChange): Added.
(WebCore::StyleChange::cssStyle): Now returns StyleProperties* instead of String so that ApplyStyleCommand's
applyInlineStyleChange could merge inline styles instead of just appending it to the end.
(WebCore::StyleChange::operator==): Moved into the cpp file.

  • editing/Editor.cpp:

(WebCore::Editor::applyStyle): Added. This variant takes EditingStyle instead of StyleProperties.
(WebCore::Editor::applyStyleToSelection): Ditto.
(WebCore::Editor::computeAndSetTypingStyle): Added a variant for EditingStyle. Also use overrideTypingStyleAt
to set -webkit-text-decorations-in-effect based on m_underlineChange and m_strikeThroughChange

  • editing/Editor.h:
  • editing/EditorCommand.cpp:

(WebCore::applyCommandToFrame):
(WebCore::isStylePresent): Extracted from executeToggleStyle.
(WebCore::executeApplyStyle):
(WebCore::executeToggleStyle):
(WebCore::executeToggleStyleInList): Deleted.
(WebCore::textDecorationChangeForToggling): Added. Used in executeStrikethrough and executeUnderline.
(WebCore::executeStrikethrough):
(WebCore::executeUnderline):

Source/WebKit/mac:

  • WebView/WebFrame.mm:

(-[WebFrame _setTypingStyle:withUndoAction:]):

LayoutTests:

Added a regression test and rebaselined various tests as explained below.

  • editing/execCommand/script-tests/toggle-style-2.js: The order in which u and strike elements appear have switched.
  • editing/execCommand/script-tests/toggle-text-decorations.js: Ditto for line-through and overline.
  • editing/execCommand/toggle-mixed-text-decorations-expected.txt: Added.
  • editing/execCommand/toggle-mixed-text-decorations.html: Added.
  • editing/execCommand/toggle-style-2-expected.txt: Rebaselined.
  • editing/execCommand/toggle-text-decorations-expected.txt: Rebaselined.
  • editing/undo/remove-css-property-and-remove-style-expected.txt: The order in which color and font-weight properties

appear have switched.

Location:
trunk
Files:
2 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r183765 r183770  
     12015-05-04  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Toggling underline or strike through affects each other
     4        https://bugs.webkit.org/show_bug.cgi?id=27818
     5
     6        Reviewed by Darin Adler.
     7
     8        Added a regression test and rebaselined various tests as explained below.
     9
     10        * editing/execCommand/script-tests/toggle-style-2.js: The order in which u and strike elements appear have switched.
     11        * editing/execCommand/script-tests/toggle-text-decorations.js: Ditto for line-through and overline.
     12        * editing/execCommand/toggle-mixed-text-decorations-expected.txt: Added.
     13        * editing/execCommand/toggle-mixed-text-decorations.html: Added.
     14        * editing/execCommand/toggle-style-2-expected.txt: Rebaselined.
     15        * editing/execCommand/toggle-text-decorations-expected.txt: Rebaselined.
     16        * editing/undo/remove-css-property-and-remove-style-expected.txt: The order in which color and font-weight properties
     17        appear have switched.
     18
    1192015-05-04  Chris Dumez  <cdumez@apple.com>
    220
  • trunk/LayoutTests/editing/execCommand/script-tests/toggle-style-2.js

    r120173 r183770  
    3838
    3939testSingleToggle("strikethrough", "<u>test</u>", "<u><strike>test</strike></u>");
    40 testSingleToggle("underline", "<strike>test</strike>", "<u><strike>test</strike></u>");
     40testSingleToggle("underline", "<strike>test</strike>", "<strike><u>test</u></strike>");
    4141
    4242testSingleToggle("strikethrough", '<span style="text-decoration: overline;">test</span>', '<span style="text-decoration: overline;"><strike>test</strike></span>');
  • trunk/LayoutTests/editing/execCommand/script-tests/toggle-text-decorations.js

    r93001 r183770  
    2020testSingleToggle("underline", "test", "<span style=\"text-decoration: underline;\">test</span>");
    2121testSingleToggle("underline", "<span style=\"text-decoration: underline;\">test</span>", "test");
    22 testSingleToggle("underline", "<span style=\"text-decoration: underline line-through overline;\">test</span>", "<span style=\"text-decoration: overline line-through;\">test</span>");
     22testSingleToggle("underline", "<span style=\"text-decoration: underline line-through overline;\">test</span>",
     23    "<span style=\"text-decoration: line-through overline;\">test</span>");
    2324testSingleToggle("strikethrough", "test", "<span style=\"text-decoration: line-through;\">test</span>");
    2425testSingleToggle("strikethrough", "<span style=\"text-decoration: line-through;\">test</span>", "test");
  • trunk/LayoutTests/editing/execCommand/toggle-style-2-expected.txt

    r93001 r183770  
    1111PASS two strikethrough commands converted test to test
    1212PASS one strikethrough command converted <u>test</u> to <u><strike>test</strike></u>
    13 PASS one underline command converted <strike>test</strike> to <u><strike>test</strike></u>
     13PASS one underline command converted <strike>test</strike> to <strike><u>test</u></strike>
    1414PASS one strikethrough command converted <span style="text-decoration: overline;">test</span> to <span style="text-decoration: overline;"><strike>test</strike></span>
    1515PASS one underline command converted <span style="text-decoration: overline;">test</span> to <span style="text-decoration: overline;"><u>test</u></span>
  • trunk/LayoutTests/editing/execCommand/toggle-text-decorations-expected.txt

    r93001 r183770  
    66PASS one underline command converted test to <span style="text-decoration: underline;">test</span>
    77PASS one underline command converted <span style="text-decoration: underline;">test</span> to test
    8 PASS one underline command converted <span style="text-decoration: underline line-through overline;">test</span> to <span style="text-decoration: overline line-through;">test</span>
     8PASS one underline command converted <span style="text-decoration: underline line-through overline;">test</span> to <span style="text-decoration: line-through overline;">test</span>
    99PASS one strikethrough command converted test to <span style="text-decoration: line-through;">test</span>
    1010PASS one strikethrough command converted <span style="text-decoration: line-through;">test</span> to test
  • trunk/LayoutTests/editing/undo/remove-css-property-and-remove-style-expected.txt

    r126656 r183770  
    6060Undo should reset the style attribute so that "test" is both bold and blue:
    6161| <span>
    62 |   style="color: blue; font-weight: 900;"
     62|   style="font-weight: 900; color: blue;"
    6363|   "<#selection-anchor>test<#selection-focus>"
    6464
  • trunk/Source/WebCore/ChangeLog

    r183767 r183770  
     12015-05-04  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Toggling underline or strike through affects each other
     4        https://bugs.webkit.org/show_bug.cgi?id=27818
     5
     6        Reviewed by Darin Adler.
     7
     8        This patch introduces a new mechanism to apply and remove text decorations. This is necessary because text
     9        decorations are always additive and we can't differentiate whether we're adding or removing a text decoration.
     10        Conceptually, we need four values for text decorations: adding underline, removing underline, adding
     11        line-through, and removing line-through but we have only three: underline, line-through, none.
     12
     13        After this patch, there are three mechanism by which text decorations states are kept tracked. While applying
     14        or removing text decorations, we use newly added m_underlineChange and m_strikeThroughChange in EditingStyle.
     15        For the typing style, we use -webkit-text-decorations-in-effect to store the state since we need to preserve
     16        every type of text decorations such as overline in addition to underline and line-through. Once applied, all
     17        text decorations should be expressed in terms of the standard text-decoration property.
     18
     19        Test: editing/execCommand/toggle-mixed-text-decorations.html
     20
     21        * editing/ApplyStyleCommand.cpp:
     22        (WebCore::ApplyStyleCommand::applyBlockStyle):
     23        (WebCore::ApplyStyleCommand::removeCSSStyle): conflictsWithInlineStyleOfElement now creates a new inline style
     24        instead of a list of properties to remove.
     25        (WebCore::ApplyStyleCommand::addBlockStyle):
     26        (WebCore::ApplyStyleCommand::applyInlineStyleChange): Merge inline styles instead of adding as string.
     27        Otherwise it would generate style content attribute with multiple text-decoration properties.
     28
     29        * editing/EditingStyle.cpp:
     30        (WebCore::HTMLElementEquivalent::matches):
     31        (WebCore::HTMLElementEquivalent::propertyExistsInStyle): Takes an EditingStyle instead of StyleProperties.
     32        (WebCore::HTMLElementEquivalent::valueIsPresentInStyle):
     33        (WebCore::HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent):
     34        (WebCore::HTMLTextDecorationEquivalent::propertyExistsInStyle): Respect newly added m_strikeThroughChange and
     35        m_underlineChange in EditingStyle.
     36        (WebCore::HTMLTextDecorationEquivalent::valueIsPresentInStyle): Ditto.
     37        (WebCore::HTMLTextDecorationEquivalent::changeInStyle): Added. Retrieves the change enum for the associated
     38        type of text-decoration (underline or strike through).
     39        (WebCore::HTMLAttributeEquivalent::matches):
     40        (WebCore::HTMLAttributeEquivalent::valueIsPresentInStyle):
     41        (WebCore::EditingStyle::EditingStyle): Initialize m_underlineChange and m_strikeThroughChange. Also use the
     42        delegating constructor elsewhere. Also added the missing call to extractFontSizeDelta() in the variant that
     43        takes CSSPropertyID and String, and added a variant that takes CSSPropertyID and CSSValueID.
     44        (WebCore::EditingStyle::isEmpty): Return false when m_underlineChange and m_strikeThroughChange are not "none".
     45        (WebCore::applyTextDecorationChangeToValueList): Added.
     46        (WebCore::EditingStyle::overrideTypingStyleAt): Added. Used by Editor::computeAndSetTypingStyle to set a new
     47        typing style. Resolve m_underlineChange and m_strikeThroughChange into -webkit-text-decorations-in-effect.
     48        (WebCore::EditingStyle::clear): Clear m_underlineChange and m_strikeThroughChange.
     49        (WebCore::EditingStyle::copy): Copy m_underlineChange and m_strikeThroughChange.
     50        (WebCore::textDecorationValueList): Added.
     51        (WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Now takes a pointer to MutableStyleProperties
     52        instead of a vector. This was necessary we can't simply remove text-decoration property in ApplyStyleCommand's
     53        removeCSSStyle as that would result in unrelated text decorations also getting removed. Also added the code
     54        for m_underlineChange and m_strikeThroughChange. Only removing text decoration changes can cause a conflict
     55        since text decorations are always additive.
     56        (WebCore::EditingStyle::conflictsWithImplicitStyleOfElement): Check isEmpty() instead of the nullity of
     57        m_mutableStyle to respect m_underlineChange and m_strikeThroughChange.
     58        (WebCore::EditingStyle::conflictsWithImplicitStyleOfAttributes):
     59        (WebCore::EditingStyle::extractConflictingImplicitStyleOfAttributes):
     60        (WebCore::EditingStyle::styleIsPresentInComputedStyleOfNode): Respect the values of m_underlineChange and
     61        m_strikeThroughChange. Here, the style is considered present if it has text decorations that are being added.
     62        (WebCore::EditingStyle::elementIsStyledSpanOrHTMLEquivalent):
     63        (WebCore::elementMatchesAndPropertyIsNotInInlineStyleDecl): Takes EditingStyle instead of StyleProperties to
     64        respect m_underlineChange and m_strikeThroughChange.
     65        (WebCore::EditingStyle::mergeInlineAndImplicitStyleOfElement):
     66        (WebCore::mergeTextDecorationValues):
     67        (WebCore::EditingStyle::mergeStyle): Make a copy of CSSValueList before modifying it since CSSValueList's are
     68        shared with other immutable StyleProperties.
     69        (WebCore::StyleChange::StyleChange): Set m_applyUnderline, m_applyLineThrough, and m_cssStyle if either
     70        m_underlineChange or m_strikeThroughChange are TextDecorationChange::Add in EditingStyle if the current position
     71        doesn't already have the matching style.
     72        (WebCore::StyleChange::operator==): Moved from the header file. Also added the logic to compare m_cssStyle now
     73        that it's a StyleProperties instead of String.
     74
     75        * editing/EditingStyle.h: Added TextDecorationChange.
     76        (WebCore::EditingStyle::create): Added a variant that takes CSSPropertyID and CSSValueID.
     77        (WebCore::EditingStyle::conflictsWithInlineStyleOfElement):
     78        (WebCore::EditingStyle::setUnderlineChange): Added.
     79        (WebCore::EditingStyle::underlineChange): Added.
     80        (WebCore::EditingStyle::setStrikeThroughChange): Added.
     81        (WebCore::EditingStyle::strikeThroughChange): Added.
     82        (WebCore::StyleChange::cssStyle): Now returns StyleProperties* instead of String so that ApplyStyleCommand's
     83        applyInlineStyleChange could merge inline styles instead of just appending it to the end.
     84        (WebCore::StyleChange::operator==): Moved into the cpp file.
     85
     86        * editing/Editor.cpp:
     87        (WebCore::Editor::applyStyle): Added. This variant takes EditingStyle instead of StyleProperties.
     88        (WebCore::Editor::applyStyleToSelection): Ditto.
     89        (WebCore::Editor::computeAndSetTypingStyle): Added a variant for EditingStyle. Also use overrideTypingStyleAt
     90        to set -webkit-text-decorations-in-effect based on m_underlineChange and m_strikeThroughChange
     91
     92        * editing/Editor.h:
     93        * editing/EditorCommand.cpp:
     94        (WebCore::applyCommandToFrame):
     95        (WebCore::isStylePresent): Extracted from executeToggleStyle.
     96        (WebCore::executeApplyStyle):
     97        (WebCore::executeToggleStyle):
     98        (WebCore::executeToggleStyleInList): Deleted.
     99        (WebCore::textDecorationChangeForToggling): Added. Used in executeStrikethrough and executeUnderline.
     100        (WebCore::executeStrikethrough):
     101        (WebCore::executeUnderline):
     102
    11032015-05-04  Eric Carlson  <eric.carlson@apple.com>
    2104
  • trunk/Source/WebCore/editing/ApplyStyleCommand.cpp

    r183368 r183770  
    264264    while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) {
    265265        StyleChange styleChange(style, paragraphStart.deepEquivalent());
    266         if (styleChange.cssStyle().length() || m_removeOnly) {
     266        if (styleChange.cssStyle() || m_removeOnly) {
    267267            RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().deprecatedNode());
    268268            if (!m_removeOnly) {
     
    946946        return style->conflictsWithInlineStyleOfElement(element);
    947947
    948     Vector<CSSPropertyID> properties;
    949     if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle, properties))
     948    RefPtr<MutableStyleProperties> newInlineStyle;
     949    if (!style->conflictsWithInlineStyleOfElement(element, newInlineStyle, extractedStyle))
    950950        return false;
    951951
    952     // FIXME: We should use a mass-removal function here but we don't have an undoable one yet.
    953     for (size_t i = 0; i < properties.size(); i++)
    954         removeCSSProperty(element, properties[i]);
    955 
    956     // No need to serialize <foo style=""> if we just removed the last css property
    957     if (element->inlineStyle()->isEmpty())
     952    if (newInlineStyle->isEmpty())
    958953        removeNodeAttribute(element, styleAttr);
     954    else
     955        setNodeAttribute(element, styleAttr, newInlineStyle->asText());
    959956
    960957    if (isSpanWithoutAttributesOrUnstyledStyleSpan(element))
     
    13711368void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElement* block)
    13721369{
     1370    ASSERT(styleChange.cssStyle());
    13731371    // Do not check for legacy styles here. Those styles, like <B> and <I>, only apply for
    13741372    // inline content.
     
    13761374        return;
    13771375       
    1378     String cssStyle = styleChange.cssStyle();
     1376    String cssStyle = styleChange.cssStyle()->asText();
    13791377    StringBuilder cssText;
    13801378    cssText.append(cssStyle);
     
    14571455    }
    14581456
    1459     if (styleChange.cssStyle().length()) {
     1457    if (auto styleToMerge = styleChange.cssStyle()) {
    14601458        if (styleContainer) {
    1461             if (const StyleProperties* existingStyle = styleContainer->inlineStyle()) {
    1462                 String existingText = existingStyle->asText();
    1463                 StringBuilder cssText;
    1464                 cssText.append(existingText);
    1465                 if (!existingText.isEmpty())
    1466                     cssText.append(' ');
    1467                 cssText.append(styleChange.cssStyle());
    1468                 setNodeAttribute(styleContainer, styleAttr, cssText.toString());
     1459            if (auto existingStyle = styleContainer->inlineStyle()) {
     1460                auto inlineStyle = EditingStyle::create(existingStyle);
     1461                inlineStyle->overrideWithStyle(styleToMerge);
     1462                setNodeAttribute(styleContainer, styleAttr, inlineStyle->style()->asText());
    14691463            } else
    1470                 setNodeAttribute(styleContainer, styleAttr, styleChange.cssStyle());
     1464                setNodeAttribute(styleContainer, styleAttr, styleToMerge->asText());
    14711465        } else {
    14721466            RefPtr<Element> styleElement = createStyleSpanElement(document());
    1473             styleElement->setAttribute(styleAttr, styleChange.cssStyle());
     1467            styleElement->setAttribute(styleAttr, styleToMerge->asText());
    14741468            surroundNodeRangeWithElement(startNode, endNode, styleElement.release());
    14751469        }
  • trunk/Source/WebCore/editing/EditingStyle.cpp

    r179143 r183770  
    161161
    162162    virtual ~HTMLElementEquivalent() { }
    163     virtual bool matches(const Element* element) const { return !m_tagName || element->hasTagName(*m_tagName); }
     163    virtual bool matches(const Element& element) const { return !m_tagName || element.hasTagName(*m_tagName); }
    164164    virtual bool hasAttribute() const { return false; }
    165     virtual bool propertyExistsInStyle(const StyleProperties* style) const { return style->getPropertyCSSValue(m_propertyID); }
    166     virtual bool valueIsPresentInStyle(Element*, StyleProperties*) const;
     165    virtual bool propertyExistsInStyle(const EditingStyle& style) const { return style.m_mutableStyle && style.m_mutableStyle->getPropertyCSSValue(m_propertyID); }
     166    virtual bool valueIsPresentInStyle(Element&, const EditingStyle&) const;
    167167    virtual void addToStyle(Element*, EditingStyle*) const;
    168168
     
    195195}
    196196
    197 bool HTMLElementEquivalent::valueIsPresentInStyle(Element* element, StyleProperties* style) const
    198 {
    199     RefPtr<CSSValue> value = style->getPropertyCSSValue(m_propertyID);
     197bool HTMLElementEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const
     198{
     199    RefPtr<CSSValue> value = style.m_mutableStyle->getPropertyCSSValue(m_propertyID);
    200200    return matches(element) && is<CSSPrimitiveValue>(value.get()) && downcast<CSSPrimitiveValue>(*value).getValueID() == m_primitiveValue->getValueID();
    201201}
     
    208208class HTMLTextDecorationEquivalent : public HTMLElementEquivalent {
    209209public:
    210     HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName);
    211 
    212     virtual bool propertyExistsInStyle(const StyleProperties*) const;
    213     virtual bool valueIsPresentInStyle(Element*, StyleProperties*) const;
     210    HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName)
     211        : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)
     212        , m_isUnderline(primitiveValue == CSSValueUnderline)
     213    {
     214    }
     215
     216    bool propertyExistsInStyle(const EditingStyle& style) const override
     217    {
     218        if (changeInStyle(style) != TextDecorationChange::None)
     219            return true;
     220
     221        if (!style.m_mutableStyle)
     222            return false;
     223
     224        auto& mutableStyle = *style.m_mutableStyle;
     225        return mutableStyle.getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect)
     226            || mutableStyle.getPropertyCSSValue(CSSPropertyTextDecoration);
     227    }
     228
     229    bool valueIsPresentInStyle(Element& element, const EditingStyle& style) const override
     230    {
     231        if (!matches(element))
     232            return false;
     233        auto change = changeInStyle(style);
     234        if (change != TextDecorationChange::None)
     235            return change == TextDecorationChange::Add;
     236        RefPtr<CSSValue> styleValue = style.m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
     237        if (!styleValue)
     238            styleValue = style.m_mutableStyle->getPropertyCSSValue(CSSPropertyTextDecoration);
     239        return is<CSSValueList>(styleValue.get()) && downcast<CSSValueList>(*styleValue).hasValue(m_primitiveValue.get());
     240    }
     241
     242private:
     243    TextDecorationChange changeInStyle(const EditingStyle& style) const
     244    {
     245        return m_isUnderline ? style.underlineChange() : style.strikeThroughChange();
     246    }
     247
     248    bool m_isUnderline;
    214249};
    215 
    216 HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName)
    217     : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)
    218     // m_propertyID is used in HTMLElementEquivalent::addToStyle
    219 {
    220 }
    221 
    222 bool HTMLTextDecorationEquivalent::propertyExistsInStyle(const StyleProperties* style) const
    223 {
    224     return style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) || style->getPropertyCSSValue(CSSPropertyTextDecoration);
    225 }
    226 
    227 bool HTMLTextDecorationEquivalent::valueIsPresentInStyle(Element* element, StyleProperties* style) const
    228 {
    229     RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
    230     if (!styleValue)
    231         styleValue = style->getPropertyCSSValue(CSSPropertyTextDecoration);
    232     return matches(element) && is<CSSValueList>(styleValue.get()) && downcast<CSSValueList>(*styleValue).hasValue(m_primitiveValue.get());
    233 }
    234250
    235251class HTMLAttributeEquivalent : public HTMLElementEquivalent {
     
    238254    HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName);
    239255
    240     bool matches(const Element* elem) const { return HTMLElementEquivalent::matches(elem) && elem->hasAttribute(m_attrName); }
     256    bool matches(const Element& element) const { return HTMLElementEquivalent::matches(element) && element.hasAttribute(m_attrName); }
    241257    virtual bool hasAttribute() const { return true; }
    242     virtual bool valueIsPresentInStyle(Element*, StyleProperties*) const;
     258    virtual bool valueIsPresentInStyle(Element&, const EditingStyle&) const;
    243259    virtual void addToStyle(Element*, EditingStyle*) const;
    244260    virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
     
    261277}
    262278
    263 bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element* element, StyleProperties* style) const
    264 {
    265     RefPtr<CSSValue> value = attributeValueAsCSSValue(element);
    266     RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(m_propertyID);
     279bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const
     280{
     281    RefPtr<CSSValue> value = attributeValueAsCSSValue(&element);
     282    RefPtr<CSSValue> styleValue = style.m_mutableStyle->getPropertyCSSValue(m_propertyID);
    267283   
    268284    return compareCSSValuePtr(value, styleValue);
     
    316332EditingStyle::EditingStyle()
    317333    : m_shouldUseFixedDefaultFontSize(false)
    318     , m_fontSizeDelta(NoFontDelta)
     334    , m_underlineChange(static_cast<unsigned>(TextDecorationChange::None))
     335    , m_strikeThroughChange(static_cast<unsigned>(TextDecorationChange::None))
    319336{
    320337}
    321338
    322339EditingStyle::EditingStyle(Node* node, PropertiesToInclude propertiesToInclude)
    323     : m_shouldUseFixedDefaultFontSize(false)
    324     , m_fontSizeDelta(NoFontDelta)
     340    : EditingStyle()
    325341{
    326342    init(node, propertiesToInclude);
     
    328344
    329345EditingStyle::EditingStyle(const Position& position, PropertiesToInclude propertiesToInclude)
    330     : m_shouldUseFixedDefaultFontSize(false)
    331     , m_fontSizeDelta(NoFontDelta)
     346    : EditingStyle()
    332347{
    333348    init(position.deprecatedNode(), propertiesToInclude);
     
    335350
    336351EditingStyle::EditingStyle(const StyleProperties* style)
    337     : m_shouldUseFixedDefaultFontSize(false)
    338     , m_fontSizeDelta(NoFontDelta)
     352    : EditingStyle()
    339353{
    340354    if (style)
     
    344358
    345359EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value)
    346     : m_mutableStyle(0)
    347     , m_shouldUseFixedDefaultFontSize(false)
    348     , m_fontSizeDelta(NoFontDelta)
     360    : EditingStyle()
    349361{
    350362    setProperty(propertyID, value);
     363    extractFontSizeDelta();
     364}
     365
     366EditingStyle::EditingStyle(CSSPropertyID propertyID, CSSValueID value)
     367    : EditingStyle()
     368{
     369    m_mutableStyle = MutableStyleProperties::create();
     370    m_mutableStyle->setProperty(propertyID, value);
     371    extractFontSizeDelta();
    351372}
    352373
     
    493514bool EditingStyle::isEmpty() const
    494515{
    495     return (!m_mutableStyle || m_mutableStyle->isEmpty()) && m_fontSizeDelta == NoFontDelta;
     516    return (!m_mutableStyle || m_mutableStyle->isEmpty()) && m_fontSizeDelta == NoFontDelta
     517        && underlineChange() == TextDecorationChange::None && strikeThroughChange() == TextDecorationChange::None;
    496518}
    497519
     
    538560}
    539561
     562static void applyTextDecorationChangeToValueList(CSSValueList& valueList, TextDecorationChange change, Ref<CSSPrimitiveValue>&& value)
     563{
     564    switch (change) {
     565    case TextDecorationChange::None:
     566        break;
     567    case TextDecorationChange::Add:
     568        valueList.append(WTF::move(value));
     569        break;
     570    case TextDecorationChange::Remove:
     571        valueList.removeAll(&value.get());
     572        break;
     573    }
     574}
     575
     576void EditingStyle::overrideTypingStyleAt(const EditingStyle& style, const Position& position)
     577{
     578    mergeStyle(style.m_mutableStyle.get(), OverrideValues);
     579
     580    m_fontSizeDelta += style.m_fontSizeDelta;
     581
     582    prepareToApplyAt(position, EditingStyle::PreserveWritingDirection);
     583
     584    auto underlineChange = style.underlineChange();
     585    auto strikeThroughChange = style.strikeThroughChange();
     586    if (underlineChange == TextDecorationChange::None && strikeThroughChange == TextDecorationChange::None)
     587        return;
     588
     589    if (!m_mutableStyle)
     590        m_mutableStyle = MutableStyleProperties::create();
     591
     592    Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
     593    Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
     594    RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
     595    RefPtr<CSSValueList> valueList;
     596    if (value && value->isValueList()) {
     597        valueList = downcast<CSSValueList>(*value).copy();
     598        applyTextDecorationChangeToValueList(*valueList, underlineChange, WTF::move(underline));
     599        applyTextDecorationChangeToValueList(*valueList, strikeThroughChange, WTF::move(lineThrough));
     600    } else {
     601        valueList = CSSValueList::createSpaceSeparated();
     602        if (underlineChange == TextDecorationChange::Add)
     603            valueList->append(WTF::move(underline));
     604        if (strikeThroughChange == TextDecorationChange::Add)
     605            valueList->append(WTF::move(lineThrough));
     606    }
     607    m_mutableStyle->setProperty(CSSPropertyWebkitTextDecorationsInEffect, valueList.get());
     608}
     609
    540610void EditingStyle::clear()
    541611{
     
    543613    m_shouldUseFixedDefaultFontSize = false;
    544614    m_fontSizeDelta = NoFontDelta;
     615    setUnderlineChange(TextDecorationChange::None);
     616    setStrikeThroughChange(TextDecorationChange::None);
    545617}
    546618
     
    551623        copy->m_mutableStyle = m_mutableStyle->mutableCopy();
    552624    copy->m_shouldUseFixedDefaultFontSize = m_shouldUseFixedDefaultFontSize;
     625    copy->m_underlineChange = m_underlineChange;
     626    copy->m_strikeThroughChange = m_strikeThroughChange;
    553627    copy->m_fontSizeDelta = m_fontSizeDelta;
    554628    return copy;
     
    695769}
    696770
    697 bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const
     771static RefPtr<CSSValueList> textDecorationValueList(const StyleProperties& properties)
     772{
     773    RefPtr<CSSValue> value = properties.getPropertyCSSValue(CSSPropertyTextDecoration);
     774    if (!is<CSSValueList>(value.get()))
     775        return nullptr;
     776    return downcast<CSSValueList>(value.get());
     777}
     778
     779bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr<MutableStyleProperties>* newInlineStylePtr, EditingStyle* extractedStyle) const
    698780{
    699781    ASSERT(element);
    700     ASSERT(!conflictingProperties || conflictingProperties->isEmpty());
    701782
    702783    const StyleProperties* inlineStyle = element->inlineStyle();
    703     if (!m_mutableStyle || !inlineStyle)
     784    if (!inlineStyle)
    704785        return false;
    705 
    706     unsigned propertyCount = m_mutableStyle->propertyCount();
     786    bool conflicts = false;
     787    RefPtr<MutableStyleProperties> newInlineStyle;
     788    if (newInlineStylePtr) {
     789        newInlineStyle = inlineStyle->mutableCopy();
     790        *newInlineStylePtr = newInlineStyle;
     791    }
     792
     793    bool shouldRemoveUnderline = underlineChange() == TextDecorationChange::Remove;
     794    bool shouldRemoveStrikeThrough = strikeThroughChange() == TextDecorationChange::Remove;
     795    if (shouldRemoveUnderline || shouldRemoveStrikeThrough) {
     796        if (RefPtr<CSSValueList> valueList = textDecorationValueList(*inlineStyle)) {
     797            RefPtr<CSSValueList> newValueList = valueList->copy();
     798            RefPtr<CSSValueList> extractedValueList = CSSValueList::createSpaceSeparated();
     799
     800            Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
     801            if (shouldRemoveUnderline && valueList->hasValue(underline.ptr())) {
     802                if (!newInlineStyle)
     803                    return true;
     804                newValueList->removeAll(underline.ptr());
     805                extractedValueList->append(WTF::move(underline));
     806            }
     807
     808            Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
     809            if (shouldRemoveStrikeThrough && valueList->hasValue(lineThrough.ptr())) {
     810                if (!newInlineStyle)
     811                    return true;
     812                newValueList->removeAll(lineThrough.ptr());
     813                extractedValueList->append(WTF::move(lineThrough));
     814            }
     815
     816            if (extractedValueList->length()) {
     817                conflicts = true;
     818                if (newValueList->length())
     819                    newInlineStyle->setProperty(CSSPropertyTextDecoration, newValueList);
     820                else
     821                    newInlineStyle->removeProperty(CSSPropertyTextDecoration);
     822
     823                if (extractedStyle) {
     824                    bool isImportant = inlineStyle->propertyIsImportant(CSSPropertyTextDecoration);
     825                    extractedStyle->setProperty(CSSPropertyTextDecoration, extractedValueList->cssText(), isImportant);
     826                }
     827            }
     828        }
     829    }
     830
     831    unsigned propertyCount = m_mutableStyle ? m_mutableStyle->propertyCount() : 0;
    707832    for (unsigned i = 0; i < propertyCount; ++i) {
    708833        CSSPropertyID propertyID = m_mutableStyle->propertyAt(i).id();
     
    713838
    714839        if (propertyID == CSSPropertyWebkitTextDecorationsInEffect && inlineStyle->getPropertyCSSValue(CSSPropertyTextDecoration)) {
    715             if (!conflictingProperties)
     840            if (!newInlineStyle)
    716841                return true;
    717             conflictingProperties->append(CSSPropertyTextDecoration);
     842            conflicts = true;
     843            newInlineStyle->removeProperty(CSSPropertyTextDecoration);
    718844            if (extractedStyle)
    719845                extractedStyle->setProperty(CSSPropertyTextDecoration, inlineStyle->getPropertyValue(CSSPropertyTextDecoration), inlineStyle->propertyIsImportant(CSSPropertyTextDecoration));
    720             continue;
    721846        }
    722847
     
    725850
    726851        if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) {
    727             if (!conflictingProperties)
     852            if (!newInlineStyle)
    728853                return true;
    729             conflictingProperties->append(CSSPropertyDirection);
     854            conflicts = true;
     855            newInlineStyle->removeProperty(CSSPropertyDirection);
    730856            if (extractedStyle)
    731857                extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
    732858        }
    733859
    734         if (!conflictingProperties)
     860        if (!newInlineStyle)
    735861            return true;
    736862
    737         conflictingProperties->append(propertyID);
    738 
     863        conflicts = true;
     864        newInlineStyle->removeProperty(propertyID);
    739865        if (extractedStyle)
    740866            extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
    741867    }
    742868
    743     return conflictingProperties && !conflictingProperties->isEmpty();
     869    return conflicts;
    744870}
    745871
     
    767893bool EditingStyle::conflictsWithImplicitStyleOfElement(HTMLElement* element, EditingStyle* extractedStyle, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
    768894{
    769     if (!m_mutableStyle)
     895    if (isEmpty())
    770896        return false;
    771897
    772898    const Vector<std::unique_ptr<HTMLElementEquivalent>>& HTMLElementEquivalents = htmlElementEquivalents();
    773     for (size_t i = 0; i < HTMLElementEquivalents.size(); ++i) {
    774         const HTMLElementEquivalent* equivalent = HTMLElementEquivalents[i].get();
    775         if (equivalent->matches(element) && equivalent->propertyExistsInStyle(m_mutableStyle.get())
    776             && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))) {
     899    for (auto& equivalent : HTMLElementEquivalents) {
     900        if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this)
     901            && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(*element, *this))) {
    777902            if (extractedStyle)
    778903                equivalent->addToStyle(element, extractedStyle);
     
    804929{
    805930    ASSERT(element);
    806     if (!m_mutableStyle)
     931    if (isEmpty())
    807932        return false;
    808933
    809934    const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
    810     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
    811         if (HTMLAttributeEquivalents[i]->matches(element) && HTMLAttributeEquivalents[i]->propertyExistsInStyle(m_mutableStyle.get())
    812             && !HTMLAttributeEquivalents[i]->valueIsPresentInStyle(element, m_mutableStyle.get()))
     935    for (auto& equivalent : HTMLAttributeEquivalents) {
     936        if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this) && !equivalent->valueIsPresentInStyle(*element, *this))
    813937            return true;
    814938    }
     
    835959            continue;
    836960
    837         if (!equivalent->matches(element) || !equivalent->propertyExistsInStyle(m_mutableStyle.get())
    838             || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(element, m_mutableStyle.get())))
     961        if (!equivalent->matches(*element) || !equivalent->propertyExistsInStyle(*this)
     962            || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(*element, *this)))
    839963            continue;
    840964
     
    850974bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const
    851975{
    852     if (!m_mutableStyle)
     976    if (isEmpty())
    853977        return true;
    854978    ComputedStyleExtractor computedStyle(node);
    855     return getPropertiesNotIn(*m_mutableStyle, computedStyle)->isEmpty();
     979
     980    bool shouldAddUnderline = underlineChange() == TextDecorationChange::Add;
     981    bool shouldAddLineThrough = strikeThroughChange() == TextDecorationChange::Add;
     982    if (shouldAddUnderline || shouldAddLineThrough) {
     983        bool hasUnderline = false;
     984        bool hasLineThrough = false;
     985        if (RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyTextDecoration)) {
     986            if (value->isValueList()) {
     987                const CSSValueList& valueList = downcast<CSSValueList>(*value);
     988                hasUnderline = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueUnderline).get());
     989                hasLineThrough = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueLineThrough).get());
     990            }
     991        }
     992        if ((shouldAddUnderline && !hasUnderline) || (shouldAddLineThrough && !hasLineThrough))
     993            return false;
     994    }
     995
     996    return !m_mutableStyle || getPropertiesNotIn(*m_mutableStyle, computedStyle)->isEmpty();
    856997}
    857998
     
    8651006        size_t i;
    8661007        for (i = 0; i < HTMLElementEquivalents.size(); ++i) {
    867             if (HTMLElementEquivalents[i]->matches(element)) {
     1008            if (HTMLElementEquivalents[i]->matches(*element)) {
    8681009                elementIsSpanOrElementEquivalent = true;
    8691010                break;
     
    8781019    const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
    8791020    for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
    880         if (HTMLAttributeEquivalents[i]->matches(element) && HTMLAttributeEquivalents[i]->attributeName() != HTMLNames::dirAttr)
     1021        if (HTMLAttributeEquivalents[i]->matches(*element) && HTMLAttributeEquivalents[i]->attributeName() != HTMLNames::dirAttr)
    8811022            matchedAttributes++;
    8821023    }
     
    9701111
    9711112static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl(const HTMLElementEquivalent* equivalent, const StyledElement* element,
    972     EditingStyle::CSSPropertyOverrideMode mode, StyleProperties* style)
    973 {
    974     return equivalent->matches(element) && (!element->inlineStyle() || !equivalent->propertyExistsInStyle(element->inlineStyle()))
    975         && (mode == EditingStyle::OverrideValues || !equivalent->propertyExistsInStyle(style));
     1113    EditingStyle::CSSPropertyOverrideMode mode, EditingStyle& style)
     1114{
     1115    if (!equivalent->matches(*element))
     1116        return false;
     1117    if (mode != EditingStyle::OverrideValues && equivalent->propertyExistsInStyle(style))
     1118        return false;
     1119
     1120    return !element->inlineStyle() || !equivalent->propertyExistsInStyle(EditingStyle::create(element->inlineStyle()).get());
    9761121}
    9771122
     
    10061151    const Vector<std::unique_ptr<HTMLElementEquivalent>>& elementEquivalents = htmlElementEquivalents();
    10071152    for (size_t i = 0; i < elementEquivalents.size(); ++i) {
    1008         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(elementEquivalents[i].get(), element, mode, m_mutableStyle.get()))
     1153        if (elementMatchesAndPropertyIsNotInInlineStyleDecl(elementEquivalents[i].get(), element, mode, *this))
    10091154            elementEquivalents[i]->addToStyle(element, this);
    10101155    }
     
    10141159        if (attributeEquivalents[i]->attributeName() == HTMLNames::dirAttr)
    10151160            continue; // We don't want to include directionality
    1016         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(attributeEquivalents[i].get(), element, mode, m_mutableStyle.get()))
     1161        if (elementMatchesAndPropertyIsNotInInlineStyleDecl(attributeEquivalents[i].get(), element, mode, *this))
    10171162            attributeEquivalents[i]->addToStyle(element, this);
    10181163    }
     
    10501195
    10511196
    1052 static void mergeTextDecorationValues(CSSValueList* mergedValue, const CSSValueList* valueToMerge)
    1053 {
    1054     RefPtr<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
    1055     RefPtr<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
    1056 
    1057     if (valueToMerge->hasValue(underline.get()) && !mergedValue->hasValue(underline.get()))
    1058         mergedValue->append(underline.releaseNonNull());
    1059 
    1060     if (valueToMerge->hasValue(lineThrough.get()) && !mergedValue->hasValue(lineThrough.get()))
    1061         mergedValue->append(lineThrough.releaseNonNull());
     1197static void mergeTextDecorationValues(CSSValueList& mergedValue, const CSSValueList& valueToMerge)
     1198{
     1199    Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
     1200    Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
     1201
     1202    if (valueToMerge.hasValue(underline.ptr()) && !mergedValue.hasValue(underline.ptr()))
     1203        mergedValue.append(WTF::move(underline));
     1204
     1205    if (valueToMerge.hasValue(lineThrough.ptr()) && !mergedValue.hasValue(lineThrough.ptr()))
     1206        mergedValue.append(WTF::move(lineThrough));
    10621207}
    10631208
     
    10781223
    10791224        // text decorations never override values.
    1080         if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect) && property.value()->isValueList() && value) {
     1225        if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect)
     1226            && is<CSSValueList>(*property.value()) && value) {
    10811227            if (is<CSSValueList>(*value)) {
    1082                 mergeTextDecorationValues(downcast<CSSValueList>(value.get()), downcast<CSSValueList>(property.value()));
     1228                RefPtr<CSSValueList> newValue = downcast<CSSValueList>(*value).copy();
     1229                mergeTextDecorationValues(*newValue, downcast<CSSValueList>(*property.value()));
     1230                m_mutableStyle->setProperty(property.id(), newValue.release(), property.isImportant());
    10831231                continue;
    10841232            }
     
    10871235
    10881236        if (mode == OverrideValues || (mode == DoNotOverrideValues && !value))
    1089             m_mutableStyle->setProperty(property.id(), property.value()->cssText(), property.isImportant());
     1237            m_mutableStyle->setProperty(property.id(), property.value(), property.isImportant());
    10901238    }
    10911239
     
    13981546    , m_applySuperscript(false)
    13991547{
    1400     Document* document = position.anchorNode() ? &position.anchorNode()->document() : 0;
    1401     if (!style || !style->style() || !document || !document->frame())
     1548    Document* document = position.deprecatedNode() ? &position.deprecatedNode()->document() : 0;
     1549    if (!style || style->isEmpty() || !document || !document->frame())
    14021550        return;
    14031551
     
    14091557
    14101558    // FIXME: take care of background-color in effect
    1411     RefPtr<MutableStyleProperties> mutableStyle = getPropertiesNotIn(*style->style(), computedStyle);
     1559    RefPtr<MutableStyleProperties> mutableStyle = style->style() ?
     1560        getPropertiesNotIn(*style->style(), computedStyle) : MutableStyleProperties::create();
    14121561
    14131562    reconcileTextDecorationProperties(mutableStyle.get());
    1414     if (!document->frame()->editor().shouldStyleWithCSS())
     1563    bool shouldStyleWithCSS = document->frame()->editor().shouldStyleWithCSS();
     1564    if (!shouldStyleWithCSS)
    14151565        extractTextStyles(document, *mutableStyle, computedStyle.useFixedFontDefaultSize());
     1566
     1567    bool shouldAddUnderline = style->underlineChange() == TextDecorationChange::Add;
     1568    bool shouldAddStrikeThrough = style->strikeThroughChange() == TextDecorationChange::Add;
     1569    if (shouldAddUnderline || shouldAddStrikeThrough) {
     1570        RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyWebkitTextDecorationsInEffect);
     1571        if (!is<CSSValueList>(value.get()))
     1572            value = computedStyle.propertyValue(CSSPropertyTextDecoration);
     1573
     1574        RefPtr<CSSValueList> valueList;
     1575        if (is<CSSValueList>(value.get()))
     1576            valueList = downcast<CSSValueList>(value.get());
     1577
     1578        Ref<CSSValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
     1579        bool hasUnderline = valueList && valueList->hasValue(underline.ptr());
     1580
     1581        Ref<CSSValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
     1582        bool hasLineThrough = valueList && valueList->hasValue(lineThrough.ptr());
     1583
     1584        if (shouldStyleWithCSS) {
     1585            valueList = valueList ? valueList->copy() : CSSValueList::createSpaceSeparated();
     1586            if (shouldAddUnderline && !hasUnderline)
     1587                valueList->append(WTF::move(underline));
     1588            if (shouldAddStrikeThrough && !hasLineThrough)
     1589                valueList->append(WTF::move(lineThrough));
     1590            mutableStyle->setProperty(CSSPropertyTextDecoration, valueList.get());
     1591        } else {
     1592            m_applyUnderline = shouldAddUnderline && !hasUnderline;
     1593            m_applyLineThrough = shouldAddStrikeThrough && !hasLineThrough;
     1594        }
     1595    }
    14161596
    14171597    // Changing the whitespace style in a tab span would collapse the tab into a space.
     
    14241604        mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection));
    14251605
    1426     // Save the result for later
    1427     m_cssStyle = mutableStyle->asText().stripWhiteSpace();
     1606    if (!mutableStyle->isEmpty())
     1607        m_cssStyle = mutableStyle;
     1608}
     1609
     1610bool StyleChange::operator==(const StyleChange& other)
     1611{
     1612    if (m_applyBold != other.m_applyBold
     1613        || m_applyItalic != other.m_applyItalic
     1614        || m_applyUnderline != other.m_applyUnderline
     1615        || m_applyLineThrough != other.m_applyLineThrough
     1616        || m_applySubscript != other.m_applySubscript
     1617        || m_applySuperscript != other.m_applySuperscript
     1618        || m_applyFontColor != other.m_applyFontColor
     1619        || m_applyFontFace != other.m_applyFontFace
     1620        || m_applyFontSize != other.m_applyFontSize)
     1621        return false;
     1622
     1623    return (!m_cssStyle && !other.m_cssStyle)
     1624        || (m_cssStyle && other.m_cssStyle && m_cssStyle->asText() == other.m_cssStyle->asText());
    14281625}
    14291626
  • trunk/Source/WebCore/editing/EditingStyle.h

    r177733 r183770  
    3535#include "CSSPropertyNames.h"
    3636#include "CSSValueKeywords.h"
     37#include "StyleProperties.h"
    3738#include "WritingDirection.h"
    3839#include <wtf/Forward.h>
     40#include <wtf/HashMap.h>
    3941#include <wtf/RefCounted.h>
    4042#include <wtf/RefPtr.h>
     
    6264class VisibleSelection;
    6365
     66enum class TextDecorationChange { None, Add, Remove };
     67
    6468class EditingStyle : public RefCounted<EditingStyle> {
    6569public:
     
    9296
    9397    static Ref<EditingStyle> create(CSSPropertyID propertyID, const String& value)
     98    {
     99        return adoptRef(*new EditingStyle(propertyID, value));
     100    }
     101
     102    static Ref<EditingStyle> create(CSSPropertyID propertyID, CSSValueID value)
    94103    {
    95104        return adoptRef(*new EditingStyle(propertyID, value));
     
    103112    void setStyle(PassRefPtr<MutableStyleProperties>);
    104113    void overrideWithStyle(const StyleProperties*);
     114    void overrideTypingStyleAt(const EditingStyle&, const Position&);
    105115    void clear();
    106116    PassRefPtr<EditingStyle> copy() const;
     
    116126    TriState triStateOfStyle(const VisibleSelection&) const;
    117127    bool conflictsWithInlineStyleOfElement(StyledElement* element) const { return conflictsWithInlineStyleOfElement(element, 0, 0); }
    118     bool conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>& conflictingProperties) const
    119     {
    120         return conflictsWithInlineStyleOfElement(element, extractedStyle, &conflictingProperties);
     128    bool conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr<MutableStyleProperties>& newInlineStyle,
     129        EditingStyle* extractedStyle) const
     130    {
     131        return conflictsWithInlineStyleOfElement(element, &newInlineStyle, extractedStyle);
    121132    }
    122133    bool conflictsWithImplicitStyleOfElement(HTMLElement*, EditingStyle* extractedStyle = 0, ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const;
     
    145156    bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; }
    146157    bool shouldUseFixedDefaultFontSize() const { return m_shouldUseFixedDefaultFontSize; }
     158   
     159    void setUnderlineChange(TextDecorationChange change) { m_underlineChange = static_cast<unsigned>(change); }
     160    TextDecorationChange underlineChange() const { return static_cast<TextDecorationChange>(m_underlineChange); }
     161    void setStrikeThroughChange(TextDecorationChange change) { m_strikeThroughChange = static_cast<unsigned>(change); }
     162    TextDecorationChange strikeThroughChange() const { return static_cast<TextDecorationChange>(m_strikeThroughChange); }
    147163
    148164    static PassRefPtr<EditingStyle> styleAtSelectionStart(const VisibleSelection&, bool shouldUseBackgroundColorInEffect = false);
     
    154170    explicit EditingStyle(const StyleProperties*);
    155171    EditingStyle(CSSPropertyID, const String& value);
     172    EditingStyle(CSSPropertyID, CSSValueID);
    156173    void init(Node*, PropertiesToInclude);
    157174    void removeTextFillAndStrokeColorsIfNeeded(RenderStyle*);
     
    159176    void extractFontSizeDelta();
    160177    template<typename T> TriState triStateOfStyle(T& styleToCompare, ShouldIgnoreTextOnlyProperties) const;
    161     bool conflictsWithInlineStyleOfElement(StyledElement*, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const;
     178    bool conflictsWithInlineStyleOfElement(StyledElement*, RefPtr<MutableStyleProperties>* newInlineStyle, EditingStyle* extractedStyle) const;
    162179    void mergeInlineAndImplicitStyleOfElement(StyledElement*, CSSPropertyOverrideMode, PropertiesToInclude);
    163180    void mergeStyle(const StyleProperties*, CSSPropertyOverrideMode);
    164181
    165182    RefPtr<MutableStyleProperties> m_mutableStyle;
    166     bool m_shouldUseFixedDefaultFontSize;
    167     float m_fontSizeDelta;
     183    unsigned m_shouldUseFixedDefaultFontSize : 1;
     184    unsigned m_underlineChange : 2;
     185    unsigned m_strikeThroughChange : 2;
     186    float m_fontSizeDelta = NoFontDelta;
    168187
    169188    friend class HTMLElementEquivalent;
    170189    friend class HTMLAttributeEquivalent;
     190    friend class HTMLTextDecorationEquivalent;
    171191};
    172192
    173193class StyleChange {
    174194public:
    175     StyleChange()
    176         : m_applyBold(false)
    177         , m_applyItalic(false)
    178         , m_applyUnderline(false)
    179         , m_applyLineThrough(false)
    180         , m_applySubscript(false)
    181         , m_applySuperscript(false)
    182     { }
    183 
     195    StyleChange() { }
    184196    StyleChange(EditingStyle*, const Position&);
    185197
    186     String cssStyle() const { return m_cssStyle; }
     198    const StyleProperties* cssStyle() const { return m_cssStyle.get(); }
    187199    bool applyBold() const { return m_applyBold; }
    188200    bool applyItalic() const { return m_applyItalic; }
     
    199211    String fontSize() { return m_applyFontSize; }
    200212
    201     bool operator==(const StyleChange& other)
    202     {
    203         return m_cssStyle == other.m_cssStyle
    204             && m_applyBold == other.m_applyBold
    205             && m_applyItalic == other.m_applyItalic
    206             && m_applyUnderline == other.m_applyUnderline
    207             && m_applyLineThrough == other.m_applyLineThrough
    208             && m_applySubscript == other.m_applySubscript
    209             && m_applySuperscript == other.m_applySuperscript
    210             && m_applyFontColor == other.m_applyFontColor
    211             && m_applyFontFace == other.m_applyFontFace
    212             && m_applyFontSize == other.m_applyFontSize;
    213     }
     213    bool operator==(const StyleChange&);
    214214    bool operator!=(const StyleChange& other)
    215215    {
     
    219219    void extractTextStyles(Document*, MutableStyleProperties&, bool shouldUseFixedFontDefaultSize);
    220220
    221     String m_cssStyle;
    222     bool m_applyBold;
    223     bool m_applyItalic;
    224     bool m_applyUnderline;
    225     bool m_applyLineThrough;
    226     bool m_applySubscript;
    227     bool m_applySuperscript;
     221    RefPtr<MutableStyleProperties> m_cssStyle;
     222    bool m_applyBold = false;
     223    bool m_applyItalic = false;
     224    bool m_applyUnderline = false;
     225    bool m_applyLineThrough = false;
     226    bool m_applySubscript = false;
     227    bool m_applySuperscript = false;
    228228    String m_applyFontColor;
    229229    String m_applyFontFace;
  • trunk/Source/WebCore/editing/Editor.cpp

    r183368 r183770  
    888888        break;
    889889    case VisibleSelection::CaretSelection:
    890         computeAndSetTypingStyle(style, editingAction);
     890        computeAndSetTypingStyle(EditingStyle::create(style), editingAction);
    891891        break;
    892892    case VisibleSelection::RangeSelection:
    893893        if (style)
    894894            applyCommand(ApplyStyleCommand::create(document(), EditingStyle::create(style).ptr(), editingAction));
     895        break;
     896    }
     897}
     898
     899void Editor::applyStyle(RefPtr<EditingStyle>&& style, EditAction editingAction)
     900{
     901    switch (m_frame.selection().selection().selectionType()) {
     902    case VisibleSelection::NoSelection:
     903        // do nothing
     904        break;
     905    case VisibleSelection::CaretSelection:
     906        computeAndSetTypingStyle(*style, editingAction);
     907        break;
     908    case VisibleSelection::RangeSelection:
     909        if (style)
     910            applyCommand(ApplyStyleCommand::create(document(), style.get(), editingAction));
    895911        break;
    896912    }
     
    921937        return;
    922938
    923     if (client() && client()->shouldApplyStyle(style, m_frame.selection().toNormalizedRange().get()))
    924         applyStyle(style, editingAction);
     939    if (!client() || !client()->shouldApplyStyle(style, m_frame.selection().toNormalizedRange().get()))
     940        return;
     941    applyStyle(style, editingAction);
     942}
     943
     944void Editor::applyStyleToSelection(RefPtr<EditingStyle>&& style, EditAction editingAction)
     945{
     946    if (!style || style->isEmpty() || !canEditRichly())
     947        return;
     948
     949    // FIXME: This is wrong for text decorations since m_mutableStyle is empty.
     950    if (!client() || !client()->shouldApplyStyle(style->style(), m_frame.selection().toNormalizedRange().get()))
     951        return;
     952
     953    applyStyle(WTF::move(style), editingAction);
    925954}
    926955
     
    29532982}
    29542983
    2955 void Editor::computeAndSetTypingStyle(StyleProperties* style, EditAction editingAction)
    2956 {
    2957     if (!style || style->isEmpty()) {
     2984void Editor::computeAndSetTypingStyle(EditingStyle& style, EditAction editingAction)
     2985{
     2986    if (style.isEmpty()) {
    29582987        m_frame.selection().clearTypingStyle();
    29592988        return;
     
    29622991    // Calculate the current typing style.
    29632992    RefPtr<EditingStyle> typingStyle;
    2964     if (m_frame.selection().typingStyle()) {
    2965         typingStyle = m_frame.selection().typingStyle()->copy();
    2966         typingStyle->overrideWithStyle(style);
    2967     } else
    2968         typingStyle = EditingStyle::create(style);
    2969 
    2970     typingStyle->prepareToApplyAt(m_frame.selection().selection().visibleStart().deepEquivalent(), EditingStyle::PreserveWritingDirection);
     2993    if (auto existingTypingStyle = m_frame.selection().typingStyle())
     2994        typingStyle = existingTypingStyle->copy();
     2995    else
     2996        typingStyle = EditingStyle::create();
     2997    typingStyle->overrideTypingStyleAt(style, m_frame.selection().selection().visibleStart().deepEquivalent());
    29712998
    29722999    // Handle block styles, substracting these from the typing style.
     
    29773004    // Set the remaining style as the typing style.
    29783005    m_frame.selection().setTypingStyle(typingStyle);
     3006}
     3007
     3008void Editor::computeAndSetTypingStyle(StyleProperties& properties, EditAction editingAction)
     3009{
     3010    return computeAndSetTypingStyle(EditingStyle::create(&properties), editingAction);
    29793011}
    29803012
  • trunk/Source/WebCore/editing/Editor.h

    r183368 r183770  
    184184   
    185185    WEBCORE_EXPORT void applyStyle(StyleProperties*, EditAction = EditActionUnspecified);
     186    void applyStyle(RefPtr<EditingStyle>&&, EditAction);
    186187    void applyParagraphStyle(StyleProperties*, EditAction = EditActionUnspecified);
    187188    WEBCORE_EXPORT void applyStyleToSelection(StyleProperties*, EditAction);
     189    void applyStyleToSelection(RefPtr<EditingStyle>&&, EditAction);
    188190    void applyParagraphStyleToSelection(StyleProperties*, EditAction);
    189191
     
    362364    void setMark(const VisibleSelection&);
    363365
    364     WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties* , EditAction = EditActionUnspecified);
     366    void computeAndSetTypingStyle(EditingStyle& , EditAction = EditActionUnspecified);
     367    WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties& , EditAction = EditActionUnspecified);
    365368    WEBCORE_EXPORT void applyEditingStyleToBodyElement() const;
    366369    void applyEditingStyleToElement(Element*) const;
  • trunk/Source/WebCore/editing/EditorCommand.cpp

    r183368 r183770  
    9999}
    100100
    101 static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, StyleProperties* style)
     101static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, RefPtr<EditingStyle>&& style)
    102102{
    103103    // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
    104104    switch (source) {
    105105    case CommandFromMenuOrKeyBinding:
    106         frame.editor().applyStyleToSelection(style, action);
     106        frame.editor().applyStyleToSelection(WTF::move(style), action);
    107107        return true;
    108108    case CommandFromDOM:
    109109    case CommandFromDOMWithUserInterface:
    110         frame.editor().applyStyle(style);
     110        frame.editor().applyStyle(WTF::move(style), EditActionUnspecified);
    111111        return true;
    112112    }
     
    115115}
    116116
    117 static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
    118 {
    119     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
    120     style->setProperty(propertyID, propertyValue);
    121     return applyCommandToFrame(frame, source, action, style.get());
    122 }
    123 
    124 static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
    125 {
    126     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
    127     style->setProperty(propertyID, propertyValue);
    128     return applyCommandToFrame(frame, source, action, style.get());
    129 }
    130 
    131 // FIXME: executeToggleStyleInList does not handle complicated cases such as <b><u>hello</u>world</b> properly.
    132 //        This function must use Editor::selectionHasStyle to determine the current style but we cannot fix this
    133 //        until https://bugs.webkit.org/show_bug.cgi?id=27818 is resolved.
    134 static bool executeToggleStyleInList(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValue* value)
    135 {
    136     RefPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelectionStart(frame.selection().selection());
    137     if (!selectionStyle || !selectionStyle->style())
    138         return false;
    139 
    140     RefPtr<CSSValue> selectedCSSValue = selectionStyle->style()->getPropertyCSSValue(propertyID);
    141     String newStyle = ASCIILiteral("none");
    142     if (is<CSSValueList>(*selectedCSSValue)) {
    143         RefPtr<CSSValueList> selectedCSSValueList = downcast<CSSValueList>(selectedCSSValue.get());
    144         if (!selectedCSSValueList->removeAll(value))
    145             selectedCSSValueList->append(*value);
    146         if (selectedCSSValueList->length())
    147             newStyle = selectedCSSValueList->cssText();
    148 
    149     } else if (selectedCSSValue->cssText() == "none")
    150         newStyle = value->cssText();
    151 
    152     // FIXME: We shouldn't be having to convert new style into text.  We should have setPropertyCSSValue.
    153     RefPtr<MutableStyleProperties> newMutableStyle = MutableStyleProperties::create();
    154     newMutableStyle->setProperty(propertyID, newStyle);
    155     return applyCommandToFrame(frame, source, action, newMutableStyle.get());
    156 }
    157 
    158 static bool executeToggleStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const char* offValue, const char* onValue)
     117static bool isStylePresent(Editor& editor, CSSPropertyID propertyID, const char* onValue)
    159118{
    160119    // Style is considered present when
    161120    // Mac: present at the beginning of selection
    162     // other: present throughout the selection
    163 
    164     bool styleIsPresent;
    165     if (frame.editor().behavior().shouldToggleStyleBasedOnStartOfSelection())
    166         styleIsPresent = frame.editor().selectionStartHasStyle(propertyID, onValue);
    167     else
    168         styleIsPresent = frame.editor().selectionHasStyle(propertyID, onValue) == TrueTriState;
    169 
    170     RefPtr<EditingStyle> style = EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue);
    171     return applyCommandToFrame(frame, source, action, style->style());
     121    // Windows: present throughout the selection
     122    if (editor.behavior().shouldToggleStyleBasedOnStartOfSelection())
     123        return editor.selectionStartHasStyle(propertyID, onValue);
     124    return editor.selectionHasStyle(propertyID, onValue) == TrueTriState;
     125}
     126
     127static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
     128{
     129    return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
     130}
     131
     132static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
     133{
     134    return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
     135}
     136
     137static bool executeToggleStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const char* offValue, const char* onValue)
     138{
     139    bool styleIsPresent = isStylePresent(frame.editor(), propertyID, onValue);
     140    return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue));
    172141}
    173142
     
    10591028}
    10601029
     1030static TextDecorationChange textDecorationChangeForToggling(Editor& editor, CSSPropertyID propertyID, const char* onValue)
     1031{
     1032    return isStylePresent(editor, propertyID, onValue) ? TextDecorationChange::Remove : TextDecorationChange::Add;
     1033}
     1034
    10611035static bool executeStrikethrough(Frame& frame, Event*, EditorCommandSource source, const String&)
    10621036{
    1063     RefPtr<CSSPrimitiveValue> lineThrough = CSSPrimitiveValue::createIdentifier(CSSValueLineThrough);
    1064     return executeToggleStyleInList(frame, source, EditActionUnderline, CSSPropertyWebkitTextDecorationsInEffect, lineThrough.get());
     1037    RefPtr<EditingStyle> style = EditingStyle::create();
     1038    style->setStrikeThroughChange(textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "line-through"));
     1039    // FIXME: Needs a new EditAction!
     1040    return applyCommandToFrame(frame, source, EditActionUnderline, WTF::move(style));
    10651041}
    10661042
     
    11261102static bool executeUnderline(Frame& frame, Event*, EditorCommandSource source, const String&)
    11271103{
    1128     RefPtr<CSSPrimitiveValue> underline = CSSPrimitiveValue::createIdentifier(CSSValueUnderline);
    1129     return executeToggleStyleInList(frame, source, EditActionUnderline, CSSPropertyWebkitTextDecorationsInEffect, underline.get());
     1104    RefPtr<EditingStyle> style = EditingStyle::create();
     1105    TextDecorationChange change = textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "underline");
     1106    style->setUnderlineChange(change);
     1107    return applyCommandToFrame(frame, source, EditActionUnderline, WTF::move(style));
    11301108}
    11311109
  • trunk/Source/WebKit/mac/ChangeLog

    r183697 r183770  
     12015-05-04  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Toggling underline or strike through affects each other
     4        https://bugs.webkit.org/show_bug.cgi?id=27818
     5
     6        Reviewed by Darin Adler.
     7
     8        * WebView/WebFrame.mm:
     9        (-[WebFrame _setTypingStyle:withUndoAction:]):
     10
    1112015-05-01  Martin Robinson  <mrobinson@igalia.com>
    212
  • trunk/Source/WebKit/mac/WebView/WebFrame.mm

    r183172 r183770  
    942942    // FIXME: We shouldn't have to create a copy here.
    943943    Ref<MutableStyleProperties> properties(core(style)->copyProperties());
    944     _private->coreFrame->editor().computeAndSetTypingStyle(properties.ptr(), undoAction);
     944    _private->coreFrame->editor().computeAndSetTypingStyle(properties.get(), undoAction);
    945945}
    946946
Note: See TracChangeset for help on using the changeset viewer.