Changeset 183770 in webkit
- Timestamp:
- May 4, 2015 1:42:41 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r183765 r183770 1 2015-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 1 19 2015-05-04 Chris Dumez <cdumez@apple.com> 2 20 -
trunk/LayoutTests/editing/execCommand/script-tests/toggle-style-2.js
r120173 r183770 38 38 39 39 testSingleToggle("strikethrough", "<u>test</u>", "<u><strike>test</strike></u>"); 40 testSingleToggle("underline", "<strike>test</strike>", "< u><strike>test</strike></u>");40 testSingleToggle("underline", "<strike>test</strike>", "<strike><u>test</u></strike>"); 41 41 42 42 testSingleToggle("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 20 20 testSingleToggle("underline", "test", "<span style=\"text-decoration: underline;\">test</span>"); 21 21 testSingleToggle("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>"); 22 testSingleToggle("underline", "<span style=\"text-decoration: underline line-through overline;\">test</span>", 23 "<span style=\"text-decoration: line-through overline;\">test</span>"); 23 24 testSingleToggle("strikethrough", "test", "<span style=\"text-decoration: line-through;\">test</span>"); 24 25 testSingleToggle("strikethrough", "<span style=\"text-decoration: line-through;\">test</span>", "test"); -
trunk/LayoutTests/editing/execCommand/toggle-style-2-expected.txt
r93001 r183770 11 11 PASS two strikethrough commands converted test to test 12 12 PASS 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>13 PASS one underline command converted <strike>test</strike> to <strike><u>test</u></strike> 14 14 PASS one strikethrough command converted <span style="text-decoration: overline;">test</span> to <span style="text-decoration: overline;"><strike>test</strike></span> 15 15 PASS 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 6 6 PASS one underline command converted test to <span style="text-decoration: underline;">test</span> 7 7 PASS 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>8 PASS one underline command converted <span style="text-decoration: underline line-through overline;">test</span> to <span style="text-decoration: line-through overline;">test</span> 9 9 PASS one strikethrough command converted test to <span style="text-decoration: line-through;">test</span> 10 10 PASS 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 60 60 Undo should reset the style attribute so that "test" is both bold and blue: 61 61 | <span> 62 | style=" color: blue; font-weight: 900;"62 | style="font-weight: 900; color: blue;" 63 63 | "<#selection-anchor>test<#selection-focus>" 64 64 -
trunk/Source/WebCore/ChangeLog
r183767 r183770 1 2015-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 1 103 2015-05-04 Eric Carlson <eric.carlson@apple.com> 2 104 -
trunk/Source/WebCore/editing/ApplyStyleCommand.cpp
r183368 r183770 264 264 while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) { 265 265 StyleChange styleChange(style, paragraphStart.deepEquivalent()); 266 if (styleChange.cssStyle() .length()|| m_removeOnly) {266 if (styleChange.cssStyle() || m_removeOnly) { 267 267 RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().deprecatedNode()); 268 268 if (!m_removeOnly) { … … 946 946 return style->conflictsWithInlineStyleOfElement(element); 947 947 948 Vector<CSSPropertyID> properties;949 if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle, properties))948 RefPtr<MutableStyleProperties> newInlineStyle; 949 if (!style->conflictsWithInlineStyleOfElement(element, newInlineStyle, extractedStyle)) 950 950 return false; 951 951 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()) 958 953 removeNodeAttribute(element, styleAttr); 954 else 955 setNodeAttribute(element, styleAttr, newInlineStyle->asText()); 959 956 960 957 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) … … 1371 1368 void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElement* block) 1372 1369 { 1370 ASSERT(styleChange.cssStyle()); 1373 1371 // Do not check for legacy styles here. Those styles, like <B> and <I>, only apply for 1374 1372 // inline content. … … 1376 1374 return; 1377 1375 1378 String cssStyle = styleChange.cssStyle() ;1376 String cssStyle = styleChange.cssStyle()->asText(); 1379 1377 StringBuilder cssText; 1380 1378 cssText.append(cssStyle); … … 1457 1455 } 1458 1456 1459 if ( styleChange.cssStyle().length()) {1457 if (auto styleToMerge = styleChange.cssStyle()) { 1460 1458 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()); 1469 1463 } else 1470 setNodeAttribute(styleContainer, styleAttr, style Change.cssStyle());1464 setNodeAttribute(styleContainer, styleAttr, styleToMerge->asText()); 1471 1465 } else { 1472 1466 RefPtr<Element> styleElement = createStyleSpanElement(document()); 1473 styleElement->setAttribute(styleAttr, style Change.cssStyle());1467 styleElement->setAttribute(styleAttr, styleToMerge->asText()); 1474 1468 surroundNodeRangeWithElement(startNode, endNode, styleElement.release()); 1475 1469 } -
trunk/Source/WebCore/editing/EditingStyle.cpp
r179143 r183770 161 161 162 162 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); } 164 164 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; 167 167 virtual void addToStyle(Element*, EditingStyle*) const; 168 168 … … 195 195 } 196 196 197 bool HTMLElementEquivalent::valueIsPresentInStyle(Element * element, StyleProperties*style) const198 { 199 RefPtr<CSSValue> value = style ->getPropertyCSSValue(m_propertyID);197 bool HTMLElementEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const 198 { 199 RefPtr<CSSValue> value = style.m_mutableStyle->getPropertyCSSValue(m_propertyID); 200 200 return matches(element) && is<CSSPrimitiveValue>(value.get()) && downcast<CSSPrimitiveValue>(*value).getValueID() == m_primitiveValue->getValueID(); 201 201 } … … 208 208 class HTMLTextDecorationEquivalent : public HTMLElementEquivalent { 209 209 public: 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 242 private: 243 TextDecorationChange changeInStyle(const EditingStyle& style) const 244 { 245 return m_isUnderline ? style.underlineChange() : style.strikeThroughChange(); 246 } 247 248 bool m_isUnderline; 214 249 }; 215 216 HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName)217 : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)218 // m_propertyID is used in HTMLElementEquivalent::addToStyle219 {220 }221 222 bool HTMLTextDecorationEquivalent::propertyExistsInStyle(const StyleProperties* style) const223 {224 return style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) || style->getPropertyCSSValue(CSSPropertyTextDecoration);225 }226 227 bool HTMLTextDecorationEquivalent::valueIsPresentInStyle(Element* element, StyleProperties* style) const228 {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 }234 250 235 251 class HTMLAttributeEquivalent : public HTMLElementEquivalent { … … 238 254 HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName); 239 255 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); } 241 257 virtual bool hasAttribute() const { return true; } 242 virtual bool valueIsPresentInStyle(Element *, StyleProperties*) const;258 virtual bool valueIsPresentInStyle(Element&, const EditingStyle&) const; 243 259 virtual void addToStyle(Element*, EditingStyle*) const; 244 260 virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const; … … 261 277 } 262 278 263 bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element * element, StyleProperties*style) const264 { 265 RefPtr<CSSValue> value = attributeValueAsCSSValue( element);266 RefPtr<CSSValue> styleValue = style ->getPropertyCSSValue(m_propertyID);279 bool 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); 267 283 268 284 return compareCSSValuePtr(value, styleValue); … … 316 332 EditingStyle::EditingStyle() 317 333 : m_shouldUseFixedDefaultFontSize(false) 318 , m_fontSizeDelta(NoFontDelta) 334 , m_underlineChange(static_cast<unsigned>(TextDecorationChange::None)) 335 , m_strikeThroughChange(static_cast<unsigned>(TextDecorationChange::None)) 319 336 { 320 337 } 321 338 322 339 EditingStyle::EditingStyle(Node* node, PropertiesToInclude propertiesToInclude) 323 : m_shouldUseFixedDefaultFontSize(false) 324 , m_fontSizeDelta(NoFontDelta) 340 : EditingStyle() 325 341 { 326 342 init(node, propertiesToInclude); … … 328 344 329 345 EditingStyle::EditingStyle(const Position& position, PropertiesToInclude propertiesToInclude) 330 : m_shouldUseFixedDefaultFontSize(false) 331 , m_fontSizeDelta(NoFontDelta) 346 : EditingStyle() 332 347 { 333 348 init(position.deprecatedNode(), propertiesToInclude); … … 335 350 336 351 EditingStyle::EditingStyle(const StyleProperties* style) 337 : m_shouldUseFixedDefaultFontSize(false) 338 , m_fontSizeDelta(NoFontDelta) 352 : EditingStyle() 339 353 { 340 354 if (style) … … 344 358 345 359 EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value) 346 : m_mutableStyle(0) 347 , m_shouldUseFixedDefaultFontSize(false) 348 , m_fontSizeDelta(NoFontDelta) 360 : EditingStyle() 349 361 { 350 362 setProperty(propertyID, value); 363 extractFontSizeDelta(); 364 } 365 366 EditingStyle::EditingStyle(CSSPropertyID propertyID, CSSValueID value) 367 : EditingStyle() 368 { 369 m_mutableStyle = MutableStyleProperties::create(); 370 m_mutableStyle->setProperty(propertyID, value); 371 extractFontSizeDelta(); 351 372 } 352 373 … … 493 514 bool EditingStyle::isEmpty() const 494 515 { 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; 496 518 } 497 519 … … 538 560 } 539 561 562 static 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 576 void 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 540 610 void EditingStyle::clear() 541 611 { … … 543 613 m_shouldUseFixedDefaultFontSize = false; 544 614 m_fontSizeDelta = NoFontDelta; 615 setUnderlineChange(TextDecorationChange::None); 616 setStrikeThroughChange(TextDecorationChange::None); 545 617 } 546 618 … … 551 623 copy->m_mutableStyle = m_mutableStyle->mutableCopy(); 552 624 copy->m_shouldUseFixedDefaultFontSize = m_shouldUseFixedDefaultFontSize; 625 copy->m_underlineChange = m_underlineChange; 626 copy->m_strikeThroughChange = m_strikeThroughChange; 553 627 copy->m_fontSizeDelta = m_fontSizeDelta; 554 628 return copy; … … 695 769 } 696 770 697 bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const 771 static 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 779 bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr<MutableStyleProperties>* newInlineStylePtr, EditingStyle* extractedStyle) const 698 780 { 699 781 ASSERT(element); 700 ASSERT(!conflictingProperties || conflictingProperties->isEmpty());701 782 702 783 const StyleProperties* inlineStyle = element->inlineStyle(); 703 if (! m_mutableStyle || !inlineStyle)784 if (!inlineStyle) 704 785 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; 707 832 for (unsigned i = 0; i < propertyCount; ++i) { 708 833 CSSPropertyID propertyID = m_mutableStyle->propertyAt(i).id(); … … 713 838 714 839 if (propertyID == CSSPropertyWebkitTextDecorationsInEffect && inlineStyle->getPropertyCSSValue(CSSPropertyTextDecoration)) { 715 if (! conflictingProperties)840 if (!newInlineStyle) 716 841 return true; 717 conflictingProperties->append(CSSPropertyTextDecoration); 842 conflicts = true; 843 newInlineStyle->removeProperty(CSSPropertyTextDecoration); 718 844 if (extractedStyle) 719 845 extractedStyle->setProperty(CSSPropertyTextDecoration, inlineStyle->getPropertyValue(CSSPropertyTextDecoration), inlineStyle->propertyIsImportant(CSSPropertyTextDecoration)); 720 continue;721 846 } 722 847 … … 725 850 726 851 if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) { 727 if (! conflictingProperties)852 if (!newInlineStyle) 728 853 return true; 729 conflictingProperties->append(CSSPropertyDirection); 854 conflicts = true; 855 newInlineStyle->removeProperty(CSSPropertyDirection); 730 856 if (extractedStyle) 731 857 extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID)); 732 858 } 733 859 734 if (! conflictingProperties)860 if (!newInlineStyle) 735 861 return true; 736 862 737 conflict ingProperties->append(propertyID);738 863 conflicts = true; 864 newInlineStyle->removeProperty(propertyID); 739 865 if (extractedStyle) 740 866 extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID)); 741 867 } 742 868 743 return conflict ingProperties && !conflictingProperties->isEmpty();869 return conflicts; 744 870 } 745 871 … … 767 893 bool EditingStyle::conflictsWithImplicitStyleOfElement(HTMLElement* element, EditingStyle* extractedStyle, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const 768 894 { 769 if ( !m_mutableStyle)895 if (isEmpty()) 770 896 return false; 771 897 772 898 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))) { 777 902 if (extractedStyle) 778 903 equivalent->addToStyle(element, extractedStyle); … … 804 929 { 805 930 ASSERT(element); 806 if ( !m_mutableStyle)931 if (isEmpty()) 807 932 return false; 808 933 809 934 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)) 813 937 return true; 814 938 } … … 835 959 continue; 836 960 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))) 839 963 continue; 840 964 … … 850 974 bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const 851 975 { 852 if ( !m_mutableStyle)976 if (isEmpty()) 853 977 return true; 854 978 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(); 856 997 } 857 998 … … 865 1006 size_t i; 866 1007 for (i = 0; i < HTMLElementEquivalents.size(); ++i) { 867 if (HTMLElementEquivalents[i]->matches( element)) {1008 if (HTMLElementEquivalents[i]->matches(*element)) { 868 1009 elementIsSpanOrElementEquivalent = true; 869 1010 break; … … 878 1019 const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents(); 879 1020 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) 881 1022 matchedAttributes++; 882 1023 } … … 970 1111 971 1112 static 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()); 976 1121 } 977 1122 … … 1006 1151 const Vector<std::unique_ptr<HTMLElementEquivalent>>& elementEquivalents = htmlElementEquivalents(); 1007 1152 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)) 1009 1154 elementEquivalents[i]->addToStyle(element, this); 1010 1155 } … … 1014 1159 if (attributeEquivalents[i]->attributeName() == HTMLNames::dirAttr) 1015 1160 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)) 1017 1162 attributeEquivalents[i]->addToStyle(element, this); 1018 1163 } … … 1050 1195 1051 1196 1052 static void mergeTextDecorationValues(CSSValueList * mergedValue, const CSSValueList*valueToMerge)1053 { 1054 Ref Ptr<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);1055 Ref Ptr<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());1197 static 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)); 1062 1207 } 1063 1208 … … 1078 1223 1079 1224 // 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) { 1081 1227 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()); 1083 1231 continue; 1084 1232 } … … 1087 1235 1088 1236 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()); 1090 1238 } 1091 1239 … … 1398 1546 , m_applySuperscript(false) 1399 1547 { 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()) 1402 1550 return; 1403 1551 … … 1409 1557 1410 1558 // 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(); 1412 1561 1413 1562 reconcileTextDecorationProperties(mutableStyle.get()); 1414 if (!document->frame()->editor().shouldStyleWithCSS()) 1563 bool shouldStyleWithCSS = document->frame()->editor().shouldStyleWithCSS(); 1564 if (!shouldStyleWithCSS) 1415 1565 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 } 1416 1596 1417 1597 // Changing the whitespace style in a tab span would collapse the tab into a space. … … 1424 1604 mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection)); 1425 1605 1426 // Save the result for later 1427 m_cssStyle = mutableStyle->asText().stripWhiteSpace(); 1606 if (!mutableStyle->isEmpty()) 1607 m_cssStyle = mutableStyle; 1608 } 1609 1610 bool 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()); 1428 1625 } 1429 1626 -
trunk/Source/WebCore/editing/EditingStyle.h
r177733 r183770 35 35 #include "CSSPropertyNames.h" 36 36 #include "CSSValueKeywords.h" 37 #include "StyleProperties.h" 37 38 #include "WritingDirection.h" 38 39 #include <wtf/Forward.h> 40 #include <wtf/HashMap.h> 39 41 #include <wtf/RefCounted.h> 40 42 #include <wtf/RefPtr.h> … … 62 64 class VisibleSelection; 63 65 66 enum class TextDecorationChange { None, Add, Remove }; 67 64 68 class EditingStyle : public RefCounted<EditingStyle> { 65 69 public: … … 92 96 93 97 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) 94 103 { 95 104 return adoptRef(*new EditingStyle(propertyID, value)); … … 103 112 void setStyle(PassRefPtr<MutableStyleProperties>); 104 113 void overrideWithStyle(const StyleProperties*); 114 void overrideTypingStyleAt(const EditingStyle&, const Position&); 105 115 void clear(); 106 116 PassRefPtr<EditingStyle> copy() const; … … 116 126 TriState triStateOfStyle(const VisibleSelection&) const; 117 127 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); 121 132 } 122 133 bool conflictsWithImplicitStyleOfElement(HTMLElement*, EditingStyle* extractedStyle = 0, ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const; … … 145 156 bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; } 146 157 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); } 147 163 148 164 static PassRefPtr<EditingStyle> styleAtSelectionStart(const VisibleSelection&, bool shouldUseBackgroundColorInEffect = false); … … 154 170 explicit EditingStyle(const StyleProperties*); 155 171 EditingStyle(CSSPropertyID, const String& value); 172 EditingStyle(CSSPropertyID, CSSValueID); 156 173 void init(Node*, PropertiesToInclude); 157 174 void removeTextFillAndStrokeColorsIfNeeded(RenderStyle*); … … 159 176 void extractFontSizeDelta(); 160 177 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; 162 179 void mergeInlineAndImplicitStyleOfElement(StyledElement*, CSSPropertyOverrideMode, PropertiesToInclude); 163 180 void mergeStyle(const StyleProperties*, CSSPropertyOverrideMode); 164 181 165 182 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; 168 187 169 188 friend class HTMLElementEquivalent; 170 189 friend class HTMLAttributeEquivalent; 190 friend class HTMLTextDecorationEquivalent; 171 191 }; 172 192 173 193 class StyleChange { 174 194 public: 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() { } 184 196 StyleChange(EditingStyle*, const Position&); 185 197 186 String cssStyle() const { return m_cssStyle; }198 const StyleProperties* cssStyle() const { return m_cssStyle.get(); } 187 199 bool applyBold() const { return m_applyBold; } 188 200 bool applyItalic() const { return m_applyItalic; } … … 199 211 String fontSize() { return m_applyFontSize; } 200 212 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&); 214 214 bool operator!=(const StyleChange& other) 215 215 { … … 219 219 void extractTextStyles(Document*, MutableStyleProperties&, bool shouldUseFixedFontDefaultSize); 220 220 221 Stringm_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; 228 228 String m_applyFontColor; 229 229 String m_applyFontFace; -
trunk/Source/WebCore/editing/Editor.cpp
r183368 r183770 888 888 break; 889 889 case VisibleSelection::CaretSelection: 890 computeAndSetTypingStyle( style, editingAction);890 computeAndSetTypingStyle(EditingStyle::create(style), editingAction); 891 891 break; 892 892 case VisibleSelection::RangeSelection: 893 893 if (style) 894 894 applyCommand(ApplyStyleCommand::create(document(), EditingStyle::create(style).ptr(), editingAction)); 895 break; 896 } 897 } 898 899 void 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)); 895 911 break; 896 912 } … … 921 937 return; 922 938 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 944 void 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); 925 954 } 926 955 … … 2953 2982 } 2954 2983 2955 void Editor::computeAndSetTypingStyle( StyleProperties*style, EditAction editingAction)2956 { 2957 if ( !style || style->isEmpty()) {2984 void Editor::computeAndSetTypingStyle(EditingStyle& style, EditAction editingAction) 2985 { 2986 if (style.isEmpty()) { 2958 2987 m_frame.selection().clearTypingStyle(); 2959 2988 return; … … 2962 2991 // Calculate the current typing style. 2963 2992 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()); 2971 2998 2972 2999 // Handle block styles, substracting these from the typing style. … … 2977 3004 // Set the remaining style as the typing style. 2978 3005 m_frame.selection().setTypingStyle(typingStyle); 3006 } 3007 3008 void Editor::computeAndSetTypingStyle(StyleProperties& properties, EditAction editingAction) 3009 { 3010 return computeAndSetTypingStyle(EditingStyle::create(&properties), editingAction); 2979 3011 } 2980 3012 -
trunk/Source/WebCore/editing/Editor.h
r183368 r183770 184 184 185 185 WEBCORE_EXPORT void applyStyle(StyleProperties*, EditAction = EditActionUnspecified); 186 void applyStyle(RefPtr<EditingStyle>&&, EditAction); 186 187 void applyParagraphStyle(StyleProperties*, EditAction = EditActionUnspecified); 187 188 WEBCORE_EXPORT void applyStyleToSelection(StyleProperties*, EditAction); 189 void applyStyleToSelection(RefPtr<EditingStyle>&&, EditAction); 188 190 void applyParagraphStyleToSelection(StyleProperties*, EditAction); 189 191 … … 362 364 void setMark(const VisibleSelection&); 363 365 364 WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties* , EditAction = EditActionUnspecified); 366 void computeAndSetTypingStyle(EditingStyle& , EditAction = EditActionUnspecified); 367 WEBCORE_EXPORT void computeAndSetTypingStyle(StyleProperties& , EditAction = EditActionUnspecified); 365 368 WEBCORE_EXPORT void applyEditingStyleToBodyElement() const; 366 369 void applyEditingStyleToElement(Element*) const; -
trunk/Source/WebCore/editing/EditorCommand.cpp
r183368 r183770 99 99 } 100 100 101 static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, StyleProperties*style)101 static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, RefPtr<EditingStyle>&& style) 102 102 { 103 103 // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that? 104 104 switch (source) { 105 105 case CommandFromMenuOrKeyBinding: 106 frame.editor().applyStyleToSelection( style, action);106 frame.editor().applyStyleToSelection(WTF::move(style), action); 107 107 return true; 108 108 case CommandFromDOM: 109 109 case CommandFromDOMWithUserInterface: 110 frame.editor().applyStyle( style);110 frame.editor().applyStyle(WTF::move(style), EditActionUnspecified); 111 111 return true; 112 112 } … … 115 115 } 116 116 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) 117 static bool isStylePresent(Editor& editor, CSSPropertyID propertyID, const char* onValue) 159 118 { 160 119 // Style is considered present when 161 120 // 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 127 static 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 132 static 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 137 static 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)); 172 141 } 173 142 … … 1059 1028 } 1060 1029 1030 static TextDecorationChange textDecorationChangeForToggling(Editor& editor, CSSPropertyID propertyID, const char* onValue) 1031 { 1032 return isStylePresent(editor, propertyID, onValue) ? TextDecorationChange::Remove : TextDecorationChange::Add; 1033 } 1034 1061 1035 static bool executeStrikethrough(Frame& frame, Event*, EditorCommandSource source, const String&) 1062 1036 { 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)); 1065 1041 } 1066 1042 … … 1126 1102 static bool executeUnderline(Frame& frame, Event*, EditorCommandSource source, const String&) 1127 1103 { 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)); 1130 1108 } 1131 1109 -
trunk/Source/WebKit/mac/ChangeLog
r183697 r183770 1 2015-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 1 11 2015-05-01 Martin Robinson <mrobinson@igalia.com> 2 12 -
trunk/Source/WebKit/mac/WebView/WebFrame.mm
r183172 r183770 942 942 // FIXME: We shouldn't have to create a copy here. 943 943 Ref<MutableStyleProperties> properties(core(style)->copyProperties()); 944 _private->coreFrame->editor().computeAndSetTypingStyle(properties. ptr(), undoAction);944 _private->coreFrame->editor().computeAndSetTypingStyle(properties.get(), undoAction); 945 945 } 946 946
Note: See TracChangeset
for help on using the changeset viewer.