REGRESSION(r183770): Crash inside WebEditorClient::shouldApplyStyle when applying...
[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 Ref<MutableStyleProperties> EditingStyle::styleWithResolvedTextDecorations() const
529 {
530     bool hasTextDecorationChanges = underlineChange() != TextDecorationChange::None || strikeThroughChange() != TextDecorationChange::None;
531     if (m_mutableStyle && !hasTextDecorationChanges)
532         return *m_mutableStyle;
533
534     Ref<MutableStyleProperties> style = m_mutableStyle ? m_mutableStyle->mutableCopy() : MutableStyleProperties::create();
535
536     Ref<CSSValueList> valueList = CSSValueList::createSpaceSeparated();
537     if (underlineChange() == TextDecorationChange::Add)
538         valueList->append(cssValuePool().createIdentifierValue(CSSValueUnderline));
539     if (strikeThroughChange() == TextDecorationChange::Add)
540         valueList->append(cssValuePool().createIdentifierValue(CSSValueLineThrough));
541
542     if (valueList->length())
543         style->setProperty(CSSPropertyTextDecoration, valueList.ptr());
544     else
545         style->setProperty(CSSPropertyTextDecoration, cssValuePool().createIdentifierValue(CSSValueNone));
546
547     return style;
548 }
549
550 bool EditingStyle::textDirection(WritingDirection& writingDirection) const
551 {
552     if (!m_mutableStyle)
553         return false;
554
555     RefPtr<CSSValue> unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
556     if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
557         return false;
558
559     CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
560     if (unicodeBidiValue == CSSValueEmbed) {
561         RefPtr<CSSValue> direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
562         if (!is<CSSPrimitiveValue>(direction.get()))
563             return false;
564
565         writingDirection = downcast<CSSPrimitiveValue>(*direction).getValueID() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
566
567         return true;
568     }
569
570     if (unicodeBidiValue == CSSValueNormal) {
571         writingDirection = NaturalWritingDirection;
572         return true;
573     }
574
575     return false;
576 }
577
578 void EditingStyle::setStyle(PassRefPtr<MutableStyleProperties> style)
579 {
580     m_mutableStyle = style;
581     // FIXME: We should be able to figure out whether or not font is fixed width for mutable style.
582     // We need to check font-family is monospace as in FontDescription but we don't want to duplicate code here.
583     m_shouldUseFixedDefaultFontSize = false;
584     extractFontSizeDelta();
585 }
586
587 void EditingStyle::overrideWithStyle(const StyleProperties* style)
588 {
589     return mergeStyle(style, OverrideValues);
590 }
591
592 static void applyTextDecorationChangeToValueList(CSSValueList& valueList, TextDecorationChange change, Ref<CSSPrimitiveValue>&& value)
593 {
594     switch (change) {
595     case TextDecorationChange::None:
596         break;
597     case TextDecorationChange::Add:
598         valueList.append(WTF::move(value));
599         break;
600     case TextDecorationChange::Remove:
601         valueList.removeAll(&value.get());
602         break;
603     }
604 }
605
606 void EditingStyle::overrideTypingStyleAt(const EditingStyle& style, const Position& position)
607 {
608     mergeStyle(style.m_mutableStyle.get(), OverrideValues);
609
610     m_fontSizeDelta += style.m_fontSizeDelta;
611
612     prepareToApplyAt(position, EditingStyle::PreserveWritingDirection);
613
614     auto underlineChange = style.underlineChange();
615     auto strikeThroughChange = style.strikeThroughChange();
616     if (underlineChange == TextDecorationChange::None && strikeThroughChange == TextDecorationChange::None)
617         return;
618
619     if (!m_mutableStyle)
620         m_mutableStyle = MutableStyleProperties::create();
621
622     Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
623     Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
624     RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
625     RefPtr<CSSValueList> valueList;
626     if (value && value->isValueList()) {
627         valueList = downcast<CSSValueList>(*value).copy();
628         applyTextDecorationChangeToValueList(*valueList, underlineChange, WTF::move(underline));
629         applyTextDecorationChangeToValueList(*valueList, strikeThroughChange, WTF::move(lineThrough));
630     } else {
631         valueList = CSSValueList::createSpaceSeparated();
632         if (underlineChange == TextDecorationChange::Add)
633             valueList->append(WTF::move(underline));
634         if (strikeThroughChange == TextDecorationChange::Add)
635             valueList->append(WTF::move(lineThrough));
636     }
637     m_mutableStyle->setProperty(CSSPropertyWebkitTextDecorationsInEffect, valueList.get());
638 }
639
640 void EditingStyle::clear()
641 {
642     m_mutableStyle.clear();
643     m_shouldUseFixedDefaultFontSize = false;
644     m_fontSizeDelta = NoFontDelta;
645     setUnderlineChange(TextDecorationChange::None);
646     setStrikeThroughChange(TextDecorationChange::None);
647 }
648
649 PassRefPtr<EditingStyle> EditingStyle::copy() const
650 {
651     RefPtr<EditingStyle> copy = EditingStyle::create();
652     if (m_mutableStyle)
653         copy->m_mutableStyle = m_mutableStyle->mutableCopy();
654     copy->m_shouldUseFixedDefaultFontSize = m_shouldUseFixedDefaultFontSize;
655     copy->m_underlineChange = m_underlineChange;
656     copy->m_strikeThroughChange = m_strikeThroughChange;
657     copy->m_fontSizeDelta = m_fontSizeDelta;
658     return copy;
659 }
660
661 PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveBlockProperties()
662 {
663     RefPtr<EditingStyle> blockProperties = EditingStyle::create();
664     if (!m_mutableStyle)
665         return blockProperties;
666
667     blockProperties->m_mutableStyle = m_mutableStyle->copyBlockProperties();
668     m_mutableStyle->removeBlockProperties();
669
670     return blockProperties;
671 }
672
673 PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveTextDirection()
674 {
675     RefPtr<EditingStyle> textDirection = EditingStyle::create();
676     textDirection->m_mutableStyle = MutableStyleProperties::create();
677     textDirection->m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed, m_mutableStyle->propertyIsImportant(CSSPropertyUnicodeBidi));
678     textDirection->m_mutableStyle->setProperty(CSSPropertyDirection, m_mutableStyle->getPropertyValue(CSSPropertyDirection),
679         m_mutableStyle->propertyIsImportant(CSSPropertyDirection));
680
681     m_mutableStyle->removeProperty(CSSPropertyUnicodeBidi);
682     m_mutableStyle->removeProperty(CSSPropertyDirection);
683
684     return textDirection;
685 }
686
687 void EditingStyle::removeBlockProperties()
688 {
689     if (!m_mutableStyle)
690         return;
691
692     m_mutableStyle->removeBlockProperties();
693 }
694
695 void EditingStyle::removeStyleAddedByNode(Node* node)
696 {
697     if (!node || !node->parentNode())
698         return;
699     RefPtr<MutableStyleProperties> parentStyle = copyPropertiesFromComputedStyle(node->parentNode(), EditingPropertiesInEffect);
700     RefPtr<MutableStyleProperties> nodeStyle = copyPropertiesFromComputedStyle(node, EditingPropertiesInEffect);
701     removeEquivalentProperties(*parentStyle);
702     removeEquivalentProperties(*nodeStyle);
703 }
704
705 void EditingStyle::removeStyleConflictingWithStyleOfNode(Node* node)
706 {
707     if (!node || !node->parentNode() || !m_mutableStyle)
708         return;
709
710     RefPtr<MutableStyleProperties> parentStyle = copyPropertiesFromComputedStyle(node->parentNode(), EditingPropertiesInEffect);
711     RefPtr<EditingStyle> nodeStyle = EditingStyle::create(node, EditingPropertiesInEffect);
712     nodeStyle->removeEquivalentProperties(*parentStyle);
713
714     MutableStyleProperties* style = nodeStyle->style();
715     unsigned propertyCount = style->propertyCount();
716     for (unsigned i = 0; i < propertyCount; ++i)
717         m_mutableStyle->removeProperty(style->propertyAt(i).id());
718 }
719
720 void EditingStyle::collapseTextDecorationProperties()
721 {
722     if (!m_mutableStyle)
723         return;
724
725     RefPtr<CSSValue> textDecorationsInEffect = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
726     if (!textDecorationsInEffect)
727         return;
728
729     if (textDecorationsInEffect->isValueList())
730         m_mutableStyle->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText(), m_mutableStyle->propertyIsImportant(CSSPropertyTextDecoration));
731     else
732         m_mutableStyle->removeProperty(CSSPropertyTextDecoration);
733     m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
734 }
735
736 // CSS properties that create a visual difference only when applied to text.
737 static const CSSPropertyID textOnlyProperties[] = {
738     CSSPropertyTextDecoration,
739     CSSPropertyWebkitTextDecorationsInEffect,
740     CSSPropertyFontStyle,
741     CSSPropertyFontWeight,
742     CSSPropertyColor,
743 };
744
745 TriState EditingStyle::triStateOfStyle(EditingStyle* style) const
746 {
747     if (!style || !style->m_mutableStyle)
748         return FalseTriState;
749     return triStateOfStyle(*style->m_mutableStyle, DoNotIgnoreTextOnlyProperties);
750 }
751
752 template<typename T>
753 TriState EditingStyle::triStateOfStyle(T& styleToCompare, ShouldIgnoreTextOnlyProperties shouldIgnoreTextOnlyProperties) const
754 {
755     if (!m_mutableStyle)
756         return TrueTriState;
757
758     RefPtr<MutableStyleProperties> difference = getPropertiesNotIn(*m_mutableStyle, styleToCompare);
759
760     if (shouldIgnoreTextOnlyProperties == IgnoreTextOnlyProperties)
761         difference->removePropertiesInSet(textOnlyProperties, WTF_ARRAY_LENGTH(textOnlyProperties));
762
763     if (difference->isEmpty())
764         return TrueTriState;
765     if (difference->propertyCount() == m_mutableStyle->propertyCount())
766         return FalseTriState;
767
768     return MixedTriState;
769 }
770
771 TriState EditingStyle::triStateOfStyle(const VisibleSelection& selection) const
772 {
773     if (!selection.isCaretOrRange())
774         return FalseTriState;
775
776     if (selection.isCaret())
777         return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection).get());
778
779     TriState state = FalseTriState;
780     bool nodeIsStart = true;
781     for (Node* node = selection.start().deprecatedNode(); node; node = NodeTraversal::next(*node)) {
782         if (node->renderer() && node->hasEditableStyle()) {
783             ComputedStyleExtractor computedStyle(node);
784             TriState nodeState = triStateOfStyle(computedStyle, node->isTextNode() ? EditingStyle::DoNotIgnoreTextOnlyProperties : EditingStyle::IgnoreTextOnlyProperties);
785             if (nodeIsStart) {
786                 state = nodeState;
787                 nodeIsStart = false;
788             } else if (state != nodeState && node->isTextNode()) {
789                 state = MixedTriState;
790                 break;
791             }
792         }
793
794         if (node == selection.end().deprecatedNode())
795             break;
796     }
797
798     return state;
799 }
800
801 static RefPtr<CSSValueList> textDecorationValueList(const StyleProperties& properties)
802 {
803     RefPtr<CSSValue> value = properties.getPropertyCSSValue(CSSPropertyTextDecoration);
804     if (!is<CSSValueList>(value.get()))
805         return nullptr;
806     return downcast<CSSValueList>(value.get());
807 }
808
809 bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, RefPtr<MutableStyleProperties>* newInlineStylePtr, EditingStyle* extractedStyle) const
810 {
811     ASSERT(element);
812
813     const StyleProperties* inlineStyle = element->inlineStyle();
814     if (!inlineStyle)
815         return false;
816     bool conflicts = false;
817     RefPtr<MutableStyleProperties> newInlineStyle;
818     if (newInlineStylePtr) {
819         newInlineStyle = inlineStyle->mutableCopy();
820         *newInlineStylePtr = newInlineStyle;
821     }
822
823     bool shouldRemoveUnderline = underlineChange() == TextDecorationChange::Remove;
824     bool shouldRemoveStrikeThrough = strikeThroughChange() == TextDecorationChange::Remove;
825     if (shouldRemoveUnderline || shouldRemoveStrikeThrough) {
826         if (RefPtr<CSSValueList> valueList = textDecorationValueList(*inlineStyle)) {
827             RefPtr<CSSValueList> newValueList = valueList->copy();
828             RefPtr<CSSValueList> extractedValueList = CSSValueList::createSpaceSeparated();
829
830             Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
831             if (shouldRemoveUnderline && valueList->hasValue(underline.ptr())) {
832                 if (!newInlineStyle)
833                     return true;
834                 newValueList->removeAll(underline.ptr());
835                 extractedValueList->append(WTF::move(underline));
836             }
837
838             Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
839             if (shouldRemoveStrikeThrough && valueList->hasValue(lineThrough.ptr())) {
840                 if (!newInlineStyle)
841                     return true;
842                 newValueList->removeAll(lineThrough.ptr());
843                 extractedValueList->append(WTF::move(lineThrough));
844             }
845
846             if (extractedValueList->length()) {
847                 conflicts = true;
848                 if (newValueList->length())
849                     newInlineStyle->setProperty(CSSPropertyTextDecoration, newValueList);
850                 else
851                     newInlineStyle->removeProperty(CSSPropertyTextDecoration);
852
853                 if (extractedStyle) {
854                     bool isImportant = inlineStyle->propertyIsImportant(CSSPropertyTextDecoration);
855                     extractedStyle->setProperty(CSSPropertyTextDecoration, extractedValueList->cssText(), isImportant);
856                 }
857             }
858         }
859     }
860
861     unsigned propertyCount = m_mutableStyle ? m_mutableStyle->propertyCount() : 0;
862     for (unsigned i = 0; i < propertyCount; ++i) {
863         CSSPropertyID propertyID = m_mutableStyle->propertyAt(i).id();
864
865         // We don't override whitespace property of a tab span because that would collapse the tab into a space.
866         if (propertyID == CSSPropertyWhiteSpace && isTabSpanNode(element))
867             continue;
868
869         if (propertyID == CSSPropertyWebkitTextDecorationsInEffect && inlineStyle->getPropertyCSSValue(CSSPropertyTextDecoration)) {
870             if (!newInlineStyle)
871                 return true;
872             conflicts = true;
873             newInlineStyle->removeProperty(CSSPropertyTextDecoration);
874             if (extractedStyle)
875                 extractedStyle->setProperty(CSSPropertyTextDecoration, inlineStyle->getPropertyValue(CSSPropertyTextDecoration), inlineStyle->propertyIsImportant(CSSPropertyTextDecoration));
876         }
877
878         if (!inlineStyle->getPropertyCSSValue(propertyID))
879             continue;
880
881         if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) {
882             if (!newInlineStyle)
883                 return true;
884             conflicts = true;
885             newInlineStyle->removeProperty(CSSPropertyDirection);
886             if (extractedStyle)
887                 extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
888         }
889
890         if (!newInlineStyle)
891             return true;
892
893         conflicts = true;
894         newInlineStyle->removeProperty(propertyID);
895         if (extractedStyle)
896             extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->propertyIsImportant(propertyID));
897     }
898
899     return conflicts;
900 }
901
902 static const Vector<std::unique_ptr<HTMLElementEquivalent>>& htmlElementEquivalents()
903 {
904     static NeverDestroyed<Vector<std::unique_ptr<HTMLElementEquivalent>>> HTMLElementEquivalents;
905
906     if (!HTMLElementEquivalents.get().size()) {
907         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontWeight, CSSValueBold, HTMLNames::bTag));
908         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontWeight, CSSValueBold, HTMLNames::strongTag));
909         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyVerticalAlign, CSSValueSub, HTMLNames::subTag));
910         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyVerticalAlign, CSSValueSuper, HTMLNames::supTag));
911         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::iTag));
912         HTMLElementEquivalents.get().append(std::make_unique<HTMLElementEquivalent>(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::emTag));
913
914         HTMLElementEquivalents.get().append(std::make_unique<HTMLTextDecorationEquivalent>(CSSValueUnderline, HTMLNames::uTag));
915         HTMLElementEquivalents.get().append(std::make_unique<HTMLTextDecorationEquivalent>(CSSValueLineThrough, HTMLNames::sTag));
916         HTMLElementEquivalents.get().append(std::make_unique<HTMLTextDecorationEquivalent>(CSSValueLineThrough, HTMLNames::strikeTag));
917     }
918
919     return HTMLElementEquivalents;
920 }
921
922
923 bool EditingStyle::conflictsWithImplicitStyleOfElement(HTMLElement* element, EditingStyle* extractedStyle, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
924 {
925     if (isEmpty())
926         return false;
927
928     const Vector<std::unique_ptr<HTMLElementEquivalent>>& HTMLElementEquivalents = htmlElementEquivalents();
929     for (auto& equivalent : HTMLElementEquivalents) {
930         if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this)
931             && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(*element, *this))) {
932             if (extractedStyle)
933                 equivalent->addToStyle(element, extractedStyle);
934             return true;
935         }
936     }
937     return false;
938 }
939
940 static const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& htmlAttributeEquivalents()
941 {
942     static NeverDestroyed<Vector<std::unique_ptr<HTMLAttributeEquivalent>>> HTMLAttributeEquivalents;
943
944     if (!HTMLAttributeEquivalents.get().size()) {
945         // elementIsStyledSpanOrHTMLEquivalent depends on the fact each HTMLAttriuteEquivalent matches exactly one attribute
946         // of exactly one element except dirAttr.
947         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyColor, HTMLNames::fontTag, HTMLNames::colorAttr));
948         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyFontFamily, HTMLNames::fontTag, HTMLNames::faceAttr));
949         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLFontSizeEquivalent>());
950
951         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyDirection, HTMLNames::dirAttr));
952         HTMLAttributeEquivalents.get().append(std::make_unique<HTMLAttributeEquivalent>(CSSPropertyUnicodeBidi, HTMLNames::dirAttr));
953     }
954
955     return HTMLAttributeEquivalents;
956 }
957
958 bool EditingStyle::conflictsWithImplicitStyleOfAttributes(HTMLElement* element) const
959 {
960     ASSERT(element);
961     if (isEmpty())
962         return false;
963
964     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
965     for (auto& equivalent : HTMLAttributeEquivalents) {
966         if (equivalent->matches(*element) && equivalent->propertyExistsInStyle(*this) && !equivalent->valueIsPresentInStyle(*element, *this))
967             return true;
968     }
969
970     return false;
971 }
972
973 bool EditingStyle::extractConflictingImplicitStyleOfAttributes(HTMLElement* element, ShouldPreserveWritingDirection shouldPreserveWritingDirection,
974     EditingStyle* extractedStyle, Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
975 {
976     ASSERT(element);
977     // HTMLAttributeEquivalent::addToStyle doesn't support unicode-bidi and direction properties
978     ASSERT(!extractedStyle || shouldPreserveWritingDirection == PreserveWritingDirection);
979     if (!m_mutableStyle)
980         return false;
981
982     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
983     bool removed = false;
984     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
985         const HTMLAttributeEquivalent* equivalent = HTMLAttributeEquivalents[i].get();
986
987         // unicode-bidi and direction are pushed down separately so don't push down with other styles.
988         if (shouldPreserveWritingDirection == PreserveWritingDirection && equivalent->attributeName() == HTMLNames::dirAttr)
989             continue;
990
991         if (!equivalent->matches(*element) || !equivalent->propertyExistsInStyle(*this)
992             || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(*element, *this)))
993             continue;
994
995         if (extractedStyle)
996             equivalent->addToStyle(element, extractedStyle);
997         conflictingAttributes.append(equivalent->attributeName());
998         removed = true;
999     }
1000
1001     return removed;
1002 }
1003
1004 bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const
1005 {
1006     if (isEmpty())
1007         return true;
1008     ComputedStyleExtractor computedStyle(node);
1009
1010     bool shouldAddUnderline = underlineChange() == TextDecorationChange::Add;
1011     bool shouldAddLineThrough = strikeThroughChange() == TextDecorationChange::Add;
1012     if (shouldAddUnderline || shouldAddLineThrough) {
1013         bool hasUnderline = false;
1014         bool hasLineThrough = false;
1015         if (RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyTextDecoration)) {
1016             if (value->isValueList()) {
1017                 const CSSValueList& valueList = downcast<CSSValueList>(*value);
1018                 hasUnderline = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueUnderline).get());
1019                 hasLineThrough = valueList.hasValue(&cssValuePool().createIdentifierValue(CSSValueLineThrough).get());
1020             }
1021         }
1022         if ((shouldAddUnderline && !hasUnderline) || (shouldAddLineThrough && !hasLineThrough))
1023             return false;
1024     }
1025
1026     return !m_mutableStyle || getPropertiesNotIn(*m_mutableStyle, computedStyle)->isEmpty();
1027 }
1028
1029 bool EditingStyle::elementIsStyledSpanOrHTMLEquivalent(const HTMLElement* element)
1030 {
1031     bool elementIsSpanOrElementEquivalent = false;
1032     if (element->hasTagName(HTMLNames::spanTag))
1033         elementIsSpanOrElementEquivalent = true;
1034     else {
1035         const Vector<std::unique_ptr<HTMLElementEquivalent>>& HTMLElementEquivalents = htmlElementEquivalents();
1036         size_t i;
1037         for (i = 0; i < HTMLElementEquivalents.size(); ++i) {
1038             if (HTMLElementEquivalents[i]->matches(*element)) {
1039                 elementIsSpanOrElementEquivalent = true;
1040                 break;
1041             }
1042         }
1043     }
1044
1045     if (!element->hasAttributes())
1046         return elementIsSpanOrElementEquivalent; // span, b, etc... without any attributes
1047
1048     unsigned matchedAttributes = 0;
1049     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = htmlAttributeEquivalents();
1050     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
1051         if (HTMLAttributeEquivalents[i]->matches(*element) && HTMLAttributeEquivalents[i]->attributeName() != HTMLNames::dirAttr)
1052             matchedAttributes++;
1053     }
1054
1055     if (!elementIsSpanOrElementEquivalent && !matchedAttributes)
1056         return false; // element is not a span, a html element equivalent, or font element.
1057     
1058     if (element->getAttribute(HTMLNames::classAttr) == AppleStyleSpanClass)
1059         matchedAttributes++;
1060
1061     if (element->hasAttribute(HTMLNames::styleAttr)) {
1062         if (const StyleProperties* style = element->inlineStyle()) {
1063             unsigned propertyCount = style->propertyCount();
1064             for (unsigned i = 0; i < propertyCount; ++i) {
1065                 if (!isEditingProperty(style->propertyAt(i).id()))
1066                     return false;
1067             }
1068         }
1069         matchedAttributes++;
1070     }
1071
1072     // font with color attribute, span with style attribute, etc...
1073     ASSERT(matchedAttributes <= element->attributeCount());
1074     return matchedAttributes >= element->attributeCount();
1075 }
1076
1077 void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
1078 {
1079     if (!m_mutableStyle)
1080         return;
1081
1082     // ReplaceSelectionCommand::handleStyleSpans() requires that this function only removes the editing style.
1083     // If this function was modified in the future to delete all redundant properties, then add a boolean value to indicate
1084     // which one of editingStyleAtPosition or computedStyle is called.
1085     RefPtr<EditingStyle> editingStyleAtPosition = EditingStyle::create(position, EditingPropertiesInEffect);
1086     StyleProperties* styleAtPosition = editingStyleAtPosition->m_mutableStyle.get();
1087
1088     RefPtr<CSSValue> unicodeBidi;
1089     RefPtr<CSSValue> direction;
1090     if (shouldPreserveWritingDirection == PreserveWritingDirection) {
1091         unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
1092         direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
1093     }
1094
1095     removeEquivalentProperties(*styleAtPosition);
1096
1097     if (textAlignResolvingStartAndEnd(*m_mutableStyle) == textAlignResolvingStartAndEnd(*styleAtPosition))
1098         m_mutableStyle->removeProperty(CSSPropertyTextAlign);
1099
1100     if (textColorFromStyle(*m_mutableStyle) == textColorFromStyle(*styleAtPosition))
1101         m_mutableStyle->removeProperty(CSSPropertyColor);
1102
1103     if (hasTransparentBackgroundColor(m_mutableStyle.get())
1104         || cssValueToRGBA(m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor).get()) == rgbaBackgroundColorInEffect(position.containerNode()))
1105         m_mutableStyle->removeProperty(CSSPropertyBackgroundColor);
1106
1107     if (is<CSSPrimitiveValue>(unicodeBidi.get())) {
1108         m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSValueID>(downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID()));
1109         if (is<CSSPrimitiveValue>(direction.get()))
1110             m_mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSValueID>(downcast<CSSPrimitiveValue>(*direction).getValueID()));
1111     }
1112 }
1113
1114 void EditingStyle::mergeTypingStyle(Document& document)
1115 {
1116     RefPtr<EditingStyle> typingStyle = document.frame()->selection().typingStyle();
1117     if (!typingStyle || typingStyle == this)
1118         return;
1119
1120     mergeStyle(typingStyle->style(), OverrideValues);
1121 }
1122
1123 void EditingStyle::mergeInlineStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
1124 {
1125     ASSERT(element);
1126     if (!element->inlineStyle())
1127         return;
1128
1129     switch (propertiesToInclude) {
1130     case AllProperties:
1131         mergeStyle(element->inlineStyle(), mode);
1132         return;
1133     case OnlyEditingInheritableProperties:
1134         mergeStyle(copyEditingProperties(element->inlineStyle(), OnlyInheritableEditingProperties).get(), mode);
1135         return;
1136     case EditingPropertiesInEffect:
1137         mergeStyle(copyEditingProperties(element->inlineStyle(), AllEditingProperties).get(), mode);
1138         return;
1139     }
1140 }
1141
1142 static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl(const HTMLElementEquivalent* equivalent, const StyledElement* element,
1143     EditingStyle::CSSPropertyOverrideMode mode, EditingStyle& style)
1144 {
1145     if (!equivalent->matches(*element))
1146         return false;
1147     if (mode != EditingStyle::OverrideValues && equivalent->propertyExistsInStyle(style))
1148         return false;
1149
1150     return !element->inlineStyle() || !equivalent->propertyExistsInStyle(EditingStyle::create(element->inlineStyle()).get());
1151 }
1152
1153 static PassRefPtr<MutableStyleProperties> extractEditingProperties(const StyleProperties* style, EditingStyle::PropertiesToInclude propertiesToInclude)
1154 {
1155     if (!style)
1156         return 0;
1157
1158     switch (propertiesToInclude) {
1159     case EditingStyle::AllProperties:
1160     case EditingStyle::EditingPropertiesInEffect:
1161         return copyEditingProperties(style, AllEditingProperties);
1162     case EditingStyle::OnlyEditingInheritableProperties:
1163         return copyEditingProperties(style, OnlyInheritableEditingProperties);
1164     }
1165
1166     ASSERT_NOT_REACHED();
1167     return 0;
1168 }
1169
1170 void EditingStyle::mergeInlineAndImplicitStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
1171 {
1172     RefPtr<EditingStyle> styleFromRules = EditingStyle::create();
1173     styleFromRules->mergeStyleFromRulesForSerialization(element);
1174
1175     if (element->inlineStyle())
1176         styleFromRules->m_mutableStyle->mergeAndOverrideOnConflict(*element->inlineStyle());
1177
1178     styleFromRules->m_mutableStyle = extractEditingProperties(styleFromRules->m_mutableStyle.get(), propertiesToInclude);
1179     mergeStyle(styleFromRules->m_mutableStyle.get(), mode);
1180
1181     const Vector<std::unique_ptr<HTMLElementEquivalent>>& elementEquivalents = htmlElementEquivalents();
1182     for (size_t i = 0; i < elementEquivalents.size(); ++i) {
1183         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(elementEquivalents[i].get(), element, mode, *this))
1184             elementEquivalents[i]->addToStyle(element, this);
1185     }
1186
1187     const Vector<std::unique_ptr<HTMLAttributeEquivalent>>& attributeEquivalents = htmlAttributeEquivalents();
1188     for (size_t i = 0; i < attributeEquivalents.size(); ++i) {
1189         if (attributeEquivalents[i]->attributeName() == HTMLNames::dirAttr)
1190             continue; // We don't want to include directionality
1191         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(attributeEquivalents[i].get(), element, mode, *this))
1192             attributeEquivalents[i]->addToStyle(element, this);
1193     }
1194 }
1195
1196 PassRefPtr<EditingStyle> EditingStyle::wrappingStyleForSerialization(Node* context, bool shouldAnnotate)
1197 {
1198     RefPtr<EditingStyle> wrappingStyle;
1199     if (shouldAnnotate) {
1200         wrappingStyle = EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect);
1201
1202         // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote,
1203         // to help us differentiate those styles from ones that the user has applied.
1204         // This helps us get the color of content pasted into blockquotes right.
1205         wrappingStyle->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInOrBeforeNode(context), isMailBlockquote, CanCrossEditingBoundary));
1206
1207         // Call collapseTextDecorationProperties first or otherwise it'll copy the value over from in-effect to text-decorations.
1208         wrappingStyle->collapseTextDecorationProperties();
1209         
1210         return wrappingStyle.release();
1211     }
1212
1213     wrappingStyle = EditingStyle::create();
1214
1215     // When not annotating for interchange, we only preserve inline style declarations.
1216     for (Node* node = context; node && !node->isDocumentNode(); node = node->parentNode()) {
1217         if (is<StyledElement>(*node) && !isMailBlockquote(node)) {
1218             wrappingStyle->mergeInlineAndImplicitStyleOfElement(downcast<StyledElement>(node), EditingStyle::DoNotOverrideValues,
1219                 EditingStyle::EditingPropertiesInEffect);
1220         }
1221     }
1222
1223     return wrappingStyle.release();
1224 }
1225
1226
1227 static void mergeTextDecorationValues(CSSValueList& mergedValue, const CSSValueList& valueToMerge)
1228 {
1229     Ref<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
1230     Ref<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
1231
1232     if (valueToMerge.hasValue(underline.ptr()) && !mergedValue.hasValue(underline.ptr()))
1233         mergedValue.append(WTF::move(underline));
1234
1235     if (valueToMerge.hasValue(lineThrough.ptr()) && !mergedValue.hasValue(lineThrough.ptr()))
1236         mergedValue.append(WTF::move(lineThrough));
1237 }
1238
1239 void EditingStyle::mergeStyle(const StyleProperties* style, CSSPropertyOverrideMode mode)
1240 {
1241     if (!style)
1242         return;
1243
1244     if (!m_mutableStyle) {
1245         m_mutableStyle = style->mutableCopy();
1246         return;
1247     }
1248
1249     unsigned propertyCount = style->propertyCount();
1250     for (unsigned i = 0; i < propertyCount; ++i) {
1251         StyleProperties::PropertyReference property = style->propertyAt(i);
1252         RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(property.id());
1253
1254         // text decorations never override values.
1255         if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect)
1256             && is<CSSValueList>(*property.value()) && value) {
1257             if (is<CSSValueList>(*value)) {
1258                 RefPtr<CSSValueList> newValue = downcast<CSSValueList>(*value).copy();
1259                 mergeTextDecorationValues(*newValue, downcast<CSSValueList>(*property.value()));
1260                 m_mutableStyle->setProperty(property.id(), newValue.release(), property.isImportant());
1261                 continue;
1262             }
1263             value = nullptr; // text-decoration: none is equivalent to not having the property.
1264         }
1265
1266         if (mode == OverrideValues || (mode == DoNotOverrideValues && !value))
1267             m_mutableStyle->setProperty(property.id(), property.value(), property.isImportant());
1268     }
1269
1270     int oldFontSizeDelta = m_fontSizeDelta;
1271     extractFontSizeDelta();
1272     m_fontSizeDelta += oldFontSizeDelta;
1273 }
1274
1275 static PassRefPtr<MutableStyleProperties> styleFromMatchedRulesForElement(Element* element, unsigned rulesToInclude)
1276 {
1277     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
1278     auto matchedRules = element->document().ensureStyleResolver().styleRulesForElement(element, rulesToInclude);
1279     for (unsigned i = 0; i < matchedRules.size(); ++i) {
1280         if (matchedRules[i]->isStyleRule())
1281             style->mergeAndOverrideOnConflict(static_pointer_cast<StyleRule>(matchedRules[i])->properties());
1282     }
1283     
1284     return style.release();
1285 }
1286
1287 void EditingStyle::mergeStyleFromRules(StyledElement* element)
1288 {
1289     RefPtr<MutableStyleProperties> styleFromMatchedRules = styleFromMatchedRulesForElement(element,
1290         StyleResolver::AuthorCSSRules | StyleResolver::CrossOriginCSSRules);
1291     // Styles from the inline style declaration, held in the variable "style", take precedence 
1292     // over those from matched rules.
1293     if (m_mutableStyle)
1294         styleFromMatchedRules->mergeAndOverrideOnConflict(*m_mutableStyle);
1295
1296     clear();
1297     m_mutableStyle = styleFromMatchedRules;
1298 }
1299
1300 void EditingStyle::mergeStyleFromRulesForSerialization(StyledElement* element)
1301 {
1302     mergeStyleFromRules(element);
1303
1304     // The property value, if it's a percentage, may not reflect the actual computed value.  
1305     // For example: style="height: 1%; overflow: visible;" in quirksmode
1306     // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot copy/paste fidelity problem
1307     RefPtr<MutableStyleProperties> fromComputedStyle = MutableStyleProperties::create();
1308     ComputedStyleExtractor computedStyle(element);
1309
1310     {
1311         unsigned propertyCount = m_mutableStyle->propertyCount();
1312         for (unsigned i = 0; i < propertyCount; ++i) {
1313             StyleProperties::PropertyReference property = m_mutableStyle->propertyAt(i);
1314             CSSValue* value = property.value();
1315             if (!is<CSSPrimitiveValue>(*value))
1316                 continue;
1317             if (downcast<CSSPrimitiveValue>(*value).isPercentage()) {
1318                 if (RefPtr<CSSValue> computedPropertyValue = computedStyle.propertyValue(property.id()))
1319                     fromComputedStyle->addParsedProperty(CSSProperty(property.id(), computedPropertyValue.release()));
1320             }
1321         }
1322     }
1323     m_mutableStyle->mergeAndOverrideOnConflict(*fromComputedStyle);
1324 }
1325
1326 static void removePropertiesInStyle(MutableStyleProperties* styleToRemovePropertiesFrom, MutableStyleProperties* style)
1327 {
1328     unsigned propertyCount = style->propertyCount();
1329     Vector<CSSPropertyID> propertiesToRemove(propertyCount);
1330     for (unsigned i = 0; i < propertyCount; ++i)
1331         propertiesToRemove[i] = style->propertyAt(i).id();
1332
1333     styleToRemovePropertiesFrom->removePropertiesInSet(propertiesToRemove.data(), propertiesToRemove.size());
1334 }
1335
1336 void EditingStyle::removeStyleFromRulesAndContext(StyledElement* element, Node* context)
1337 {
1338     ASSERT(element);
1339     if (!m_mutableStyle)
1340         return;
1341
1342     // 1. Remove style from matched rules because style remain without repeating it in inline style declaration
1343     RefPtr<MutableStyleProperties> styleFromMatchedRules = styleFromMatchedRulesForElement(element, StyleResolver::AllButEmptyCSSRules);
1344     if (styleFromMatchedRules && !styleFromMatchedRules->isEmpty())
1345         m_mutableStyle = getPropertiesNotIn(*m_mutableStyle, *styleFromMatchedRules);
1346
1347     // 2. Remove style present in context and not overriden by matched rules.
1348     RefPtr<EditingStyle> computedStyle = EditingStyle::create(context, EditingPropertiesInEffect);
1349     if (computedStyle->m_mutableStyle) {
1350         if (!computedStyle->m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor))
1351             computedStyle->m_mutableStyle->setProperty(CSSPropertyBackgroundColor, CSSValueTransparent);
1352
1353         removePropertiesInStyle(computedStyle->m_mutableStyle.get(), styleFromMatchedRules.get());
1354         m_mutableStyle = getPropertiesNotIn(*m_mutableStyle, *computedStyle->m_mutableStyle);
1355     }
1356
1357     // 3. If this element is a span and has display: inline or float: none, remove them unless they are overriden by rules.
1358     // These rules are added by serialization code to wrap text nodes.
1359     if (isStyleSpanOrSpanWithOnlyStyleAttribute(element)) {
1360         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyDisplay) && identifierForStyleProperty(*m_mutableStyle, CSSPropertyDisplay) == CSSValueInline)
1361             m_mutableStyle->removeProperty(CSSPropertyDisplay);
1362         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyFloat) && identifierForStyleProperty(*m_mutableStyle, CSSPropertyFloat) == CSSValueNone)
1363             m_mutableStyle->removeProperty(CSSPropertyFloat);
1364     }
1365 }
1366
1367 void EditingStyle::removePropertiesInElementDefaultStyle(Element* element)
1368 {
1369     if (!m_mutableStyle || m_mutableStyle->isEmpty())
1370         return;
1371
1372     RefPtr<MutableStyleProperties> defaultStyle = styleFromMatchedRulesForElement(element, StyleResolver::UAAndUserCSSRules);
1373
1374     removePropertiesInStyle(m_mutableStyle.get(), defaultStyle.get());
1375 }
1376
1377 template<typename T>
1378 void EditingStyle::removeEquivalentProperties(const T& style)
1379 {
1380     Vector<CSSPropertyID> propertiesToRemove;
1381     for (auto& property : m_mutableStyle->m_propertyVector) {
1382         if (style.propertyMatches(property.id(), property.value()))
1383             propertiesToRemove.append(property.id());
1384     }
1385     // FIXME: This should use mass removal.
1386     for (auto& property : propertiesToRemove)
1387         m_mutableStyle->removeProperty(property);
1388 }
1389
1390 void EditingStyle::forceInline()
1391 {
1392     if (!m_mutableStyle)
1393         m_mutableStyle = MutableStyleProperties::create();
1394     const bool propertyIsImportant = true;
1395     m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline, propertyIsImportant);
1396 }
1397
1398 bool EditingStyle::convertPositionStyle()
1399 {
1400     if (!m_mutableStyle)
1401         return false;
1402
1403     RefPtr<CSSPrimitiveValue> sticky = cssValuePool().createIdentifierValue(CSSValueWebkitSticky);
1404     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, sticky.get())) {
1405         m_mutableStyle->setProperty(CSSPropertyPosition, cssValuePool().createIdentifierValue(CSSValueStatic), m_mutableStyle->propertyIsImportant(CSSPropertyPosition));
1406         return false;
1407     }
1408     RefPtr<CSSPrimitiveValue> fixed = cssValuePool().createIdentifierValue(CSSValueFixed);
1409     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, fixed.get())) {
1410         m_mutableStyle->setProperty(CSSPropertyPosition, cssValuePool().createIdentifierValue(CSSValueAbsolute), m_mutableStyle->propertyIsImportant(CSSPropertyPosition));
1411         return true;
1412     }
1413     RefPtr<CSSPrimitiveValue> absolute = cssValuePool().createIdentifierValue(CSSValueAbsolute);
1414     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, absolute.get()))
1415         return true;
1416     return false;
1417 }
1418
1419 bool EditingStyle::isFloating()
1420 {
1421     RefPtr<CSSValue> v = m_mutableStyle->getPropertyCSSValue(CSSPropertyFloat);
1422     RefPtr<CSSPrimitiveValue> noneValue = cssValuePool().createIdentifierValue(CSSValueNone);
1423     return v && !v->equals(*noneValue);
1424 }
1425
1426 int EditingStyle::legacyFontSize(Document* document) const
1427 {
1428     RefPtr<CSSValue> cssValue = m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize);
1429     if (!is<CSSPrimitiveValue>(cssValue.get()))
1430         return 0;
1431     return legacyFontSizeFromCSSValue(document, downcast<CSSPrimitiveValue>(cssValue.get()),
1432         m_shouldUseFixedDefaultFontSize, AlwaysUseLegacyFontSize);
1433 }
1434
1435 PassRefPtr<EditingStyle> EditingStyle::styleAtSelectionStart(const VisibleSelection& selection, bool shouldUseBackgroundColorInEffect)
1436 {
1437     if (selection.isNone())
1438         return 0;
1439
1440     Position position = adjustedSelectionStartForStyleComputation(selection);
1441
1442     // If the pos is at the end of a text node, then this node is not fully selected. 
1443     // Move it to the next deep equivalent position to avoid removing the style from this node. 
1444     // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we want Position("world", 0) instead. 
1445     // We only do this for range because caret at Position("hello", 5) in <b>hello</b>world should give you font-weight: bold. 
1446     Node* positionNode = position.containerNode(); 
1447     if (selection.isRange() && positionNode && positionNode->isTextNode() && position.computeOffsetInContainerNode() == positionNode->maxCharacterOffset()) 
1448         position = nextVisuallyDistinctCandidate(position); 
1449
1450     Element* element = position.element();
1451     if (!element)
1452         return 0;
1453
1454     RefPtr<EditingStyle> style = EditingStyle::create(element, EditingStyle::AllProperties);
1455     style->mergeTypingStyle(element->document());
1456
1457     // If background color is transparent, traverse parent nodes until we hit a different value or document root
1458     // Also, if the selection is a range, ignore the background color at the start of selection,
1459     // and find the background color of the common ancestor.
1460     if (shouldUseBackgroundColorInEffect && (selection.isRange() || hasTransparentBackgroundColor(style->m_mutableStyle.get()))) {
1461         RefPtr<Range> range(selection.toNormalizedRange());
1462         if (PassRefPtr<CSSValue> value = backgroundColorInEffect(range->commonAncestorContainer(IGNORE_EXCEPTION)))
1463             style->setProperty(CSSPropertyBackgroundColor, value->cssText());
1464     }
1465
1466     return style;
1467 }
1468
1469 WritingDirection EditingStyle::textDirectionForSelection(const VisibleSelection& selection, EditingStyle* typingStyle, bool& hasNestedOrMultipleEmbeddings)
1470 {
1471     hasNestedOrMultipleEmbeddings = true;
1472
1473     if (selection.isNone())
1474         return NaturalWritingDirection;
1475
1476     Position position = selection.start().downstream();
1477
1478     Node* node = position.deprecatedNode();
1479     if (!node)
1480         return NaturalWritingDirection;
1481
1482     Position end;
1483     if (selection.isRange()) {
1484         end = selection.end().upstream();
1485
1486         Node* pastLast = Range::create(*end.document(), position.parentAnchoredEquivalent(), end.parentAnchoredEquivalent())->pastLastNode();
1487         for (Node* n = node; n && n != pastLast; n = NodeTraversal::next(*n)) {
1488             if (!n->isStyledElement())
1489                 continue;
1490
1491             RefPtr<CSSValue> unicodeBidi = ComputedStyleExtractor(n).propertyValue(CSSPropertyUnicodeBidi);
1492             if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
1493                 continue;
1494
1495             CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
1496             if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride)
1497                 return NaturalWritingDirection;
1498         }
1499     }
1500
1501     if (selection.isCaret()) {
1502         WritingDirection direction;
1503         if (typingStyle && typingStyle->textDirection(direction)) {
1504             hasNestedOrMultipleEmbeddings = false;
1505             return direction;
1506         }
1507         node = selection.visibleStart().deepEquivalent().deprecatedNode();
1508     }
1509
1510     // 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
1511     // to decide.
1512     Node* block = enclosingBlock(node);
1513     WritingDirection foundDirection = NaturalWritingDirection;
1514
1515     for (; node != block; node = node->parentNode()) {
1516         if (!node->isStyledElement())
1517             continue;
1518
1519         ComputedStyleExtractor computedStyle(node);
1520         RefPtr<CSSValue> unicodeBidi = computedStyle.propertyValue(CSSPropertyUnicodeBidi);
1521         if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
1522             continue;
1523
1524         CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
1525         if (unicodeBidiValue == CSSValueNormal)
1526             continue;
1527
1528         if (unicodeBidiValue == CSSValueBidiOverride)
1529             return NaturalWritingDirection;
1530
1531         ASSERT(unicodeBidiValue == CSSValueEmbed);
1532         RefPtr<CSSValue> direction = computedStyle.propertyValue(CSSPropertyDirection);
1533         if (!is<CSSPrimitiveValue>(direction.get()))
1534             continue;
1535
1536         CSSValueID directionValue = downcast<CSSPrimitiveValue>(*direction).getValueID();
1537         if (directionValue != CSSValueLtr && directionValue != CSSValueRtl)
1538             continue;
1539
1540         if (foundDirection != NaturalWritingDirection)
1541             return NaturalWritingDirection;
1542
1543         // In the range case, make sure that the embedding element persists until the end of the range.
1544         if (selection.isRange() && !end.deprecatedNode()->isDescendantOf(node))
1545             return NaturalWritingDirection;
1546         
1547         foundDirection = directionValue == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
1548     }
1549     hasNestedOrMultipleEmbeddings = false;
1550     return foundDirection;
1551 }
1552
1553 static void reconcileTextDecorationProperties(MutableStyleProperties* style)
1554 {    
1555     RefPtr<CSSValue> textDecorationsInEffect = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
1556     RefPtr<CSSValue> textDecoration = style->getPropertyCSSValue(CSSPropertyTextDecoration);
1557     // We shouldn't have both text-decoration and -webkit-text-decorations-in-effect because that wouldn't make sense.
1558     ASSERT(!textDecorationsInEffect || !textDecoration);
1559     if (textDecorationsInEffect) {
1560         style->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText());
1561         style->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
1562         textDecoration = textDecorationsInEffect;
1563     }
1564
1565     // If text-decoration is set to "none", remove the property because we don't want to add redundant "text-decoration: none".
1566     if (textDecoration && !textDecoration->isValueList())
1567         style->removeProperty(CSSPropertyTextDecoration);
1568 }
1569
1570 StyleChange::StyleChange(EditingStyle* style, const Position& position)
1571     : m_applyBold(false)
1572     , m_applyItalic(false)
1573     , m_applyUnderline(false)
1574     , m_applyLineThrough(false)
1575     , m_applySubscript(false)
1576     , m_applySuperscript(false)
1577 {
1578     Document* document = position.deprecatedNode() ? &position.deprecatedNode()->document() : 0;
1579     if (!style || style->isEmpty() || !document || !document->frame())
1580         return;
1581
1582     Node* node = position.containerNode();
1583     if (!node)
1584         return;
1585
1586     ComputedStyleExtractor computedStyle(node);
1587
1588     // FIXME: take care of background-color in effect
1589     RefPtr<MutableStyleProperties> mutableStyle = style->style() ?
1590         getPropertiesNotIn(*style->style(), computedStyle) : MutableStyleProperties::create();
1591
1592     reconcileTextDecorationProperties(mutableStyle.get());
1593     bool shouldStyleWithCSS = document->frame()->editor().shouldStyleWithCSS();
1594     if (!shouldStyleWithCSS)
1595         extractTextStyles(document, *mutableStyle, computedStyle.useFixedFontDefaultSize());
1596
1597     bool shouldAddUnderline = style->underlineChange() == TextDecorationChange::Add;
1598     bool shouldAddStrikeThrough = style->strikeThroughChange() == TextDecorationChange::Add;
1599     if (shouldAddUnderline || shouldAddStrikeThrough) {
1600         RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyWebkitTextDecorationsInEffect);
1601         if (!is<CSSValueList>(value.get()))
1602             value = computedStyle.propertyValue(CSSPropertyTextDecoration);
1603
1604         RefPtr<CSSValueList> valueList;
1605         if (is<CSSValueList>(value.get()))
1606             valueList = downcast<CSSValueList>(value.get());
1607
1608         Ref<CSSValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
1609         bool hasUnderline = valueList && valueList->hasValue(underline.ptr());
1610
1611         Ref<CSSValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
1612         bool hasLineThrough = valueList && valueList->hasValue(lineThrough.ptr());
1613
1614         if (shouldStyleWithCSS) {
1615             valueList = valueList ? valueList->copy() : CSSValueList::createSpaceSeparated();
1616             if (shouldAddUnderline && !hasUnderline)
1617                 valueList->append(WTF::move(underline));
1618             if (shouldAddStrikeThrough && !hasLineThrough)
1619                 valueList->append(WTF::move(lineThrough));
1620             mutableStyle->setProperty(CSSPropertyTextDecoration, valueList.get());
1621         } else {
1622             m_applyUnderline = shouldAddUnderline && !hasUnderline;
1623             m_applyLineThrough = shouldAddStrikeThrough && !hasLineThrough;
1624         }
1625     }
1626
1627     // Changing the whitespace style in a tab span would collapse the tab into a space.
1628     if (isTabSpanTextNode(position.deprecatedNode()) || isTabSpanNode((position.deprecatedNode())))
1629         mutableStyle->removeProperty(CSSPropertyWhiteSpace);
1630
1631     // If unicode-bidi is present in mutableStyle and direction is not, then add direction to mutableStyle.
1632     // FIXME: Shouldn't this be done in getPropertiesNotIn?
1633     if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->style()->getPropertyCSSValue(CSSPropertyDirection))
1634         mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection));
1635
1636     if (!mutableStyle->isEmpty())
1637         m_cssStyle = mutableStyle;
1638 }
1639
1640 bool StyleChange::operator==(const StyleChange& other)
1641 {
1642     if (m_applyBold != other.m_applyBold
1643         || m_applyItalic != other.m_applyItalic
1644         || m_applyUnderline != other.m_applyUnderline
1645         || m_applyLineThrough != other.m_applyLineThrough
1646         || m_applySubscript != other.m_applySubscript
1647         || m_applySuperscript != other.m_applySuperscript
1648         || m_applyFontColor != other.m_applyFontColor
1649         || m_applyFontFace != other.m_applyFontFace
1650         || m_applyFontSize != other.m_applyFontSize)
1651         return false;
1652
1653     return (!m_cssStyle && !other.m_cssStyle)
1654         || (m_cssStyle && other.m_cssStyle && m_cssStyle->asText() == other.m_cssStyle->asText());
1655 }
1656
1657 static void setTextDecorationProperty(MutableStyleProperties& style, const CSSValueList* newTextDecoration, CSSPropertyID propertyID)
1658 {
1659     if (newTextDecoration->length())
1660         style.setProperty(propertyID, newTextDecoration->cssText(), style.propertyIsImportant(propertyID));
1661     else {
1662         // text-decoration: none is redundant since it does not remove any text decorations.
1663         style.removeProperty(propertyID);
1664     }
1665 }
1666
1667 void StyleChange::extractTextStyles(Document* document, MutableStyleProperties& style, bool shouldUseFixedFontDefaultSize)
1668 {
1669     if (identifierForStyleProperty(style, CSSPropertyFontWeight) == CSSValueBold) {
1670         style.removeProperty(CSSPropertyFontWeight);
1671         m_applyBold = true;
1672     }
1673
1674     int fontStyle = identifierForStyleProperty(style, CSSPropertyFontStyle);
1675     if (fontStyle == CSSValueItalic || fontStyle == CSSValueOblique) {
1676         style.removeProperty(CSSPropertyFontStyle);
1677         m_applyItalic = true;
1678     }
1679
1680     // Assuming reconcileTextDecorationProperties has been called, there should not be -webkit-text-decorations-in-effect
1681     // Furthermore, text-decoration: none has been trimmed so that text-decoration property is always a CSSValueList.
1682     RefPtr<CSSValue> textDecoration = style.getPropertyCSSValue(CSSPropertyTextDecoration);
1683     if (is<CSSValueList>(textDecoration.get())) {
1684         RefPtr<CSSPrimitiveValue> underline = cssValuePool().createIdentifierValue(CSSValueUnderline);
1685         RefPtr<CSSPrimitiveValue> lineThrough = cssValuePool().createIdentifierValue(CSSValueLineThrough);
1686
1687         RefPtr<CSSValueList> newTextDecoration = downcast<CSSValueList>(*textDecoration).copy();
1688         if (newTextDecoration->removeAll(underline.get()))
1689             m_applyUnderline = true;
1690         if (newTextDecoration->removeAll(lineThrough.get()))
1691             m_applyLineThrough = true;
1692
1693         // If trimTextDecorations, delete underline and line-through
1694         setTextDecorationProperty(style, newTextDecoration.get(), CSSPropertyTextDecoration);
1695     }
1696
1697     int verticalAlign = identifierForStyleProperty(style, CSSPropertyVerticalAlign);
1698     switch (verticalAlign) {
1699     case CSSValueSub:
1700         style.removeProperty(CSSPropertyVerticalAlign);
1701         m_applySubscript = true;
1702         break;
1703     case CSSValueSuper:
1704         style.removeProperty(CSSPropertyVerticalAlign);
1705         m_applySuperscript = true;
1706         break;
1707     }
1708
1709     if (style.getPropertyCSSValue(CSSPropertyColor)) {
1710         m_applyFontColor = Color(textColorFromStyle(style)).serialized();
1711         style.removeProperty(CSSPropertyColor);
1712     }
1713
1714     m_applyFontFace = style.getPropertyValue(CSSPropertyFontFamily);
1715     // Remove single quotes for Outlook 2007 compatibility. See https://bugs.webkit.org/show_bug.cgi?id=79448
1716     m_applyFontFace.replaceWithLiteral('\'', "");
1717     style.removeProperty(CSSPropertyFontFamily);
1718
1719     if (RefPtr<CSSValue> fontSize = style.getPropertyCSSValue(CSSPropertyFontSize)) {
1720         if (!is<CSSPrimitiveValue>(*fontSize))
1721             style.removeProperty(CSSPropertyFontSize); // Can't make sense of the number. Put no font size.
1722         else if (int legacyFontSize = legacyFontSizeFromCSSValue(document, downcast<CSSPrimitiveValue>(fontSize.get()),
1723                 shouldUseFixedFontDefaultSize, UseLegacyFontSizeOnlyIfPixelValuesMatch)) {
1724             m_applyFontSize = String::number(legacyFontSize);
1725             style.removeProperty(CSSPropertyFontSize);
1726         }
1727     }
1728 }
1729
1730 static void diffTextDecorations(MutableStyleProperties& style, CSSPropertyID propertID, CSSValue* refTextDecoration)
1731 {
1732     RefPtr<CSSValue> textDecoration = style.getPropertyCSSValue(propertID);
1733     if (!is<CSSValueList>(textDecoration.get()) || !is<CSSValueList>(refTextDecoration))
1734         return;
1735
1736     RefPtr<CSSValueList> newTextDecoration = downcast<CSSValueList>(*textDecoration).copy();
1737     CSSValueList& valuesInRefTextDecoration = downcast<CSSValueList>(*refTextDecoration);
1738
1739     for (size_t i = 0; i < valuesInRefTextDecoration.length(); ++i)
1740         newTextDecoration->removeAll(valuesInRefTextDecoration.item(i));
1741
1742     setTextDecorationProperty(style, newTextDecoration.get(), propertID);
1743 }
1744
1745 static bool fontWeightIsBold(CSSValue& fontWeight)
1746 {
1747     if (!is<CSSPrimitiveValue>(fontWeight))
1748         return false;
1749
1750     // Because b tag can only bold text, there are only two states in plain html: bold and not bold.
1751     // Collapse all other values to either one of these two states for editing purposes.
1752     switch (downcast<CSSPrimitiveValue>(fontWeight).getValueID()) {
1753         case CSSValue100:
1754         case CSSValue200:
1755         case CSSValue300:
1756         case CSSValue400:
1757         case CSSValue500:
1758         case CSSValueNormal:
1759             return false;
1760         case CSSValueBold:
1761         case CSSValue600:
1762         case CSSValue700:
1763         case CSSValue800:
1764         case CSSValue900:
1765             return true;
1766         default:
1767             break;
1768     }
1769
1770     ASSERT_NOT_REACHED(); // For CSSValueBolder and CSSValueLighter
1771     return false;
1772 }
1773
1774 template<typename T>
1775 static bool fontWeightIsBold(T& style)
1776 {
1777     RefPtr<CSSValue> fontWeight = extractPropertyValue(style, CSSPropertyFontWeight);
1778     return fontWeight && fontWeightIsBold(*fontWeight);
1779 }
1780
1781 template<typename T>
1782 static PassRefPtr<MutableStyleProperties> extractPropertiesNotIn(StyleProperties& styleWithRedundantProperties, T& baseStyle)
1783 {
1784     RefPtr<EditingStyle> result = EditingStyle::create(&styleWithRedundantProperties);
1785     result->removeEquivalentProperties(baseStyle);
1786     RefPtr<MutableStyleProperties> mutableStyle = result->style();
1787
1788     RefPtr<CSSValue> baseTextDecorationsInEffect = extractPropertyValue(baseStyle, CSSPropertyWebkitTextDecorationsInEffect);
1789     diffTextDecorations(*mutableStyle, CSSPropertyTextDecoration, baseTextDecorationsInEffect.get());
1790     diffTextDecorations(*mutableStyle, CSSPropertyWebkitTextDecorationsInEffect, baseTextDecorationsInEffect.get());
1791
1792     if (extractPropertyValue(baseStyle, CSSPropertyFontWeight) && fontWeightIsBold(*mutableStyle) == fontWeightIsBold(baseStyle))
1793         mutableStyle->removeProperty(CSSPropertyFontWeight);
1794
1795     if (extractPropertyValue(baseStyle, CSSPropertyColor) && textColorFromStyle(*mutableStyle) == textColorFromStyle(baseStyle))
1796         mutableStyle->removeProperty(CSSPropertyColor);
1797
1798     if (extractPropertyValue(baseStyle, CSSPropertyTextAlign)
1799         && textAlignResolvingStartAndEnd(*mutableStyle) == textAlignResolvingStartAndEnd(baseStyle))
1800         mutableStyle->removeProperty(CSSPropertyTextAlign);
1801
1802     if (extractPropertyValue(baseStyle, CSSPropertyBackgroundColor) && backgroundColorFromStyle(*mutableStyle) == backgroundColorFromStyle(baseStyle))
1803         mutableStyle->removeProperty(CSSPropertyBackgroundColor);
1804
1805     return mutableStyle.release();
1806 }
1807
1808 template<typename T>
1809 PassRefPtr<MutableStyleProperties> getPropertiesNotIn(StyleProperties& styleWithRedundantProperties, T& baseStyle)
1810 {
1811     return extractPropertiesNotIn(styleWithRedundantProperties, baseStyle);
1812 }
1813
1814 static bool isCSSValueLength(CSSPrimitiveValue* value)
1815 {
1816     return value->isFontIndependentLength();
1817 }
1818
1819 int legacyFontSizeFromCSSValue(Document* document, CSSPrimitiveValue* value, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode mode)
1820 {
1821     ASSERT(document); // FIXME: This method should take a Document&
1822
1823     if (isCSSValueLength(value)) {
1824         int pixelFontSize = value->getIntValue(CSSPrimitiveValue::CSS_PX);
1825         int legacyFontSize = Style::legacyFontSizeForPixelSize(pixelFontSize, shouldUseFixedFontDefaultSize, *document);
1826         // Use legacy font size only if pixel value matches exactly to that of legacy font size.
1827         int cssPrimitiveEquivalent = legacyFontSize - 1 + CSSValueXSmall;
1828         if (mode == AlwaysUseLegacyFontSize || Style::fontSizeForKeyword(cssPrimitiveEquivalent, shouldUseFixedFontDefaultSize, *document) == pixelFontSize)
1829             return legacyFontSize;
1830
1831         return 0;
1832     }
1833
1834     if (CSSValueXSmall <= value->getValueID() && value->getValueID() <= CSSValueWebkitXxxLarge)
1835         return value->getValueID() - CSSValueXSmall + 1;
1836
1837     return 0;
1838 }
1839
1840 bool isTransparentColorValue(CSSValue* cssValue)
1841 {
1842     if (!cssValue)
1843         return true;
1844     if (!is<CSSPrimitiveValue>(*cssValue))
1845         return false;
1846     CSSPrimitiveValue& value = downcast<CSSPrimitiveValue>(*cssValue);
1847     if (value.isRGBColor())
1848         return !alphaChannel(value.getRGBA32Value());
1849     return value.getValueID() == CSSValueTransparent;
1850 }
1851
1852 bool hasTransparentBackgroundColor(StyleProperties* style)
1853 {
1854     RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(CSSPropertyBackgroundColor);
1855     return isTransparentColorValue(cssValue.get());
1856 }
1857
1858 PassRefPtr<CSSValue> backgroundColorInEffect(Node* node)
1859 {
1860     for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) {
1861         if (RefPtr<CSSValue> value = ComputedStyleExtractor(ancestor).propertyValue(CSSPropertyBackgroundColor)) {
1862             if (!isTransparentColorValue(value.get()))
1863                 return value.release();
1864         }
1865     }
1866     return 0;
1867 }
1868
1869 }