f2b0104019d2ddf93ea2773721c000f8cd320f3a
[WebKit-https.git] / Source / WebCore / editing / EditingStyle.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2013 Apple Inc.
3  * Copyright (C) 2010, 2011 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "EditingStyle.h"
29
30 #include "ApplyStyleCommand.h"
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSParser.h"
33 #include "CSSRuleList.h"
34 #include "CSSStyleRule.h"
35 #include "CSSValueList.h"
36 #include "CSSValuePool.h"
37 #include "Editor.h"
38 #include "Frame.h"
39 #include "HTMLFontElement.h"
40 #include "HTMLInterchange.h"
41 #include "HTMLNames.h"
42 #include "Node.h"
43 #include "NodeTraversal.h"
44 #include "QualifiedName.h"
45 #include "RenderStyle.h"
46 #include "StyleFontSizeFunctions.h"
47 #include "StyleProperties.h"
48 #include "StyleResolver.h"
49 #include "StyleRule.h"
50 #include "StyledElement.h"
51 #include "VisibleUnits.h"
52 #include "htmlediting.h"
53
54 namespace WebCore {
55
56 // Editing style properties must be preserved during editing operation.
57 // e.g. when a user inserts a new paragraph, all properties listed here must be copied to the new paragraph.
58 static const CSSPropertyID editingProperties[] = {
59     CSSPropertyColor,
60     CSSPropertyFontFamily,
61     CSSPropertyFontSize,
62     CSSPropertyFontStyle,
63     CSSPropertyFontVariant,
64     CSSPropertyFontWeight,
65     CSSPropertyLetterSpacing,
66     CSSPropertyLineHeight,
67     CSSPropertyOrphans,
68     CSSPropertyTextAlign,
69     CSSPropertyTextIndent,
70     CSSPropertyTextTransform,
71     CSSPropertyWhiteSpace,
72     CSSPropertyWidows,
73     CSSPropertyWordSpacing,
74 #if ENABLE(TOUCH_EVENTS)
75     CSSPropertyWebkitTapHighlightColor,
76 #endif
77     CSSPropertyWebkitTextDecorationsInEffect,
78     CSSPropertyWebkitTextFillColor,
79 #if ENABLE(IOS_TEXT_AUTOSIZING)
80     CSSPropertyWebkitTextSizeAdjust,
81 #endif
82     CSSPropertyWebkitTextStrokeColor,
83     CSSPropertyWebkitTextStrokeWidth,
84
85     // Non-inheritable properties
86     CSSPropertyBackgroundColor,
87     CSSPropertyTextDecoration,
88 };
89
90 const unsigned numAllEditingProperties = WTF_ARRAY_LENGTH(editingProperties);
91 const unsigned numInheritableEditingProperties = numAllEditingProperties - 2;
92
93 enum EditingPropertiesToInclude { OnlyInheritableEditingProperties, AllEditingProperties };
94 template <class StyleDeclarationType>
95 static PassRefPtr<MutableStyleProperties> copyEditingProperties(StyleDeclarationType* style, EditingPropertiesToInclude type)
96 {
97     if (type == AllEditingProperties)
98         return style->copyPropertiesInSet(editingProperties, numAllEditingProperties);
99     return style->copyPropertiesInSet(editingProperties, numInheritableEditingProperties);
100 }
101
102 static inline bool isEditingProperty(int id)
103 {
104     for (size_t i = 0; i < WTF_ARRAY_LENGTH(editingProperties); ++i) {
105         if (editingProperties[i] == id)
106             return true;
107     }
108     return false;
109 }
110
111 static PassRefPtr<MutableStyleProperties> copyPropertiesFromComputedStyle(ComputedStyleExtractor& computedStyle, EditingStyle::PropertiesToInclude propertiesToInclude)
112 {
113     switch (propertiesToInclude) {
114     case EditingStyle::AllProperties:
115         return computedStyle.copyProperties();
116     case EditingStyle::OnlyEditingInheritableProperties:
117         return copyEditingProperties(&computedStyle, OnlyInheritableEditingProperties);
118     case EditingStyle::EditingPropertiesInEffect:
119         return copyEditingProperties(&computedStyle, AllEditingProperties);
120     }
121     ASSERT_NOT_REACHED();
122     return 0;
123 }
124
125 static PassRefPtr<MutableStyleProperties> copyPropertiesFromComputedStyle(Node* node, EditingStyle::PropertiesToInclude propertiesToInclude)
126 {
127     ComputedStyleExtractor computedStyle(node);
128     return copyPropertiesFromComputedStyle(computedStyle, propertiesToInclude);
129 }
130
131 static PassRefPtr<CSSValue> extractPropertyValue(const StyleProperties& style, CSSPropertyID propertyID)
132 {
133     return style.getPropertyCSSValue(propertyID);
134 }
135
136 static PassRefPtr<CSSValue> extractPropertyValue(ComputedStyleExtractor& computedStyle, CSSPropertyID propertyID)
137 {
138     return computedStyle.propertyValue(propertyID);
139 }
140
141 template<typename T>
142 int identifierForStyleProperty(T& style, CSSPropertyID propertyID)
143 {
144     RefPtr<CSSValue> value = extractPropertyValue(style, propertyID);
145     if (!is<CSSPrimitiveValue>(value.get()))
146         return 0;
147     return downcast<CSSPrimitiveValue>(*value).getValueID();
148 }
149
150 template<typename T> PassRefPtr<MutableStyleProperties> getPropertiesNotIn(StyleProperties& styleWithRedundantProperties, T& baseStyle);
151 enum LegacyFontSizeMode { AlwaysUseLegacyFontSize, UseLegacyFontSizeOnlyIfPixelValuesMatch };
152 static int legacyFontSizeFromCSSValue(Document*, CSSPrimitiveValue*, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode);
153 static bool isTransparentColorValue(CSSValue*);
154 static bool hasTransparentBackgroundColor(StyleProperties*);
155 static PassRefPtr<CSSValue> backgroundColorInEffect(Node*);
156
157 class HTMLElementEquivalent {
158     WTF_MAKE_FAST_ALLOCATED;
159 public:
160     HTMLElementEquivalent(CSSPropertyID, CSSValueID primitiveValue, const QualifiedName& tagName);
161
162     virtual ~HTMLElementEquivalent() { }
163     virtual bool matches(const Element& element) const { return !m_tagName || element.hasTagName(*m_tagName); }
164     virtual bool hasAttribute() const { return false; }
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     virtual void addToStyle(Element*, EditingStyle*) const;
168
169 protected:
170     HTMLElementEquivalent(CSSPropertyID);
171     HTMLElementEquivalent(CSSPropertyID, const QualifiedName& tagName);
172     const CSSPropertyID m_propertyID;
173     const RefPtr<CSSPrimitiveValue> m_primitiveValue;
174     const QualifiedName* m_tagName; // We can store a pointer because HTML tag names are const global.
175 };
176
177 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id)
178     : m_propertyID(id)
179     , m_tagName(0)
180 {
181 }
182
183 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, const QualifiedName& tagName)
184     : m_propertyID(id)
185     , m_tagName(&tagName)
186 {
187 }
188
189 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, CSSValueID primitiveValue, const QualifiedName& tagName)
190     : m_propertyID(id)
191     , m_primitiveValue(CSSPrimitiveValue::createIdentifier(primitiveValue))
192     , m_tagName(&tagName)
193 {
194     ASSERT(primitiveValue != CSSValueInvalid);
195 }
196
197 bool HTMLElementEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const
198 {
199     RefPtr<CSSValue> value = style.m_mutableStyle->getPropertyCSSValue(m_propertyID);
200     return matches(element) && is<CSSPrimitiveValue>(value.get()) && downcast<CSSPrimitiveValue>(*value).getValueID() == m_primitiveValue->getValueID();
201 }
202
203 void HTMLElementEquivalent::addToStyle(Element*, EditingStyle* style) const
204 {
205     style->setProperty(m_propertyID, m_primitiveValue->cssText());
206 }
207
208 class HTMLTextDecorationEquivalent : public HTMLElementEquivalent {
209 public:
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;
249 };
250
251 class HTMLAttributeEquivalent : public HTMLElementEquivalent {
252 public:
253     HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& tagName, const QualifiedName& attrName);
254     HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName);
255
256     bool matches(const Element& element) const { return HTMLElementEquivalent::matches(element) && element.hasAttribute(m_attrName); }
257     virtual bool hasAttribute() const { return true; }
258     virtual bool valueIsPresentInStyle(Element&, const EditingStyle&) const;
259     virtual void addToStyle(Element*, EditingStyle*) const;
260     virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
261     inline const QualifiedName& attributeName() const { return m_attrName; }
262
263 protected:
264     const QualifiedName& m_attrName; // We can store a reference because HTML attribute names are const global.
265 };
266
267 HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& tagName, const QualifiedName& attrName)
268     : HTMLElementEquivalent(id, tagName)
269     , m_attrName(attrName)
270 {
271 }
272
273 HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& attrName)
274     : HTMLElementEquivalent(id)
275     , m_attrName(attrName)
276 {
277 }
278
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);
283     
284     return compareCSSValuePtr(value, styleValue);
285 }
286
287 void HTMLAttributeEquivalent::addToStyle(Element* element, EditingStyle* style) const
288 {
289     if (RefPtr<CSSValue> value = attributeValueAsCSSValue(element))
290         style->setProperty(m_propertyID, value->cssText());
291 }
292
293 PassRefPtr<CSSValue> HTMLAttributeEquivalent::attributeValueAsCSSValue(Element* element) const
294 {
295     ASSERT(element);
296     const AtomicString& value = element->getAttribute(m_attrName);
297     if (value.isNull())
298         return nullptr;
299     
300     RefPtr<MutableStyleProperties> dummyStyle;
301     dummyStyle = MutableStyleProperties::create();
302     dummyStyle->setProperty(m_propertyID, value);
303     return dummyStyle->getPropertyCSSValue(m_propertyID);
304 }
305
306 class HTMLFontSizeEquivalent : public HTMLAttributeEquivalent {
307 public:
308     HTMLFontSizeEquivalent();
309
310     virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
311 };
312
313 HTMLFontSizeEquivalent::HTMLFontSizeEquivalent()
314     : HTMLAttributeEquivalent(CSSPropertyFontSize, HTMLNames::fontTag, HTMLNames::sizeAttr)
315 {
316 }
317
318 PassRefPtr<CSSValue> HTMLFontSizeEquivalent::attributeValueAsCSSValue(Element* element) const
319 {
320     ASSERT(element);
321     const AtomicString& value = element->getAttribute(m_attrName);
322     if (value.isNull())
323         return nullptr;
324     CSSValueID size;
325     if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
326         return nullptr;
327     return CSSPrimitiveValue::createIdentifier(size);
328 }
329
330 float EditingStyle::NoFontDelta = 0.0f;
331
332 EditingStyle::EditingStyle()
333     : m_shouldUseFixedDefaultFontSize(false)
334     , m_underlineChange(static_cast<unsigned>(TextDecorationChange::None))
335     , m_strikeThroughChange(static_cast<unsigned>(TextDecorationChange::None))
336 {
337 }
338
339 EditingStyle::EditingStyle(Node* node, PropertiesToInclude propertiesToInclude)
340     : EditingStyle()
341 {
342     init(node, propertiesToInclude);
343 }
344
345 EditingStyle::EditingStyle(const Position& position, PropertiesToInclude propertiesToInclude)
346     : EditingStyle()
347 {
348     init(position.deprecatedNode(), propertiesToInclude);
349 }
350
351 EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
352     : EditingStyle()
353 {
354     if (style)
355         m_mutableStyle = style->copyProperties();
356     extractFontSizeDelta();
357 }
358
359 EditingStyle::EditingStyle(const StyleProperties* style)
360     : EditingStyle()
361 {
362     if (style)
363         m_mutableStyle = style->mutableCopy();
364     extractFontSizeDelta();
365 }
366
367 EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value)
368     : EditingStyle()
369 {
370     setProperty(propertyID, value);
371     extractFontSizeDelta();
372 }
373
374 EditingStyle::EditingStyle(CSSPropertyID propertyID, CSSValueID value)
375     : EditingStyle()
376 {
377     m_mutableStyle = MutableStyleProperties::create();
378     m_mutableStyle->setProperty(propertyID, value);
379     extractFontSizeDelta();
380 }
381
382 EditingStyle::~EditingStyle()
383 {
384 }
385
386 static RGBA32 cssValueToRGBA(CSSValue* colorValue)
387 {
388     if (!is<CSSPrimitiveValue>(colorValue))
389         return Color::transparent;
390     
391     CSSPrimitiveValue& primitiveColor = downcast<CSSPrimitiveValue>(*colorValue);
392     if (primitiveColor.isRGBColor())
393         return primitiveColor.getRGBA32Value();
394     
395     RGBA32 rgba = 0;
396     CSSParser::parseColor(rgba, colorValue->cssText());
397     return rgba;
398 }
399
400 template<typename T>
401 static inline RGBA32 textColorFromStyle(T& style)
402 {
403     return cssValueToRGBA(extractPropertyValue(style, CSSPropertyColor).get());
404 }
405
406 template<typename T>
407 static inline RGBA32 backgroundColorFromStyle(T& style)
408 {
409     return cssValueToRGBA(extractPropertyValue(style, CSSPropertyBackgroundColor).get());
410 }
411
412 static inline RGBA32 rgbaBackgroundColorInEffect(Node* node)
413 {
414     return cssValueToRGBA(backgroundColorInEffect(node).get());
415 }
416
417 static int textAlignResolvingStartAndEnd(int textAlign, int direction)
418 {
419     switch (textAlign) {
420     case CSSValueCenter:
421     case CSSValueWebkitCenter:
422         return CSSValueCenter;
423     case CSSValueJustify:
424         return CSSValueJustify;
425     case CSSValueLeft:
426     case CSSValueWebkitLeft:
427         return CSSValueLeft;
428     case CSSValueRight:
429     case CSSValueWebkitRight:
430         return CSSValueRight;
431     case CSSValueStart:
432         return direction != CSSValueRtl ? CSSValueLeft : CSSValueRight;
433     case CSSValueEnd:
434         return direction == CSSValueRtl ? CSSValueRight : CSSValueLeft;
435     }
436     return CSSValueInvalid;
437 }
438
439 template<typename T>
440 static int textAlignResolvingStartAndEnd(T& style)
441 {
442     return textAlignResolvingStartAndEnd(identifierForStyleProperty(style, CSSPropertyTextAlign), identifierForStyleProperty(style, CSSPropertyDirection));
443 }
444
445 void EditingStyle::init(Node* node, PropertiesToInclude propertiesToInclude)
446 {
447     if (isTabSpanTextNode(node))
448         node = tabSpanNode(node)->parentNode();
449     else if (isTabSpanNode(node))
450         node = node->parentNode();
451
452     ComputedStyleExtractor computedStyleAtPosition(node);
453     // FIXME: It's strange to not set background-color and text-decoration when propertiesToInclude is EditingPropertiesInEffect.
454     // However editing/selection/contains-boundaries.html fails without this ternary.
455     m_mutableStyle = copyPropertiesFromComputedStyle(computedStyleAtPosition,
456         propertiesToInclude == EditingPropertiesInEffect ? OnlyEditingInheritableProperties : propertiesToInclude);
457
458     if (propertiesToInclude == EditingPropertiesInEffect) {
459         if (RefPtr<CSSValue> value = backgroundColorInEffect(node))
460             m_mutableStyle->setProperty(CSSPropertyBackgroundColor, value->cssText());
461         if (RefPtr<CSSValue> value = computedStyleAtPosition.propertyValue(CSSPropertyWebkitTextDecorationsInEffect))
462             m_mutableStyle->setProperty(CSSPropertyTextDecoration, value->cssText());
463     }
464
465     if (node && node->computedStyle()) {
466         RenderStyle* renderStyle = node->computedStyle();
467         removeTextFillAndStrokeColorsIfNeeded(renderStyle);
468         if (renderStyle->fontDescription().keywordSize())
469             m_mutableStyle->setProperty(CSSPropertyFontSize, computedStyleAtPosition.getFontSizeCSSValuePreferringKeyword()->cssText());
470     }
471
472     m_shouldUseFixedDefaultFontSize = computedStyleAtPosition.useFixedFontDefaultSize();
473     extractFontSizeDelta();
474 }
475
476 void EditingStyle::removeTextFillAndStrokeColorsIfNeeded(RenderStyle* renderStyle)
477 {
478     // If a node's text fill color is invalid, then its children use 
479     // their font-color as their text fill color (they don't
480     // inherit it).  Likewise for stroke color.
481     if (!renderStyle->textFillColor().isValid())
482         m_mutableStyle->removeProperty(CSSPropertyWebkitTextFillColor);
483     if (!renderStyle->textStrokeColor().isValid())
484         m_mutableStyle->removeProperty(CSSPropertyWebkitTextStrokeColor);
485 }
486
487 void EditingStyle::setProperty(CSSPropertyID propertyID, const String& value, bool important)
488 {
489     if (!m_mutableStyle)
490         m_mutableStyle = MutableStyleProperties::create();
491
492     m_mutableStyle->setProperty(propertyID, value, important);
493 }
494
495 void EditingStyle::extractFontSizeDelta()
496 {
497     if (!m_mutableStyle)
498         return;
499
500     if (m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize)) {
501         // Explicit font size overrides any delta.
502         m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
503         return;
504     }
505
506     // Get the adjustment amount out of the style.
507     RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitFontSizeDelta);
508     if (!is<CSSPrimitiveValue>(value.get()))
509         return;
510
511     CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(*value);
512
513     // Only PX handled now. If we handle more types in the future, perhaps
514     // a switch statement here would be more appropriate.
515     if (!primitiveValue.isPx())
516         return;
517
518     m_fontSizeDelta = primitiveValue.getFloatValue();
519     m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
520 }
521
522 bool EditingStyle::isEmpty() const
523 {
524     return (!m_mutableStyle || m_mutableStyle->isEmpty()) && m_fontSizeDelta == NoFontDelta
525         && underlineChange() == TextDecorationChange::None && strikeThroughChange() == TextDecorationChange::None;
526 }
527
528 bool EditingStyle::textDirection(WritingDirection& writingDirection) const
529 {
530     if (!m_mutableStyle)
531         return false;
532
533     RefPtr<CSSValue> unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
534     if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
535         return false;
536
537     CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
538     if (unicodeBidiValue == CSSValueEmbed) {
539         RefPtr<CSSValue> direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
540         if (!is<CSSPrimitiveValue>(direction.get()))
541             return false;
542
543         writingDirection = downcast<CSSPrimitiveValue>(*direction).getValueID() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
544
545         return true;
546     }
547
548     if (unicodeBidiValue == CSSValueNormal) {
549         writingDirection = NaturalWritingDirection;
550         return true;
551     }
552
553     return false;
554 }
555
556 void EditingStyle::setStyle(PassRefPtr<MutableStyleProperties> style)
557 {
558     m_mutableStyle = style;
559     // FIXME: We should be able to figure out whether or not font is fixed width for mutable style.
560     // We need to check font-family is monospace as in FontDescription but we don't want to duplicate code here.
561     m_shouldUseFixedDefaultFontSize = false;
562     extractFontSizeDelta();
563 }
564
565 void EditingStyle::overrideWithStyle(const StyleProperties* style)
566 {
567     return mergeStyle(style, OverrideValues);
568 }
569
570 static void applyTextDecorationChangeToValueList(CSSValueList& valueList, TextDecorationChange change, Ref<CSSPrimitiveValue>&& value)
571 {
572     switch (change) {
573     case TextDecorationChange::None:
574         break;
575     case TextDecorationChange::Add:
576         valueList.append(WTF::move(value));
577         break;
578     case TextDecorationChange::Remove:
579         valueList.removeAll(&value.get());
580         break;
581     }
582 }
583
584 void EditingStyle::overrideTypingStyleAt(const EditingStyle& style, const Position& position)
585 {
586     mergeStyle(style.m_mutableStyle.get(), OverrideValues);
587
588     m_fontSizeDelta += style.m_fontSizeDelta;
589
590     prepareToApplyAt(position, EditingStyle::PreserveWritingDirection);
591
592     auto underlineChange = style.underlineChange();
593     auto strikeThroughChange = style.strikeThroughChange();
594     if (underlineChange == TextDecorationChange::None && strikeThroughChange == TextDecorationChange::None)
595         return;
596
597     if (!m_mutableStyle)
598         m_mutableStyle = MutableStyleProperties::create();
599
600     Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
601     Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
602     RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
603     RefPtr<CSSValueList> valueList;
604     if (value && value->isValueList()) {
605         valueList = downcast<CSSValueList>(*value).copy();
606         applyTextDecorationChangeToValueList(*valueList, underlineChange, WTF::move(underline));
607         applyTextDecorationChangeToValueList(*valueList, strikeThroughChange, WTF::move(lineThrough));
608     } else {
609         valueList = CSSValueList::createSpaceSeparated();
610         if (underlineChange == TextDecorationChange::Add)
611             valueList->append(WTF::move(underline));
612         if (strikeThroughChange == TextDecorationChange::Add)
613             valueList->append(WTF::move(lineThrough));
614     }
615     m_mutableStyle->setProperty(CSSPropertyWebkitTextDecorationsInEffect, valueList.get());
616 }
617
618 void EditingStyle::clear()
619 {
620     m_mutableStyle.clear();
621     m_shouldUseFixedDefaultFontSize = false;
622     m_fontSizeDelta = NoFontDelta;
623     setUnderlineChange(TextDecorationChange::None);
624     setStrikeThroughChange(TextDecorationChange::None);
625 }
626
627 PassRefPtr<EditingStyle> EditingStyle::copy() const
628 {
629     RefPtr<EditingStyle> copy = EditingStyle::create();
630     if (m_mutableStyle)
631         copy->m_mutableStyle = m_mutableStyle->mutableCopy();
632     copy->m_shouldUseFixedDefaultFontSize = m_shouldUseFixedDefaultFontSize;
633     copy->m_underlineChange = m_underlineChange;
634     copy->m_strikeThroughChange = m_strikeThroughChange;
635     copy->m_fontSizeDelta = m_fontSizeDelta;
636     return copy;
637 }
638
639 PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveBlockProperties()
640 {
641     RefPtr<EditingStyle> blockProperties = EditingStyle::create();
642     if (!m_mutableStyle)
643         return blockProperties;
644
645     blockProperties->m_mutableStyle = m_mutableStyle->copyBlockProperties();
646     m_mutableStyle->removeBlockProperties();
647
648     return blockProperties;
649 }
650
651 PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveTextDirection()
652 {
653     RefPtr<EditingStyle> textDirection = EditingStyle::create();
654     textDirection->m_mutableStyle = MutableStyleProperties::create();
655     textDirection->m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed, m_mutableStyle->propertyIsImportant(CSSPropertyUnicodeBidi));
656     textDirection->m_mutableStyle->setProperty(CSSPropertyDirection, m_mutableStyle->getPropertyValue(CSSPropertyDirection),
657         m_mutableStyle->propertyIsImportant(CSSPropertyDirection));
658
659     m_mutableStyle->removeProperty(CSSPropertyUnicodeBidi);
660     m_mutableStyle->removeProperty(CSSPropertyDirection);
661
662     return textDirection;
663 }
664
665 void EditingStyle::removeBlockProperties()
666 {
667     if (!m_mutableStyle)
668         return;
669
670     m_mutableStyle->removeBlockProperties();
671 }
672
673 void EditingStyle::removeStyleAddedByNode(Node* node)
674 {
675     if (!node || !node->parentNode())
676         return;
677     RefPtr<MutableStyleProperties> parentStyle = copyPropertiesFromComputedStyle(node->parentNode(), EditingPropertiesInEffect);
678     RefPtr<MutableStyleProperties> nodeStyle = copyPropertiesFromComputedStyle(node, EditingPropertiesInEffect);
679     removeEquivalentProperties(*parentStyle);
680     removeEquivalentProperties(*nodeStyle);
681 }
682
683 void EditingStyle::removeStyleConflictingWithStyleOfNode(Node* node)
684 {
685     if (!node || !node->parentNode() || !m_mutableStyle)
686         return;
687
688     RefPtr<MutableStyleProperties> parentStyle = copyPropertiesFromComputedStyle(node->parentNode(), EditingPropertiesInEffect);
689     RefPtr<EditingStyle> nodeStyle = EditingStyle::create(node, EditingPropertiesInEffect);
690     nodeStyle->removeEquivalentProperties(*parentStyle);
691
692     MutableStyleProperties* style = nodeStyle->style();
693     unsigned propertyCount = style->propertyCount();
694     for (unsigned i = 0; i < propertyCount; ++i)
695         m_mutableStyle->removeProperty(style->propertyAt(i).id());
696 }
697
698 void EditingStyle::collapseTextDecorationProperties()
699 {
700     if (!m_mutableStyle)
701         return;
702
703     RefPtr<CSSValue> textDecorationsInEffect = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
704     if (!textDecorationsInEffect)
705         return;
706
707     if (textDecorationsInEffect->isValueList())
708         m_mutableStyle->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText(), m_mutableStyle->propertyIsImportant(CSSPropertyTextDecoration));
709     else
710         m_mutableStyle->removeProperty(CSSPropertyTextDecoration);
711     m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
712 }
713
714 // CSS properties that create a visual difference only when applied to text.
715 static const CSSPropertyID textOnlyProperties[] = {
716     CSSPropertyTextDecoration,
717     CSSPropertyWebkitTextDecorationsInEffect,
718     CSSPropertyFontStyle,
719     CSSPropertyFontWeight,
720     CSSPropertyColor,
721 };
722
723 TriState EditingStyle::triStateOfStyle(EditingStyle* style) const
724 {
725     if (!style || !style->m_mutableStyle)
726         return FalseTriState;
727     return triStateOfStyle(*style->m_mutableStyle, DoNotIgnoreTextOnlyProperties);
728 }
729
730 template<typename T>
731 TriState EditingStyle::triStateOfStyle(T& styleToCompare, ShouldIgnoreTextOnlyProperties shouldIgnoreTextOnlyProperties) const
732 {
733     if (!m_mutableStyle)
734         return TrueTriState;
735
736     RefPtr<MutableStyleProperties> difference = getPropertiesNotIn(*m_mutableStyle, styleToCompare);
737
738     if (shouldIgnoreTextOnlyProperties == IgnoreTextOnlyProperties)
739         difference->removePropertiesInSet(textOnlyProperties, WTF_ARRAY_LENGTH(textOnlyProperties));
740
741     if (difference->isEmpty())
742         return TrueTriState;
743     if (difference->propertyCount() == m_mutableStyle->propertyCount())
744         return FalseTriState;
745
746     return MixedTriState;
747 }
748
749 TriState EditingStyle::triStateOfStyle(const VisibleSelection& selection) const
750 {
751     if (!selection.isCaretOrRange())
752         return FalseTriState;
753
754     if (selection.isCaret())
755         return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection).get());
756
757     TriState state = FalseTriState;
758     bool nodeIsStart = true;
759     for (Node* node = selection.start().deprecatedNode(); node; node = NodeTraversal::next(*node)) {
760         if (node->renderer() && node->hasEditableStyle()) {
761             ComputedStyleExtractor computedStyle(node);
762             TriState nodeState = triStateOfStyle(computedStyle, node->isTextNode() ? EditingStyle::DoNotIgnoreTextOnlyProperties : EditingStyle::IgnoreTextOnlyProperties);
763             if (nodeIsStart) {
764                 state = nodeState;
765                 nodeIsStart = false;
766             } else if (state != nodeState && node->isTextNode()) {
767                 state = MixedTriState;
768                 break;
769             }
770         }
771
772         if (node == selection.end().deprecatedNode())
773             break;
774     }
775
776     return state;
777 }
778
779 static RefPtr<CSSValueList> textDecorationValueList(const StyleProperties& properties)
780 {
781     RefPtr<CSSValue> value = properties.getPropertyCSSValue(CSSPropertyTextDecoration);
782     if (!is<CSSValueList>(value.get()))
783         return nullptr;
784     return downcast<CSSValueList>(value.get());
785 }
786
787 bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr<MutableStyleProperties>* newInlineStylePtr, EditingStyle* extractedStyle) const
788 {
789     ASSERT(element);
790
791     const StyleProperties* inlineStyle = element->inlineStyle();
792     if (!inlineStyle)
793         return false;
794     bool conflicts = false;
795     RefPtr<MutableStyleProperties> newInlineStyle;
796     if (newInlineStylePtr) {
797         newInlineStyle = inlineStyle->mutableCopy();
798         *newInlineStylePtr = newInlineStyle;
799     }
800
801     bool shouldRemoveUnderline = underlineChange() == TextDecorationChange::Remove;
802     bool shouldRemoveStrikeThrough = strikeThroughChange() == TextDecorationChange::Remove;
803     if (shouldRemoveUnderline || shouldRemoveStrikeThrough) {
804         if (RefPtr<CSSValueList> valueList = textDecorationValueList(*inlineStyle)) {
805             RefPtr<CSSValueList> newValueList = valueList->copy();
806             RefPtr<CSSValueList> extractedValueList = CSSValueList::createSpaceSeparated();
807
808             Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
809             if (shouldRemoveUnderline && valueList->hasValue(underline.ptr())) {
810                 if (!newInlineStyle)
811                     return true;
812                 newValueList->removeAll(underline.ptr());
813                 extractedValueList->append(WTF::move(underline));
814             }
815
816             Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
817             if (shouldRemoveStrikeThrough && valueList->hasValue(lineThrough.ptr())) {
818                 if (!newInlineStyle)
819                     return true;
820                 newValueList->removeAll(lineThrough.ptr());
821                 extractedValueList->append(WTF::move(lineThrough));
822             }
823
824             if (extractedValueList->length()) {
825                 conflicts = true;
826                 if (newValueList->length())
827                     newInlineStyle->setProperty(CSSPropertyTextDecoration, newValueList);
828                 else
829                     newInlineStyle->removeProperty(CSSPropertyTextDecoration);
830
831                 if (extractedStyle) {
832                     bool isImportant = inlineStyle->propertyIsImportant(CSSPropertyTextDecoration);
833                     extractedStyle->setProperty(CSSPropertyTextDecoration, extractedValueList->cssText(), isImportant);
834                 }
835             }
836         }
837     }
838
839     unsigned propertyCount = m_mutableStyle ? m_mutableStyle->propertyCount() : 0;
840     for (unsigned i = 0; i < propertyCount; ++i) {
841         CSSPropertyID propertyID = m_mutableStyle->propertyAt(i).id();
842
843         // We don't override whitespace property of a tab span because that would collapse the tab into a space.
844         if (propertyID == CSSPropertyWhiteSpace && isTabSpanNode(element))
845             continue;
846
847         if (propertyID == CSSPropertyWebkitTextDecorationsInEffect && inlineStyle->getPropertyCSSValue(CSSPropertyTextDecoration)) {
848             if (!newInlineStyle)
849                 return true;
850             conflicts = true;
851             newInlineStyle->removeProperty(CSSPropertyTextDecoration);
852             if (extractedStyle)
853                 extractedStyle->setProperty(CSSPropertyTextDecoration, inlineStyle->getPropertyValue(CSSPropertyTextDecoration), inlineStyle->propertyIsImportant(CSSPropertyTextDecoration));
854         }
855
856         if (!inlineStyle->getPropertyCSSValue(propertyID))
857             continue;
858
859         if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) {
860             if (!newInlineStyle)
861                 return true;
862             conflicts = true;
863             newInlineStyle->removeProperty(CSSPropertyDirection);
864             if (extractedStyle)
865                 extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
866         }
867
868         if (!newInlineStyle)
869             return true;
870
871         conflicts = true;
872         newInlineStyle->removeProperty(propertyID);
873         if (extractedStyle)
874             extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
875     }
876
877     return conflicts;
878 }
879
880 static const Vector<std::unique_ptr<HTMLElementEquivalent>>& htmlElementEquivalents()
881 {
882     static NeverDestroyed<Vector<std::unique_ptr<HTMLElementEquivalent>>> HTMLElementEquivalents;
883
884     if (!HTMLElementEquivalents.get().size()) {
885         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontWeight, CSSValueBold, HTMLNames::bTag));
886         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontWeight, CSSValueBold, HTMLNames::strongTag));
887         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyVerticalAlign, CSSValueSub, HTMLNames::subTag));
888         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyVerticalAlign, CSSValueSuper, HTMLNames::supTag));
889         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::iTag));
890         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::emTag));
891
892         HTMLElementEquivalents.get().append(std::make_unique<HTMLTextDecorationEquivalent>(CSSValueUnderline, HTMLNames::uTag));
893         HTMLElementEquivalents.get().append(std::make_unique<HTMLTextDecorationEquivalent>(CSSValueLineThrough, HTMLNames::sTag));
894         HTMLElementEquivalents.get().append(std::make_unique<HTMLTextDecorationEquivalent>(CSSValueLineThrough, HTMLNames::strikeTag));
895     }
896
897     return HTMLElementEquivalents;
898 }
899
900
901 bool EditingStyle::conflictsWithImplicitStyleOfElement(HTMLElement* element, EditingStyle* extractedStyle, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
902 {
903     if (isEmpty())
904         return false;
905
906     const Vector<std::unique_ptr<HTMLElementEquivalent>>& HTMLElementEquivalents = htmlElementEquivalents();
907     for (auto& equivalent : HTMLElementEquivalents) {
908         if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this)
909             && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(*element, *this))) {
910             if (extractedStyle)
911                 equivalent->addToStyle(element, extractedStyle);
912             return true;
913         }
914     }
915     return false;
916 }
917
918 static const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& htmlAttributeEquivalents()
919 {
920     static NeverDestroyed<Vector<std::unique_ptr<HTMLAttributeEquivalent>>> HTMLAttributeEquivalents;
921
922     if (!HTMLAttributeEquivalents.get().size()) {
923         // elementIsStyledSpanOrHTMLEquivalent depends on the fact each HTMLAttriuteEquivalent matches exactly one attribute
924         // of exactly one element except dirAttr.
925         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyColor, HTMLNames::fontTag, HTMLNames::colorAttr));
926         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyFontFamily, HTMLNames::fontTag, HTMLNames::faceAttr));
927         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLFontSizeEquivalent>());
928
929         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyDirection, HTMLNames::dirAttr));
930         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyUnicodeBidi, HTMLNames::dirAttr));
931     }
932
933     return HTMLAttributeEquivalents;
934 }
935
936 bool EditingStyle::conflictsWithImplicitStyleOfAttributes(HTMLElement* element) const
937 {
938     ASSERT(element);
939     if (isEmpty())
940         return false;
941
942     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
943     for (auto& equivalent : HTMLAttributeEquivalents) {
944         if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this) && !equivalent->valueIsPresentInStyle(*element, *this))
945             return true;
946     }
947
948     return false;
949 }
950
951 bool EditingStyle::extractConflictingImplicitStyleOfAttributes(HTMLElement* element, ShouldPreserveWritingDirection shouldPreserveWritingDirection,
952     EditingStyle* extractedStyle, Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
953 {
954     ASSERT(element);
955     // HTMLAttributeEquivalent::addToStyle doesn't support unicode-bidi and direction properties
956     ASSERT(!extractedStyle || shouldPreserveWritingDirection == PreserveWritingDirection);
957     if (!m_mutableStyle)
958         return false;
959
960     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
961     bool removed = false;
962     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
963         const HTMLAttributeEquivalent* equivalent = HTMLAttributeEquivalents[i].get();
964
965         // unicode-bidi and direction are pushed down separately so don't push down with other styles.
966         if (shouldPreserveWritingDirection == PreserveWritingDirection && equivalent->attributeName() == HTMLNames::dirAttr)
967             continue;
968
969         if (!equivalent->matches(*element) || !equivalent->propertyExistsInStyle(*this)
970             || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(*element, *this)))
971             continue;
972
973         if (extractedStyle)
974             equivalent->addToStyle(element, extractedStyle);
975         conflictingAttributes.append(equivalent->attributeName());
976         removed = true;
977     }
978
979     return removed;
980 }
981
982 bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const
983 {
984     if (isEmpty())
985         return true;
986     ComputedStyleExtractor computedStyle(node);
987
988     bool shouldAddUnderline = underlineChange() == TextDecorationChange::Add;
989     bool shouldAddLineThrough = strikeThroughChange() == TextDecorationChange::Add;
990     if (shouldAddUnderline || shouldAddLineThrough) {
991         bool hasUnderline = false;
992         bool hasLineThrough = false;
993         if (RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyTextDecoration)) {
994             if (value->isValueList()) {
995                 const CSSValueList& valueList = downcast<CSSValueList>(*value);
996                 hasUnderline = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueUnderline).get());
997                 hasLineThrough = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueLineThrough).get());
998             }
999         }
1000         if ((shouldAddUnderline && !hasUnderline) || (shouldAddLineThrough && !hasLineThrough))
1001             return false;
1002     }
1003
1004     return !m_mutableStyle || getPropertiesNotIn(*m_mutableStyle, computedStyle)->isEmpty();
1005 }
1006
1007 bool EditingStyle::elementIsStyledSpanOrHTMLEquivalent(const HTMLElement* element)
1008 {
1009     bool elementIsSpanOrElementEquivalent = false;
1010     if (element->hasTagName(HTMLNames::spanTag))
1011         elementIsSpanOrElementEquivalent = true;
1012     else {
1013         const Vector<std::unique_ptr<HTMLElementEquivalent>>& HTMLElementEquivalents = htmlElementEquivalents();
1014         size_t i;
1015         for (i = 0; i < HTMLElementEquivalents.size(); ++i) {
1016             if (HTMLElementEquivalents[i]->matches(*element)) {
1017                 elementIsSpanOrElementEquivalent = true;
1018                 break;
1019             }
1020         }
1021     }
1022
1023     if (!element->hasAttributes())
1024         return elementIsSpanOrElementEquivalent; // span, b, etc... without any attributes
1025
1026     unsigned matchedAttributes = 0;
1027     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
1028     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
1029         if (HTMLAttributeEquivalents[i]->matches(*element) && HTMLAttributeEquivalents[i]->attributeName() != HTMLNames::dirAttr)
1030             matchedAttributes++;
1031     }
1032
1033     if (!elementIsSpanOrElementEquivalent && !matchedAttributes)
1034         return false; // element is not a span, a html element equivalent, or font element.
1035     
1036     if (element->getAttribute(HTMLNames::classAttr) == AppleStyleSpanClass)
1037         matchedAttributes++;
1038
1039     if (element->hasAttribute(HTMLNames::styleAttr)) {
1040         if (const StyleProperties* style = element->inlineStyle()) {
1041             unsigned propertyCount = style->propertyCount();
1042             for (unsigned i = 0; i < propertyCount; ++i) {
1043                 if (!isEditingProperty(style->propertyAt(i).id()))
1044                     return false;
1045             }
1046         }
1047         matchedAttributes++;
1048     }
1049
1050     // font with color attribute, span with style attribute, etc...
1051     ASSERT(matchedAttributes <= element->attributeCount());
1052     return matchedAttributes >= element->attributeCount();
1053 }
1054
1055 void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
1056 {
1057     if (!m_mutableStyle)
1058         return;
1059
1060     // ReplaceSelectionCommand::handleStyleSpans() requires that this function only removes the editing style.
1061     // If this function was modified in the future to delete all redundant properties, then add a boolean value to indicate
1062     // which one of editingStyleAtPosition or computedStyle is called.
1063     RefPtr<EditingStyle> editingStyleAtPosition = EditingStyle::create(position, EditingPropertiesInEffect);
1064     StyleProperties* styleAtPosition = editingStyleAtPosition->m_mutableStyle.get();
1065
1066     RefPtr<CSSValue> unicodeBidi;
1067     RefPtr<CSSValue> direction;
1068     if (shouldPreserveWritingDirection == PreserveWritingDirection) {
1069         unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
1070         direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
1071     }
1072
1073     removeEquivalentProperties(*styleAtPosition);
1074
1075     if (textAlignResolvingStartAndEnd(*m_mutableStyle) == textAlignResolvingStartAndEnd(*styleAtPosition))
1076         m_mutableStyle->removeProperty(CSSPropertyTextAlign);
1077
1078     if (textColorFromStyle(*m_mutableStyle) == textColorFromStyle(*styleAtPosition))
1079         m_mutableStyle->removeProperty(CSSPropertyColor);
1080
1081     if (hasTransparentBackgroundColor(m_mutableStyle.get())
1082         || cssValueToRGBA(m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor).get()) == rgbaBackgroundColorInEffect(position.containerNode()))
1083         m_mutableStyle->removeProperty(CSSPropertyBackgroundColor);
1084
1085     if (is<CSSPrimitiveValue>(unicodeBidi.get())) {
1086         m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSValueID>(downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID()));
1087         if (is<CSSPrimitiveValue>(direction.get()))
1088             m_mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSValueID>(downcast<CSSPrimitiveValue>(*direction).getValueID()));
1089     }
1090 }
1091
1092 void EditingStyle::mergeTypingStyle(Document& document)
1093 {
1094     RefPtr<EditingStyle> typingStyle = document.frame()->selection().typingStyle();
1095     if (!typingStyle || typingStyle == this)
1096         return;
1097
1098     mergeStyle(typingStyle->style(), OverrideValues);
1099 }
1100
1101 void EditingStyle::mergeInlineStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
1102 {
1103     ASSERT(element);
1104     if (!element->inlineStyle())
1105         return;
1106
1107     switch (propertiesToInclude) {
1108     case AllProperties:
1109         mergeStyle(element->inlineStyle(), mode);
1110         return;
1111     case OnlyEditingInheritableProperties:
1112         mergeStyle(copyEditingProperties(element->inlineStyle(), OnlyInheritableEditingProperties).get(), mode);
1113         return;
1114     case EditingPropertiesInEffect:
1115         mergeStyle(copyEditingProperties(element->inlineStyle(), AllEditingProperties).get(), mode);
1116         return;
1117     }
1118 }
1119
1120 static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl(const HTMLElementEquivalent* equivalent, const StyledElement* element,
1121     EditingStyle::CSSPropertyOverrideMode mode, EditingStyle& style)
1122 {
1123     if (!equivalent->matches(*element))
1124         return false;
1125     if (mode != EditingStyle::OverrideValues && equivalent->propertyExistsInStyle(style))
1126         return false;
1127
1128     return !element->inlineStyle() || !equivalent->propertyExistsInStyle(EditingStyle::create(element->inlineStyle()).get());
1129 }
1130
1131 static PassRefPtr<MutableStyleProperties> extractEditingProperties(const StyleProperties* style, EditingStyle::PropertiesToInclude propertiesToInclude)
1132 {
1133     if (!style)
1134         return 0;
1135
1136     switch (propertiesToInclude) {
1137     case EditingStyle::AllProperties:
1138     case EditingStyle::EditingPropertiesInEffect:
1139         return copyEditingProperties(style, AllEditingProperties);
1140     case EditingStyle::OnlyEditingInheritableProperties:
1141         return copyEditingProperties(style, OnlyInheritableEditingProperties);
1142     }
1143
1144     ASSERT_NOT_REACHED();
1145     return 0;
1146 }
1147
1148 void EditingStyle::mergeInlineAndImplicitStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
1149 {
1150     RefPtr<EditingStyle> styleFromRules = EditingStyle::create();
1151     styleFromRules->mergeStyleFromRulesForSerialization(element);
1152
1153     if (element->inlineStyle())
1154         styleFromRules->m_mutableStyle->mergeAndOverrideOnConflict(*element->inlineStyle());
1155
1156     styleFromRules->m_mutableStyle = extractEditingProperties(styleFromRules->m_mutableStyle.get(), propertiesToInclude);
1157     mergeStyle(styleFromRules->m_mutableStyle.get(), mode);
1158
1159     const Vector<std::unique_ptr<HTMLElementEquivalent>>& elementEquivalents = htmlElementEquivalents();
1160     for (size_t i = 0; i < elementEquivalents.size(); ++i) {
1161         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(elementEquivalents[i].get(), element, mode, *this))
1162             elementEquivalents[i]->addToStyle(element, this);
1163     }
1164
1165     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& attributeEquivalents = htmlAttributeEquivalents();
1166     for (size_t i = 0; i < attributeEquivalents.size(); ++i) {
1167         if (attributeEquivalents[i]->attributeName() == HTMLNames::dirAttr)
1168             continue; // We don't want to include directionality
1169         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(attributeEquivalents[i].get(), element, mode, *this))
1170             attributeEquivalents[i]->addToStyle(element, this);
1171     }
1172 }
1173
1174 PassRefPtr<EditingStyle> EditingStyle::wrappingStyleForSerialization(Node* context, bool shouldAnnotate)
1175 {
1176     RefPtr<EditingStyle> wrappingStyle;
1177     if (shouldAnnotate) {
1178         wrappingStyle = EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect);
1179
1180         // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote,
1181         // to help us differentiate those styles from ones that the user has applied.
1182         // This helps us get the color of content pasted into blockquotes right.
1183         wrappingStyle->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInOrBeforeNode(context), isMailBlockquote, CanCrossEditingBoundary));
1184
1185         // Call collapseTextDecorationProperties first or otherwise it'll copy the value over from in-effect to text-decorations.
1186         wrappingStyle->collapseTextDecorationProperties();
1187         
1188         return wrappingStyle.release();
1189     }
1190
1191     wrappingStyle = EditingStyle::create();
1192
1193     // When not annotating for interchange, we only preserve inline style declarations.
1194     for (Node* node = context; node && !node->isDocumentNode(); node = node->parentNode()) {
1195         if (is<StyledElement>(*node) && !isMailBlockquote(node)) {
1196             wrappingStyle->mergeInlineAndImplicitStyleOfElement(downcast<StyledElement>(node), EditingStyle::DoNotOverrideValues,
1197                 EditingStyle::EditingPropertiesInEffect);
1198         }
1199     }
1200
1201     return wrappingStyle.release();
1202 }
1203
1204
1205 static void mergeTextDecorationValues(CSSValueList& mergedValue, const CSSValueList& valueToMerge)
1206 {
1207     Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
1208     Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
1209
1210     if (valueToMerge.hasValue(underline.ptr()) && !mergedValue.hasValue(underline.ptr()))
1211         mergedValue.append(WTF::move(underline));
1212
1213     if (valueToMerge.hasValue(lineThrough.ptr()) && !mergedValue.hasValue(lineThrough.ptr()))
1214         mergedValue.append(WTF::move(lineThrough));
1215 }
1216
1217 void EditingStyle::mergeStyle(const StyleProperties* style, CSSPropertyOverrideMode mode)
1218 {
1219     if (!style)
1220         return;
1221
1222     if (!m_mutableStyle) {
1223         m_mutableStyle = style->mutableCopy();
1224         return;
1225     }
1226
1227     unsigned propertyCount = style->propertyCount();
1228     for (unsigned i = 0; i < propertyCount; ++i) {
1229         StyleProperties::PropertyReference property = style->propertyAt(i);
1230         RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(property.id());
1231
1232         // text decorations never override values.
1233         if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect)
1234             && is<CSSValueList>(*property.value()) && value) {
1235             if (is<CSSValueList>(*value)) {
1236                 RefPtr<CSSValueList> newValue = downcast<CSSValueList>(*value).copy();
1237                 mergeTextDecorationValues(*newValue, downcast<CSSValueList>(*property.value()));
1238                 m_mutableStyle->setProperty(property.id(), newValue.release(), property.isImportant());
1239                 continue;
1240             }
1241             value = nullptr; // text-decoration: none is equivalent to not having the property.
1242         }
1243
1244         if (mode == OverrideValues || (mode == DoNotOverrideValues && !value))
1245             m_mutableStyle->setProperty(property.id(), property.value(), property.isImportant());
1246     }
1247
1248     int oldFontSizeDelta = m_fontSizeDelta;
1249     extractFontSizeDelta();
1250     m_fontSizeDelta += oldFontSizeDelta;
1251 }
1252
1253 static PassRefPtr<MutableStyleProperties> styleFromMatchedRulesForElement(Element* element, unsigned rulesToInclude)
1254 {
1255     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
1256     auto matchedRules = element->document().ensureStyleResolver().styleRulesForElement(element, rulesToInclude);
1257     for (unsigned i = 0; i < matchedRules.size(); ++i) {
1258         if (matchedRules[i]->isStyleRule())
1259             style->mergeAndOverrideOnConflict(static_pointer_cast<StyleRule>(matchedRules[i])->properties());
1260     }
1261     
1262     return style.release();
1263 }
1264
1265 void EditingStyle::mergeStyleFromRules(StyledElement* element)
1266 {
1267     RefPtr<MutableStyleProperties> styleFromMatchedRules = styleFromMatchedRulesForElement(element,
1268         StyleResolver::AuthorCSSRules | StyleResolver::CrossOriginCSSRules);
1269     // Styles from the inline style declaration, held in the variable "style", take precedence 
1270     // over those from matched rules.
1271     if (m_mutableStyle)
1272         styleFromMatchedRules->mergeAndOverrideOnConflict(*m_mutableStyle);
1273
1274     clear();
1275     m_mutableStyle = styleFromMatchedRules;
1276 }
1277
1278 void EditingStyle::mergeStyleFromRulesForSerialization(StyledElement* element)
1279 {
1280     mergeStyleFromRules(element);
1281
1282     // The property value, if it's a percentage, may not reflect the actual computed value.  
1283     // For example: style="height: 1%; overflow: visible;" in quirksmode
1284     // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot copy/paste fidelity problem
1285     RefPtr<MutableStyleProperties> fromComputedStyle = MutableStyleProperties::create();
1286     ComputedStyleExtractor computedStyle(element);
1287
1288     {
1289         unsigned propertyCount = m_mutableStyle->propertyCount();
1290         for (unsigned i = 0; i < propertyCount; ++i) {
1291             StyleProperties::PropertyReference property = m_mutableStyle->propertyAt(i);
1292             CSSValue* value = property.value();
1293             if (!is<CSSPrimitiveValue>(*value))
1294                 continue;
1295             if (downcast<CSSPrimitiveValue>(*value).isPercentage()) {
1296                 if (RefPtr<CSSValue> computedPropertyValue = computedStyle.propertyValue(property.id()))
1297                     fromComputedStyle->addParsedProperty(CSSProperty(property.id(), computedPropertyValue.release()));
1298             }
1299         }
1300     }
1301     m_mutableStyle->mergeAndOverrideOnConflict(*fromComputedStyle);
1302 }
1303
1304 static void removePropertiesInStyle(MutableStyleProperties* styleToRemovePropertiesFrom, MutableStyleProperties* style)
1305 {
1306     unsigned propertyCount = style->propertyCount();
1307     Vector<CSSPropertyID> propertiesToRemove(propertyCount);
1308     for (unsigned i = 0; i < propertyCount; ++i)
1309         propertiesToRemove[i] = style->propertyAt(i).id();
1310
1311     styleToRemovePropertiesFrom->removePropertiesInSet(propertiesToRemove.data(), propertiesToRemove.size());
1312 }
1313
1314 void EditingStyle::removeStyleFromRulesAndContext(StyledElement* element, Node* context)
1315 {
1316     ASSERT(element);
1317     if (!m_mutableStyle)
1318         return;
1319
1320     // 1. Remove style from matched rules because style remain without repeating it in inline style declaration
1321     RefPtr<MutableStyleProperties> styleFromMatchedRules = styleFromMatchedRulesForElement(element, StyleResolver::AllButEmptyCSSRules);
1322     if (styleFromMatchedRules && !styleFromMatchedRules->isEmpty())
1323         m_mutableStyle = getPropertiesNotIn(*m_mutableStyle, *styleFromMatchedRules);
1324
1325     // 2. Remove style present in context and not overriden by matched rules.
1326     RefPtr<EditingStyle> computedStyle = EditingStyle::create(context, EditingPropertiesInEffect);
1327     if (computedStyle->m_mutableStyle) {
1328         if (!computedStyle->m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor))
1329             computedStyle->m_mutableStyle->setProperty(CSSPropertyBackgroundColor, CSSValueTransparent);
1330
1331         removePropertiesInStyle(computedStyle->m_mutableStyle.get(), styleFromMatchedRules.get());
1332         m_mutableStyle = getPropertiesNotIn(*m_mutableStyle, *computedStyle->m_mutableStyle);
1333     }
1334
1335     // 3. If this element is a span and has display: inline or float: none, remove them unless they are overriden by rules.
1336     // These rules are added by serialization code to wrap text nodes.
1337     if (isStyleSpanOrSpanWithOnlyStyleAttribute(element)) {
1338         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyDisplay) && identifierForStyleProperty(*m_mutableStyle, CSSPropertyDisplay) == CSSValueInline)
1339             m_mutableStyle->removeProperty(CSSPropertyDisplay);
1340         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyFloat) && identifierForStyleProperty(*m_mutableStyle, CSSPropertyFloat) == CSSValueNone)
1341             m_mutableStyle->removeProperty(CSSPropertyFloat);
1342     }
1343 }
1344
1345 void EditingStyle::removePropertiesInElementDefaultStyle(Element* element)
1346 {
1347     if (!m_mutableStyle || m_mutableStyle->isEmpty())
1348         return;
1349
1350     RefPtr<MutableStyleProperties> defaultStyle = styleFromMatchedRulesForElement(element, StyleResolver::UAAndUserCSSRules);
1351
1352     removePropertiesInStyle(m_mutableStyle.get(), defaultStyle.get());
1353 }
1354
1355 template<typename T>
1356 void EditingStyle::removeEquivalentProperties(const T& style)
1357 {
1358     Vector<CSSPropertyID> propertiesToRemove;
1359     for (auto& property : m_mutableStyle->m_propertyVector) {
1360         if (style.propertyMatches(property.id(), property.value()))
1361             propertiesToRemove.append(property.id());
1362     }
1363     // FIXME: This should use mass removal.
1364     for (auto& property : propertiesToRemove)
1365         m_mutableStyle->removeProperty(property);
1366 }
1367
1368 void EditingStyle::forceInline()
1369 {
1370     if (!m_mutableStyle)
1371         m_mutableStyle = MutableStyleProperties::create();
1372     const bool propertyIsImportant = true;
1373     m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline, propertyIsImportant);
1374 }
1375
1376 bool EditingStyle::convertPositionStyle()
1377 {
1378     if (!m_mutableStyle)
1379         return false;
1380
1381     RefPtr<CSSPrimitiveValue> sticky = cssValuePool().createIdentifierValue(CSSValueWebkitSticky);
1382     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, sticky.get())) {
1383         m_mutableStyle->setProperty(CSSPropertyPosition, cssValuePool().createIdentifierValue(CSSValueStatic), m_mutableStyle->propertyIsImportant(CSSPropertyPosition));
1384         return false;
1385     }
1386     RefPtr<CSSPrimitiveValue> fixed = cssValuePool().createIdentifierValue(CSSValueFixed);
1387     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, fixed.get())) {
1388         m_mutableStyle->setProperty(CSSPropertyPosition, cssValuePool().createIdentifierValue(CSSValueAbsolute), m_mutableStyle->propertyIsImportant(CSSPropertyPosition));
1389         return true;
1390     }
1391     RefPtr<CSSPrimitiveValue> absolute = cssValuePool().createIdentifierValue(CSSValueAbsolute);
1392     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, absolute.get()))
1393         return true;
1394     return false;
1395 }
1396
1397 bool EditingStyle::isFloating()
1398 {
1399     RefPtr<CSSValue> v = m_mutableStyle->getPropertyCSSValue(CSSPropertyFloat);
1400     RefPtr<CSSPrimitiveValue> noneValue = cssValuePool().createIdentifierValue(CSSValueNone);
1401     return v && !v->equals(*noneValue);
1402 }
1403
1404 int EditingStyle::legacyFontSize(Document* document) const
1405 {
1406     RefPtr<CSSValue> cssValue = m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize);
1407     if (!is<CSSPrimitiveValue>(cssValue.get()))
1408         return 0;
1409     return legacyFontSizeFromCSSValue(document, downcast<CSSPrimitiveValue>(cssValue.get()),
1410         m_shouldUseFixedDefaultFontSize, AlwaysUseLegacyFontSize);
1411 }
1412
1413 PassRefPtr<EditingStyle> EditingStyle::styleAtSelectionStart(const VisibleSelection& selection, bool shouldUseBackgroundColorInEffect)
1414 {
1415     if (selection.isNone())
1416         return 0;
1417
1418     Position position = adjustedSelectionStartForStyleComputation(selection);
1419
1420     // If the pos is at the end of a text node, then this node is not fully selected. 
1421     // Move it to the next deep equivalent position to avoid removing the style from this node. 
1422     // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we want Position("world", 0) instead. 
1423     // We only do this for range because caret at Position("hello", 5) in <b>hello</b>world should give you font-weight: bold. 
1424     Node* positionNode = position.containerNode(); 
1425     if (selection.isRange() && positionNode && positionNode->isTextNode() && position.computeOffsetInContainerNode() == positionNode->maxCharacterOffset()) 
1426         position = nextVisuallyDistinctCandidate(position); 
1427
1428     Element* element = position.element();
1429     if (!element)
1430         return 0;
1431
1432     RefPtr<EditingStyle> style = EditingStyle::create(element, EditingStyle::AllProperties);
1433     style->mergeTypingStyle(element->document());
1434
1435     // If background color is transparent, traverse parent nodes until we hit a different value or document root
1436     // Also, if the selection is a range, ignore the background color at the start of selection,
1437     // and find the background color of the common ancestor.
1438     if (shouldUseBackgroundColorInEffect && (selection.isRange() || hasTransparentBackgroundColor(style->m_mutableStyle.get()))) {
1439         RefPtr<Range> range(selection.toNormalizedRange());
1440         if (PassRefPtr<CSSValue> value = backgroundColorInEffect(range->commonAncestorContainer(IGNORE_EXCEPTION)))
1441             style->setProperty(CSSPropertyBackgroundColor, value->cssText());
1442     }
1443
1444     return style;
1445 }
1446
1447 WritingDirection EditingStyle::textDirectionForSelection(const VisibleSelection& selection, EditingStyle* typingStyle, bool& hasNestedOrMultipleEmbeddings)
1448 {
1449     hasNestedOrMultipleEmbeddings = true;
1450
1451     if (selection.isNone())
1452         return NaturalWritingDirection;
1453
1454     Position position = selection.start().downstream();
1455
1456     Node* node = position.deprecatedNode();
1457     if (!node)
1458         return NaturalWritingDirection;
1459
1460     Position end;
1461     if (selection.isRange()) {
1462         end = selection.end().upstream();
1463
1464         Node* pastLast = Range::create(*end.document(), position.parentAnchoredEquivalent(), end.parentAnchoredEquivalent())->pastLastNode();
1465         for (Node* n = node; n && n != pastLast; n = NodeTraversal::next(*n)) {
1466             if (!n->isStyledElement())
1467                 continue;
1468
1469             RefPtr<CSSValue> unicodeBidi = ComputedStyleExtractor(n).propertyValue(CSSPropertyUnicodeBidi);
1470             if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
1471                 continue;
1472
1473             CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
1474             if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride)
1475                 return NaturalWritingDirection;
1476         }
1477     }
1478
1479     if (selection.isCaret()) {
1480         WritingDirection direction;
1481         if (typingStyle && typingStyle->textDirection(direction)) {
1482             hasNestedOrMultipleEmbeddings = false;
1483             return direction;
1484         }
1485         node = selection.visibleStart().deepEquivalent().deprecatedNode();
1486     }
1487
1488     // The selection is either a caret with no typing attributes or a range in which no embedding is added, so just use the start position
1489     // to decide.
1490     Node* block = enclosingBlock(node);
1491     WritingDirection foundDirection = NaturalWritingDirection;
1492
1493     for (; node != block; node = node->parentNode()) {
1494         if (!node->isStyledElement())
1495             continue;
1496
1497         ComputedStyleExtractor computedStyle(node);
1498         RefPtr<CSSValue> unicodeBidi = computedStyle.propertyValue(CSSPropertyUnicodeBidi);
1499         if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
1500             continue;
1501
1502         CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
1503         if (unicodeBidiValue == CSSValueNormal)
1504             continue;
1505
1506         if (unicodeBidiValue == CSSValueBidiOverride)
1507             return NaturalWritingDirection;
1508
1509         ASSERT(unicodeBidiValue == CSSValueEmbed);
1510         RefPtr<CSSValue> direction = computedStyle.propertyValue(CSSPropertyDirection);
1511         if (!is<CSSPrimitiveValue>(direction.get()))
1512             continue;
1513
1514         CSSValueID directionValue = downcast<CSSPrimitiveValue>(*direction).getValueID();
1515         if (directionValue != CSSValueLtr && directionValue != CSSValueRtl)
1516             continue;
1517
1518         if (foundDirection != NaturalWritingDirection)
1519             return NaturalWritingDirection;
1520
1521         // In the range case, make sure that the embedding element persists until the end of the range.
1522         if (selection.isRange() && !end.deprecatedNode()->isDescendantOf(node))
1523             return NaturalWritingDirection;
1524         
1525         foundDirection = directionValue == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
1526     }
1527     hasNestedOrMultipleEmbeddings = false;
1528     return foundDirection;
1529 }
1530
1531 static void reconcileTextDecorationProperties(MutableStyleProperties* style)
1532 {    
1533     RefPtr<CSSValue> textDecorationsInEffect = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
1534     RefPtr<CSSValue> textDecoration = style->getPropertyCSSValue(CSSPropertyTextDecoration);
1535     // We shouldn't have both text-decoration and -webkit-text-decorations-in-effect because that wouldn't make sense.
1536     ASSERT(!textDecorationsInEffect || !textDecoration);
1537     if (textDecorationsInEffect) {
1538         style->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText());
1539         style->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
1540         textDecoration = textDecorationsInEffect;
1541     }
1542
1543     // If text-decoration is set to "none", remove the property because we don't want to add redundant "text-decoration: none".
1544     if (textDecoration && !textDecoration->isValueList())
1545         style->removeProperty(CSSPropertyTextDecoration);
1546 }
1547
1548 StyleChange::StyleChange(EditingStyle* style, const Position& position)
1549     : m_applyBold(false)
1550     , m_applyItalic(false)
1551     , m_applyUnderline(false)
1552     , m_applyLineThrough(false)
1553     , m_applySubscript(false)
1554     , m_applySuperscript(false)
1555 {
1556     Document* document = position.deprecatedNode() ? &position.deprecatedNode()->document() : 0;
1557     if (!style || style->isEmpty() || !document || !document->frame())
1558         return;
1559
1560     Node* node = position.containerNode();
1561     if (!node)
1562         return;
1563
1564     ComputedStyleExtractor computedStyle(node);
1565
1566     // FIXME: take care of background-color in effect
1567     RefPtr<MutableStyleProperties> mutableStyle = style->style() ?
1568         getPropertiesNotIn(*style->style(), computedStyle) : MutableStyleProperties::create();
1569
1570     reconcileTextDecorationProperties(mutableStyle.get());
1571     bool shouldStyleWithCSS = document->frame()->editor().shouldStyleWithCSS();
1572     if (!shouldStyleWithCSS)
1573         extractTextStyles(document, *mutableStyle, computedStyle.useFixedFontDefaultSize());
1574
1575     bool shouldAddUnderline = style->underlineChange() == TextDecorationChange::Add;
1576     bool shouldAddStrikeThrough = style->strikeThroughChange() == TextDecorationChange::Add;
1577     if (shouldAddUnderline || shouldAddStrikeThrough) {
1578         RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyWebkitTextDecorationsInEffect);
1579         if (!is<CSSValueList>(value.get()))
1580             value = computedStyle.propertyValue(CSSPropertyTextDecoration);
1581
1582         RefPtr<CSSValueList> valueList;
1583         if (is<CSSValueList>(value.get()))
1584             valueList = downcast<CSSValueList>(value.get());
1585
1586         Ref<CSSValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
1587         bool hasUnderline = valueList && valueList->hasValue(underline.ptr());
1588
1589         Ref<CSSValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
1590         bool hasLineThrough = valueList && valueList->hasValue(lineThrough.ptr());
1591
1592         if (shouldStyleWithCSS) {
1593             valueList = valueList ? valueList->copy() : CSSValueList::createSpaceSeparated();
1594             if (shouldAddUnderline && !hasUnderline)
1595                 valueList->append(WTF::move(underline));
1596             if (shouldAddStrikeThrough && !hasLineThrough)
1597                 valueList->append(WTF::move(lineThrough));
1598             mutableStyle->setProperty(CSSPropertyTextDecoration, valueList.get());
1599         } else {
1600             m_applyUnderline = shouldAddUnderline && !hasUnderline;
1601             m_applyLineThrough = shouldAddStrikeThrough && !hasLineThrough;
1602         }
1603     }
1604
1605     // Changing the whitespace style in a tab span would collapse the tab into a space.
1606     if (isTabSpanTextNode(position.deprecatedNode()) || isTabSpanNode((position.deprecatedNode())))
1607         mutableStyle->removeProperty(CSSPropertyWhiteSpace);
1608
1609     // If unicode-bidi is present in mutableStyle and direction is not, then add direction to mutableStyle.
1610     // FIXME: Shouldn't this be done in getPropertiesNotIn?
1611     if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->style()->getPropertyCSSValue(CSSPropertyDirection))
1612         mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection));
1613
1614     if (!mutableStyle->isEmpty())
1615         m_cssStyle = mutableStyle;
1616 }
1617
1618 bool StyleChange::operator==(const StyleChange& other)
1619 {
1620     if (m_applyBold != other.m_applyBold
1621         || m_applyItalic != other.m_applyItalic
1622         || m_applyUnderline != other.m_applyUnderline
1623         || m_applyLineThrough != other.m_applyLineThrough
1624         || m_applySubscript != other.m_applySubscript
1625         || m_applySuperscript != other.m_applySuperscript
1626         || m_applyFontColor != other.m_applyFontColor
1627         || m_applyFontFace != other.m_applyFontFace
1628         || m_applyFontSize != other.m_applyFontSize)
1629         return false;
1630
1631     return (!m_cssStyle && !other.m_cssStyle)
1632         || (m_cssStyle && other.m_cssStyle && m_cssStyle->asText() == other.m_cssStyle->asText());
1633 }
1634
1635 static void setTextDecorationProperty(MutableStyleProperties& style, const CSSValueList* newTextDecoration, CSSPropertyID propertyID)
1636 {
1637     if (newTextDecoration->length())
1638         style.setProperty(propertyID, newTextDecoration->cssText(), style.propertyIsImportant(propertyID));
1639     else {
1640         // text-decoration: none is redundant since it does not remove any text decorations.
1641         style.removeProperty(propertyID);
1642     }
1643 }
1644
1645 void StyleChange::extractTextStyles(Document* document, MutableStyleProperties& style, bool shouldUseFixedFontDefaultSize)
1646 {
1647     if (identifierForStyleProperty(style, CSSPropertyFontWeight) == CSSValueBold) {
1648         style.removeProperty(CSSPropertyFontWeight);
1649         m_applyBold = true;
1650     }
1651
1652     int fontStyle = identifierForStyleProperty(style, CSSPropertyFontStyle);
1653     if (fontStyle == CSSValueItalic || fontStyle == CSSValueOblique) {
1654         style.removeProperty(CSSPropertyFontStyle);
1655         m_applyItalic = true;
1656     }
1657
1658     // Assuming reconcileTextDecorationProperties has been called, there should not be -webkit-text-decorations-in-effect
1659     // Furthermore, text-decoration: none has been trimmed so that text-decoration property is always a CSSValueList.
1660     RefPtr<CSSValue> textDecoration = style.getPropertyCSSValue(CSSPropertyTextDecoration);
1661     if (is<CSSValueList>(textDecoration.get())) {
1662         RefPtr<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
1663         RefPtr<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
1664
1665         RefPtr<CSSValueList> newTextDecoration = downcast<CSSValueList>(*textDecoration).copy();
1666         if (newTextDecoration->removeAll(underline.get()))
1667             m_applyUnderline = true;
1668         if (newTextDecoration->removeAll(lineThrough.get()))
1669             m_applyLineThrough = true;
1670
1671         // If trimTextDecorations, delete underline and line-through
1672         setTextDecorationProperty(style, newTextDecoration.get(), CSSPropertyTextDecoration);
1673     }
1674
1675     int verticalAlign = identifierForStyleProperty(style, CSSPropertyVerticalAlign);
1676     switch (verticalAlign) {
1677     case CSSValueSub:
1678         style.removeProperty(CSSPropertyVerticalAlign);
1679         m_applySubscript = true;
1680         break;
1681     case CSSValueSuper:
1682         style.removeProperty(CSSPropertyVerticalAlign);
1683         m_applySuperscript = true;
1684         break;
1685     }
1686
1687     if (style.getPropertyCSSValue(CSSPropertyColor)) {
1688         m_applyFontColor = Color(textColorFromStyle(style)).serialized();
1689         style.removeProperty(CSSPropertyColor);
1690     }
1691
1692     m_applyFontFace = style.getPropertyValue(CSSPropertyFontFamily);
1693     // Remove single quotes for Outlook 2007 compatibility. See https://bugs.webkit.org/show_bug.cgi?id=79448
1694     m_applyFontFace.replaceWithLiteral('\'', "");
1695     style.removeProperty(CSSPropertyFontFamily);
1696
1697     if (RefPtr<CSSValue> fontSize = style.getPropertyCSSValue(CSSPropertyFontSize)) {
1698         if (!is<CSSPrimitiveValue>(*fontSize))
1699             style.removeProperty(CSSPropertyFontSize); // Can't make sense of the number. Put no font size.
1700         else if (int legacyFontSize = legacyFontSizeFromCSSValue(document, downcast<CSSPrimitiveValue>(fontSize.get()),
1701                 shouldUseFixedFontDefaultSize, UseLegacyFontSizeOnlyIfPixelValuesMatch)) {
1702             m_applyFontSize = String::number(legacyFontSize);
1703             style.removeProperty(CSSPropertyFontSize);
1704         }
1705     }
1706 }
1707
1708 static void diffTextDecorations(MutableStyleProperties& style, CSSPropertyID propertID, CSSValue* refTextDecoration)
1709 {
1710     RefPtr<CSSValue> textDecoration = style.getPropertyCSSValue(propertID);
1711     if (!is<CSSValueList>(textDecoration.get()) || !is<CSSValueList>(refTextDecoration))
1712         return;
1713
1714     RefPtr<CSSValueList> newTextDecoration = downcast<CSSValueList>(*textDecoration).copy();
1715     CSSValueList& valuesInRefTextDecoration = downcast<CSSValueList>(*refTextDecoration);
1716
1717     for (size_t i = 0; i < valuesInRefTextDecoration.length(); ++i)
1718         newTextDecoration->removeAll(valuesInRefTextDecoration.item(i));
1719
1720     setTextDecorationProperty(style, newTextDecoration.get(), propertID);
1721 }
1722
1723 static bool fontWeightIsBold(CSSValue& fontWeight)
1724 {
1725     if (!is<CSSPrimitiveValue>(fontWeight))
1726         return false;
1727
1728     // Because b tag can only bold text, there are only two states in plain html: bold and not bold.
1729     // Collapse all other values to either one of these two states for editing purposes.
1730     switch (downcast<CSSPrimitiveValue>(fontWeight).getValueID()) {
1731         case CSSValue100:
1732         case CSSValue200:
1733         case CSSValue300:
1734         case CSSValue400:
1735         case CSSValue500:
1736         case CSSValueNormal:
1737             return false;
1738         case CSSValueBold:
1739         case CSSValue600:
1740         case CSSValue700:
1741         case CSSValue800:
1742         case CSSValue900:
1743             return true;
1744         default:
1745             break;
1746     }
1747
1748     ASSERT_NOT_REACHED(); // For CSSValueBolder and CSSValueLighter
1749     return false;
1750 }
1751
1752 template<typename T>
1753 static bool fontWeightIsBold(T& style)
1754 {
1755     RefPtr<CSSValue> fontWeight = extractPropertyValue(style, CSSPropertyFontWeight);
1756     return fontWeight && fontWeightIsBold(*fontWeight);
1757 }
1758
1759 template<typename T>
1760 static PassRefPtr<MutableStyleProperties> extractPropertiesNotIn(StyleProperties& styleWithRedundantProperties, T& baseStyle)
1761 {
1762     RefPtr<EditingStyle> result = EditingStyle::create(&styleWithRedundantProperties);
1763     result->removeEquivalentProperties(baseStyle);
1764     RefPtr<MutableStyleProperties> mutableStyle = result->style();
1765
1766     RefPtr<CSSValue> baseTextDecorationsInEffect = extractPropertyValue(baseStyle, CSSPropertyWebkitTextDecorationsInEffect);
1767     diffTextDecorations(*mutableStyle, CSSPropertyTextDecoration, baseTextDecorationsInEffect.get());
1768     diffTextDecorations(*mutableStyle, CSSPropertyWebkitTextDecorationsInEffect, baseTextDecorationsInEffect.get());
1769
1770     if (extractPropertyValue(baseStyle, CSSPropertyFontWeight) && fontWeightIsBold(*mutableStyle) == fontWeightIsBold(baseStyle))
1771         mutableStyle->removeProperty(CSSPropertyFontWeight);
1772
1773     if (extractPropertyValue(baseStyle, CSSPropertyColor) && textColorFromStyle(*mutableStyle) == textColorFromStyle(baseStyle))
1774         mutableStyle->removeProperty(CSSPropertyColor);
1775
1776     if (extractPropertyValue(baseStyle, CSSPropertyTextAlign)
1777         && textAlignResolvingStartAndEnd(*mutableStyle) == textAlignResolvingStartAndEnd(baseStyle))
1778         mutableStyle->removeProperty(CSSPropertyTextAlign);
1779
1780     if (extractPropertyValue(baseStyle, CSSPropertyBackgroundColor) && backgroundColorFromStyle(*mutableStyle) == backgroundColorFromStyle(baseStyle))
1781         mutableStyle->removeProperty(CSSPropertyBackgroundColor);
1782
1783     return mutableStyle.release();
1784 }
1785
1786 template<typename T>
1787 PassRefPtr<MutableStyleProperties> getPropertiesNotIn(StyleProperties& styleWithRedundantProperties, T& baseStyle)
1788 {
1789     return extractPropertiesNotIn(styleWithRedundantProperties, baseStyle);
1790 }
1791
1792 static bool isCSSValueLength(CSSPrimitiveValue* value)
1793 {
1794     return value->isFontIndependentLength();
1795 }
1796
1797 int legacyFontSizeFromCSSValue(Document* document, CSSPrimitiveValue* value, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode mode)
1798 {
1799     ASSERT(document); // FIXME: This method should take a Document&
1800
1801     if (isCSSValueLength(value)) {
1802         int pixelFontSize = value->getIntValue(CSSPrimitiveValue::CSS_PX);
1803         int legacyFontSize = Style::legacyFontSizeForPixelSize(pixelFontSize, shouldUseFixedFontDefaultSize, *document);
1804         // Use legacy font size only if pixel value matches exactly to that of legacy font size.
1805         int cssPrimitiveEquivalent = legacyFontSize - 1 + CSSValueXSmall;
1806         if (mode == AlwaysUseLegacyFontSize || Style::fontSizeForKeyword(cssPrimitiveEquivalent, shouldUseFixedFontDefaultSize, *document) == pixelFontSize)
1807             return legacyFontSize;
1808
1809         return 0;
1810     }
1811
1812     if (CSSValueXSmall <= value->getValueID() && value->getValueID() <= CSSValueWebkitXxxLarge)
1813         return value->getValueID() - CSSValueXSmall + 1;
1814
1815     return 0;
1816 }
1817
1818 bool isTransparentColorValue(CSSValue* cssValue)
1819 {
1820     if (!cssValue)
1821         return true;
1822     if (!is<CSSPrimitiveValue>(*cssValue))
1823         return false;
1824     CSSPrimitiveValue& value = downcast<CSSPrimitiveValue>(*cssValue);
1825     if (value.isRGBColor())
1826         return !alphaChannel(value.getRGBA32Value());
1827     return value.getValueID() == CSSValueTransparent;
1828 }
1829
1830 bool hasTransparentBackgroundColor(StyleProperties* style)
1831 {
1832     RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(CSSPropertyBackgroundColor);
1833     return isTransparentColorValue(cssValue.get());
1834 }
1835
1836 PassRefPtr<CSSValue> backgroundColorInEffect(Node* node)
1837 {
1838     for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) {
1839         if (RefPtr<CSSValue> value = ComputedStyleExtractor(ancestor).propertyValue(CSSPropertyBackgroundColor)) {
1840             if (!isTransparentColorValue(value.get()))
1841                 return value.release();
1842         }
1843     }
1844     return 0;
1845 }
1846
1847 }