Rename IOS_TEXT_AUTOSIZING to TEXT_AUTOSIZING
[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 "HTMLSpanElement.h"
43 #include "Node.h"
44 #include "NodeTraversal.h"
45 #include "QualifiedName.h"
46 #include "RenderStyle.h"
47 #include "StyleFontSizeFunctions.h"
48 #include "StyleProperties.h"
49 #include "StyleResolver.h"
50 #include "StyleRule.h"
51 #include "StyledElement.h"
52 #include "VisibleUnits.h"
53 #include "htmlediting.h"
54
55 namespace WebCore {
56
57 // Editing style properties must be preserved during editing operation.
58 // e.g. when a user inserts a new paragraph, all properties listed here must be copied to the new paragraph.
59 static const CSSPropertyID editingProperties[] = {
60     CSSPropertyColor,
61     CSSPropertyFontFamily,
62     CSSPropertyFontSize,
63     CSSPropertyFontStyle,
64     CSSPropertyFontVariantCaps,
65     CSSPropertyFontWeight,
66     CSSPropertyLetterSpacing,
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(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 (auto& editingProperty : editingProperties) {
105         if (editingProperty == 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 RefPtr<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 { nullptr }; // We can store a pointer because HTML tag names are const global.
175 };
176
177 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id)
178     : m_propertyID(id)
179 {
180 }
181
182 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, const QualifiedName& tagName)
183     : m_propertyID(id)
184     , m_tagName(&tagName)
185 {
186 }
187
188 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, CSSValueID primitiveValue, const QualifiedName& tagName)
189     : m_propertyID(id)
190     , m_primitiveValue(CSSPrimitiveValue::createIdentifier(primitiveValue))
191     , m_tagName(&tagName)
192 {
193     ASSERT(primitiveValue != CSSValueInvalid);
194 }
195
196 bool HTMLElementEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const
197 {
198     RefPtr<CSSValue> value = style.m_mutableStyle->getPropertyCSSValue(m_propertyID);
199     return matches(element) && is<CSSPrimitiveValue>(value.get()) && downcast<CSSPrimitiveValue>(*value).getValueID() == m_primitiveValue->getValueID();
200 }
201
202 void HTMLElementEquivalent::addToStyle(Element*, EditingStyle* style) const
203 {
204     style->setProperty(m_propertyID, m_primitiveValue->cssText());
205 }
206
207 class HTMLTextDecorationEquivalent : public HTMLElementEquivalent {
208 public:
209     HTMLTextDecorationEquivalent(CSSValueID primitiveValue, const QualifiedName& tagName)
210         : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)
211         , m_isUnderline(primitiveValue == CSSValueUnderline)
212     {
213     }
214
215     bool propertyExistsInStyle(const EditingStyle& style) const override
216     {
217         if (changeInStyle(style) != TextDecorationChange::None)
218             return true;
219
220         if (!style.m_mutableStyle)
221             return false;
222
223         auto& mutableStyle = *style.m_mutableStyle;
224         return mutableStyle.getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect)
225             || mutableStyle.getPropertyCSSValue(CSSPropertyTextDecoration);
226     }
227
228     bool valueIsPresentInStyle(Element& element, const EditingStyle& style) const override
229     {
230         if (!matches(element))
231             return false;
232         auto change = changeInStyle(style);
233         if (change != TextDecorationChange::None)
234             return change == TextDecorationChange::Add;
235         RefPtr<CSSValue> styleValue = style.m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
236         if (!styleValue)
237             styleValue = style.m_mutableStyle->getPropertyCSSValue(CSSPropertyTextDecoration);
238         return is<CSSValueList>(styleValue.get()) && downcast<CSSValueList>(*styleValue).hasValue(m_primitiveValue.get());
239     }
240
241 private:
242     TextDecorationChange changeInStyle(const EditingStyle& style) const
243     {
244         return m_isUnderline ? style.underlineChange() : style.strikeThroughChange();
245     }
246
247     bool m_isUnderline;
248 };
249
250 class HTMLAttributeEquivalent : public HTMLElementEquivalent {
251 public:
252     HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& tagName, const QualifiedName& attrName);
253     HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName);
254
255     bool matches(const Element& element) const override { return HTMLElementEquivalent::matches(element) && element.hasAttribute(m_attrName); }
256     bool hasAttribute() const override { return true; }
257     bool valueIsPresentInStyle(Element&, const EditingStyle&) const override;
258     void addToStyle(Element*, EditingStyle*) const override;
259     virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
260     inline const QualifiedName& attributeName() const { return m_attrName; }
261
262 protected:
263     const QualifiedName& m_attrName; // We can store a reference because HTML attribute names are const global.
264 };
265
266 HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& tagName, const QualifiedName& attrName)
267     : HTMLElementEquivalent(id, tagName)
268     , m_attrName(attrName)
269 {
270 }
271
272 HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& attrName)
273     : HTMLElementEquivalent(id)
274     , m_attrName(attrName)
275 {
276 }
277
278 bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element& element, const EditingStyle& style) const
279 {
280     RefPtr<CSSValue> value = attributeValueAsCSSValue(&element);
281     RefPtr<CSSValue> styleValue = style.m_mutableStyle->getPropertyCSSValue(m_propertyID);
282     
283     return compareCSSValuePtr(value, styleValue);
284 }
285
286 void HTMLAttributeEquivalent::addToStyle(Element* element, EditingStyle* style) const
287 {
288     if (RefPtr<CSSValue> value = attributeValueAsCSSValue(element))
289         style->setProperty(m_propertyID, value->cssText());
290 }
291
292 PassRefPtr<CSSValue> HTMLAttributeEquivalent::attributeValueAsCSSValue(Element* element) const
293 {
294     ASSERT(element);
295     const AtomicString& value = element->getAttribute(m_attrName);
296     if (value.isNull())
297         return nullptr;
298     
299     RefPtr<MutableStyleProperties> dummyStyle;
300     dummyStyle = MutableStyleProperties::create();
301     dummyStyle->setProperty(m_propertyID, value);
302     return dummyStyle->getPropertyCSSValue(m_propertyID);
303 }
304
305 class HTMLFontSizeEquivalent : public HTMLAttributeEquivalent {
306 public:
307     HTMLFontSizeEquivalent();
308
309     PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const override;
310 };
311
312 HTMLFontSizeEquivalent::HTMLFontSizeEquivalent()
313     : HTMLAttributeEquivalent(CSSPropertyFontSize, HTMLNames::fontTag, HTMLNames::sizeAttr)
314 {
315 }
316
317 PassRefPtr<CSSValue> HTMLFontSizeEquivalent::attributeValueAsCSSValue(Element* element) const
318 {
319     ASSERT(element);
320     const AtomicString& value = element->getAttribute(m_attrName);
321     if (value.isNull())
322         return nullptr;
323     CSSValueID size;
324     if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
325         return nullptr;
326     return CSSPrimitiveValue::createIdentifier(size);
327 }
328
329 float EditingStyle::NoFontDelta = 0.0f;
330
331 EditingStyle::EditingStyle()
332     : m_shouldUseFixedDefaultFontSize(false)
333     , m_underlineChange(static_cast<unsigned>(TextDecorationChange::None))
334     , m_strikeThroughChange(static_cast<unsigned>(TextDecorationChange::None))
335 {
336 }
337
338 EditingStyle::EditingStyle(Node* node, PropertiesToInclude propertiesToInclude)
339     : EditingStyle()
340 {
341     init(node, propertiesToInclude);
342 }
343
344 EditingStyle::EditingStyle(const Position& position, PropertiesToInclude propertiesToInclude)
345     : EditingStyle()
346 {
347     init(position.deprecatedNode(), propertiesToInclude);
348 }
349
350 EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
351     : EditingStyle()
352 {
353     if (style)
354         m_mutableStyle = style->copyProperties();
355     extractFontSizeDelta();
356 }
357
358 EditingStyle::EditingStyle(const StyleProperties* style)
359     : EditingStyle()
360 {
361     if (style)
362         m_mutableStyle = style->mutableCopy();
363     extractFontSizeDelta();
364 }
365
366 EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value)
367     : EditingStyle()
368 {
369     setProperty(propertyID, value);
370     extractFontSizeDelta();
371 }
372
373 EditingStyle::EditingStyle(CSSPropertyID propertyID, CSSValueID value)
374     : EditingStyle()
375 {
376     m_mutableStyle = MutableStyleProperties::create();
377     m_mutableStyle->setProperty(propertyID, value);
378     extractFontSizeDelta();
379 }
380
381 EditingStyle::~EditingStyle()
382 {
383 }
384
385 static RGBA32 cssValueToRGBA(CSSValue* colorValue)
386 {
387     if (!is<CSSPrimitiveValue>(colorValue))
388         return Color::transparent;
389     
390     CSSPrimitiveValue& primitiveColor = downcast<CSSPrimitiveValue>(*colorValue);
391     if (primitiveColor.isRGBColor())
392         return primitiveColor.getRGBA32Value();
393     
394     RGBA32 rgba = 0;
395     CSSParser::parseColor(rgba, colorValue->cssText());
396     return rgba;
397 }
398
399 template<typename T>
400 static inline RGBA32 textColorFromStyle(T& style)
401 {
402     return cssValueToRGBA(extractPropertyValue(style, CSSPropertyColor).get());
403 }
404
405 template<typename T>
406 static inline RGBA32 backgroundColorFromStyle(T& style)
407 {
408     return cssValueToRGBA(extractPropertyValue(style, CSSPropertyBackgroundColor).get());
409 }
410
411 static inline RGBA32 rgbaBackgroundColorInEffect(Node* node)
412 {
413     return cssValueToRGBA(backgroundColorInEffect(node).get());
414 }
415
416 static int textAlignResolvingStartAndEnd(int textAlign, int direction)
417 {
418     switch (textAlign) {
419     case CSSValueCenter:
420     case CSSValueWebkitCenter:
421         return CSSValueCenter;
422     case CSSValueJustify:
423         return CSSValueJustify;
424     case CSSValueLeft:
425     case CSSValueWebkitLeft:
426         return CSSValueLeft;
427     case CSSValueRight:
428     case CSSValueWebkitRight:
429         return CSSValueRight;
430     case CSSValueStart:
431         return direction != CSSValueRtl ? CSSValueLeft : CSSValueRight;
432     case CSSValueEnd:
433         return direction == CSSValueRtl ? CSSValueRight : CSSValueLeft;
434     }
435     return CSSValueInvalid;
436 }
437
438 template<typename T>
439 static int textAlignResolvingStartAndEnd(T& style)
440 {
441     return textAlignResolvingStartAndEnd(identifierForStyleProperty(style, CSSPropertyTextAlign), identifierForStyleProperty(style, CSSPropertyDirection));
442 }
443
444 void EditingStyle::init(Node* node, PropertiesToInclude propertiesToInclude)
445 {
446     if (isTabSpanTextNode(node))
447         node = tabSpanNode(node)->parentNode();
448     else if (isTabSpanNode(node))
449         node = node->parentNode();
450
451     ComputedStyleExtractor computedStyleAtPosition(node);
452     // FIXME: It's strange to not set background-color and text-decoration when propertiesToInclude is EditingPropertiesInEffect.
453     // However editing/selection/contains-boundaries.html fails without this ternary.
454     m_mutableStyle = copyPropertiesFromComputedStyle(computedStyleAtPosition,
455         propertiesToInclude == EditingPropertiesInEffect ? OnlyEditingInheritableProperties : propertiesToInclude);
456
457     if (propertiesToInclude == EditingPropertiesInEffect) {
458         if (RefPtr<CSSValue> value = backgroundColorInEffect(node))
459             m_mutableStyle->setProperty(CSSPropertyBackgroundColor, value->cssText());
460         if (RefPtr<CSSValue> value = computedStyleAtPosition.propertyValue(CSSPropertyWebkitTextDecorationsInEffect))
461             m_mutableStyle->setProperty(CSSPropertyTextDecoration, value->cssText());
462     }
463
464     if (node && node->computedStyle()) {
465         auto* renderStyle = node->computedStyle();
466         removeTextFillAndStrokeColorsIfNeeded(renderStyle);
467         if (renderStyle->fontDescription().keywordSize())
468             m_mutableStyle->setProperty(CSSPropertyFontSize, computedStyleAtPosition.getFontSizeCSSValuePreferringKeyword()->cssText());
469     }
470
471     m_shouldUseFixedDefaultFontSize = computedStyleAtPosition.useFixedFontDefaultSize();
472     extractFontSizeDelta();
473 }
474
475 void EditingStyle::removeTextFillAndStrokeColorsIfNeeded(const RenderStyle* renderStyle)
476 {
477     // If a node's text fill color is invalid, then its children use 
478     // their font-color as their text fill color (they don't
479     // inherit it).  Likewise for stroke color.
480     if (!renderStyle->textFillColor().isValid())
481         m_mutableStyle->removeProperty(CSSPropertyWebkitTextFillColor);
482     if (!renderStyle->textStrokeColor().isValid())
483         m_mutableStyle->removeProperty(CSSPropertyWebkitTextStrokeColor);
484 }
485
486 void EditingStyle::setProperty(CSSPropertyID propertyID, const String& value, bool important)
487 {
488     if (!m_mutableStyle)
489         m_mutableStyle = MutableStyleProperties::create();
490
491     m_mutableStyle->setProperty(propertyID, value, important);
492 }
493
494 void EditingStyle::extractFontSizeDelta()
495 {
496     if (!m_mutableStyle)
497         return;
498
499     if (m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize)) {
500         // Explicit font size overrides any delta.
501         m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
502         return;
503     }
504
505     // Get the adjustment amount out of the style.
506     RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitFontSizeDelta);
507     if (!is<CSSPrimitiveValue>(value.get()))
508         return;
509
510     CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(*value);
511
512     // Only PX handled now. If we handle more types in the future, perhaps
513     // a switch statement here would be more appropriate.
514     if (!primitiveValue.isPx())
515         return;
516
517     m_fontSizeDelta = primitiveValue.getFloatValue();
518     m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
519 }
520
521 bool EditingStyle::isEmpty() const
522 {
523     return (!m_mutableStyle || m_mutableStyle->isEmpty()) && m_fontSizeDelta == NoFontDelta
524         && underlineChange() == TextDecorationChange::None && strikeThroughChange() == TextDecorationChange::None;
525 }
526
527 Ref<MutableStyleProperties> EditingStyle::styleWithResolvedTextDecorations() const
528 {
529     bool hasTextDecorationChanges = underlineChange() != TextDecorationChange::None || strikeThroughChange() != TextDecorationChange::None;
530     if (m_mutableStyle && !hasTextDecorationChanges)
531         return *m_mutableStyle;
532
533     Ref<MutableStyleProperties> style = m_mutableStyle ? m_mutableStyle->mutableCopy() : MutableStyleProperties::create();
534
535     Ref<CSSValueList> valueList = CSSValueList::createSpaceSeparated();
536     if (underlineChange() == TextDecorationChange::Add)
537         valueList->append(CSSValuePool::singleton().createIdentifierValue(CSSValueUnderline));
538     if (strikeThroughChange() == TextDecorationChange::Add)
539         valueList->append(CSSValuePool::singleton().createIdentifierValue(CSSValueLineThrough));
540
541     if (valueList->length())
542         style->setProperty(CSSPropertyTextDecoration, valueList.ptr());
543     else
544         style->setProperty(CSSPropertyTextDecoration, CSSValuePool::singleton().createIdentifierValue(CSSValueNone));
545
546     return style;
547 }
548
549 bool EditingStyle::textDirection(WritingDirection& writingDirection) const
550 {
551     if (!m_mutableStyle)
552         return false;
553
554     RefPtr<CSSValue> unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
555     if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
556         return false;
557
558     CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
559     if (unicodeBidiValue == CSSValueEmbed) {
560         RefPtr<CSSValue> direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
561         if (!is<CSSPrimitiveValue>(direction.get()))
562             return false;
563
564         writingDirection = downcast<CSSPrimitiveValue>(*direction).getValueID() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
565
566         return true;
567     }
568
569     if (unicodeBidiValue == CSSValueNormal) {
570         writingDirection = NaturalWritingDirection;
571         return true;
572     }
573
574     return false;
575 }
576
577 void EditingStyle::setStyle(PassRefPtr<MutableStyleProperties> style)
578 {
579     m_mutableStyle = style;
580     // FIXME: We should be able to figure out whether or not font is fixed width for mutable style.
581     // We need to check font-family is monospace as in FontDescription but we don't want to duplicate code here.
582     m_shouldUseFixedDefaultFontSize = false;
583     extractFontSizeDelta();
584 }
585
586 void EditingStyle::overrideWithStyle(const StyleProperties* style)
587 {
588     return mergeStyle(style, OverrideValues);
589 }
590
591 static void applyTextDecorationChangeToValueList(CSSValueList& valueList, TextDecorationChange change, Ref<CSSPrimitiveValue>&& value)
592 {
593     switch (change) {
594     case TextDecorationChange::None:
595         break;
596     case TextDecorationChange::Add:
597         valueList.append(WTFMove(value));
598         break;
599     case TextDecorationChange::Remove:
600         valueList.removeAll(&value.get());
601         break;
602     }
603 }
604
605 void EditingStyle::overrideTypingStyleAt(const EditingStyle& style, const Position& position)
606 {
607     mergeStyle(style.m_mutableStyle.get(), OverrideValues);
608
609     m_fontSizeDelta += style.m_fontSizeDelta;
610
611     prepareToApplyAt(position, EditingStyle::PreserveWritingDirection);
612
613     auto underlineChange = style.underlineChange();
614     auto strikeThroughChange = style.strikeThroughChange();
615     if (underlineChange == TextDecorationChange::None && strikeThroughChange == TextDecorationChange::None)
616         return;
617
618     if (!m_mutableStyle)
619         m_mutableStyle = MutableStyleProperties::create();
620
621     auto& cssValuePool = CSSValuePool::singleton();
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, WTFMove(underline));
629         applyTextDecorationChangeToValueList(*valueList, strikeThroughChange, WTFMove(lineThrough));
630     } else {
631         valueList = CSSValueList::createSpaceSeparated();
632         if (underlineChange == TextDecorationChange::Add)
633             valueList->append(WTFMove(underline));
634         if (strikeThroughChange == TextDecorationChange::Add)
635             valueList->append(WTFMove(lineThrough));
636     }
637     m_mutableStyle->setProperty(CSSPropertyWebkitTextDecorationsInEffect, valueList.get());
638 }
639
640 void EditingStyle::clear()
641 {
642     m_mutableStyle = nullptr;
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::singleton().createIdentifierValue(CSSValueUnderline);
831             if (shouldRemoveUnderline && valueList->hasValue(underline.ptr())) {
832                 if (!newInlineStyle)
833                     return true;
834                 newValueList->removeAll(underline.ptr());
835                 extractedValueList->append(WTFMove(underline));
836             }
837
838             Ref<CSSPrimitiveValue> lineThrough = CSSValuePool::singleton().createIdentifierValue(CSSValueLineThrough);
839             if (shouldRemoveStrikeThrough && valueList->hasValue(lineThrough.ptr())) {
840                 if (!newInlineStyle)
841                     return true;
842                 newValueList->removeAll(lineThrough.ptr());
843                 extractedValueList->append(WTFMove(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     bool removed = false;
983     for (auto& equivalent : htmlAttributeEquivalents()) {
984         // unicode-bidi and direction are pushed down separately so don't push down with other styles.
985         if (shouldPreserveWritingDirection == PreserveWritingDirection && equivalent->attributeName() == HTMLNames::dirAttr)
986             continue;
987
988         if (!equivalent->matches(*element) || !equivalent->propertyExistsInStyle(*this)
989             || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(*element, *this)))
990             continue;
991
992         if (extractedStyle)
993             equivalent->addToStyle(element, extractedStyle);
994         conflictingAttributes.append(equivalent->attributeName());
995         removed = true;
996     }
997
998     return removed;
999 }
1000
1001 bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const
1002 {
1003     if (isEmpty())
1004         return true;
1005     ComputedStyleExtractor computedStyle(node);
1006
1007     bool shouldAddUnderline = underlineChange() == TextDecorationChange::Add;
1008     bool shouldAddLineThrough = strikeThroughChange() == TextDecorationChange::Add;
1009     if (shouldAddUnderline || shouldAddLineThrough) {
1010         bool hasUnderline = false;
1011         bool hasLineThrough = false;
1012         if (RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyTextDecoration)) {
1013             if (value->isValueList()) {
1014                 auto& cssValuePool = CSSValuePool::singleton();
1015                 const CSSValueList& valueList = downcast<CSSValueList>(*value);
1016                 hasUnderline = valueList.hasValue(cssValuePool.createIdentifierValue(CSSValueUnderline).ptr());
1017                 hasLineThrough = valueList.hasValue(cssValuePool.createIdentifierValue(CSSValueLineThrough).ptr());
1018             }
1019         }
1020         if ((shouldAddUnderline && !hasUnderline) || (shouldAddLineThrough && !hasLineThrough))
1021             return false;
1022     }
1023
1024     return !m_mutableStyle || getPropertiesNotIn(*m_mutableStyle, computedStyle)->isEmpty();
1025 }
1026
1027 bool EditingStyle::elementIsStyledSpanOrHTMLEquivalent(const HTMLElement* element)
1028 {
1029     bool elementIsSpanOrElementEquivalent = false;
1030     if (element->hasTagName(HTMLNames::spanTag))
1031         elementIsSpanOrElementEquivalent = true;
1032     else {
1033         for (auto& equivalent : htmlElementEquivalents()) {
1034             if (equivalent->matches(*element)) {
1035                 elementIsSpanOrElementEquivalent = true;
1036                 break;
1037             }
1038         }
1039     }
1040
1041     if (!element->hasAttributes())
1042         return elementIsSpanOrElementEquivalent; // span, b, etc... without any attributes
1043
1044     unsigned matchedAttributes = 0;
1045     for (auto& equivalent : htmlAttributeEquivalents()) {
1046         if (equivalent->matches(*element) && equivalent->attributeName() != HTMLNames::dirAttr)
1047             matchedAttributes++;
1048     }
1049
1050     if (!elementIsSpanOrElementEquivalent && !matchedAttributes)
1051         return false; // element is not a span, a html element equivalent, or font element.
1052     
1053     if (element->attributeWithoutSynchronization(HTMLNames::classAttr) == AppleStyleSpanClass)
1054         matchedAttributes++;
1055
1056     if (element->hasAttribute(HTMLNames::styleAttr)) {
1057         if (const StyleProperties* style = element->inlineStyle()) {
1058             unsigned propertyCount = style->propertyCount();
1059             for (unsigned i = 0; i < propertyCount; ++i) {
1060                 if (!isEditingProperty(style->propertyAt(i).id()))
1061                     return false;
1062             }
1063         }
1064         matchedAttributes++;
1065     }
1066
1067     // font with color attribute, span with style attribute, etc...
1068     ASSERT(matchedAttributes <= element->attributeCount());
1069     return matchedAttributes >= element->attributeCount();
1070 }
1071
1072 void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
1073 {
1074     if (!m_mutableStyle)
1075         return;
1076
1077     // ReplaceSelectionCommand::handleStyleSpans() requires that this function only removes the editing style.
1078     // If this function was modified in the future to delete all redundant properties, then add a boolean value to indicate
1079     // which one of editingStyleAtPosition or computedStyle is called.
1080     RefPtr<EditingStyle> editingStyleAtPosition = EditingStyle::create(position, EditingPropertiesInEffect);
1081     StyleProperties* styleAtPosition = editingStyleAtPosition->m_mutableStyle.get();
1082
1083     RefPtr<CSSValue> unicodeBidi;
1084     RefPtr<CSSValue> direction;
1085     if (shouldPreserveWritingDirection == PreserveWritingDirection) {
1086         unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
1087         direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
1088     }
1089
1090     removeEquivalentProperties(*styleAtPosition);
1091
1092     if (textAlignResolvingStartAndEnd(*m_mutableStyle) == textAlignResolvingStartAndEnd(*styleAtPosition))
1093         m_mutableStyle->removeProperty(CSSPropertyTextAlign);
1094
1095     if (textColorFromStyle(*m_mutableStyle) == textColorFromStyle(*styleAtPosition))
1096         m_mutableStyle->removeProperty(CSSPropertyColor);
1097
1098     if (hasTransparentBackgroundColor(m_mutableStyle.get())
1099         || cssValueToRGBA(m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor).get()) == rgbaBackgroundColorInEffect(position.containerNode()))
1100         m_mutableStyle->removeProperty(CSSPropertyBackgroundColor);
1101
1102     if (is<CSSPrimitiveValue>(unicodeBidi.get())) {
1103         m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSValueID>(downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID()));
1104         if (is<CSSPrimitiveValue>(direction.get()))
1105             m_mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSValueID>(downcast<CSSPrimitiveValue>(*direction).getValueID()));
1106     }
1107 }
1108
1109 void EditingStyle::mergeTypingStyle(Document& document)
1110 {
1111     RefPtr<EditingStyle> typingStyle = document.frame()->selection().typingStyle();
1112     if (!typingStyle || typingStyle == this)
1113         return;
1114
1115     mergeStyle(typingStyle->style(), OverrideValues);
1116 }
1117
1118 void EditingStyle::mergeInlineStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
1119 {
1120     ASSERT(element);
1121     if (!element->inlineStyle())
1122         return;
1123
1124     switch (propertiesToInclude) {
1125     case AllProperties:
1126         mergeStyle(element->inlineStyle(), mode);
1127         return;
1128     case OnlyEditingInheritableProperties:
1129         mergeStyle(copyEditingProperties(element->inlineStyle(), OnlyInheritableEditingProperties).get(), mode);
1130         return;
1131     case EditingPropertiesInEffect:
1132         mergeStyle(copyEditingProperties(element->inlineStyle(), AllEditingProperties).get(), mode);
1133         return;
1134     }
1135 }
1136
1137 static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl(const HTMLElementEquivalent* equivalent, const StyledElement* element,
1138     EditingStyle::CSSPropertyOverrideMode mode, EditingStyle& style)
1139 {
1140     if (!equivalent->matches(*element))
1141         return false;
1142     if (mode != EditingStyle::OverrideValues && equivalent->propertyExistsInStyle(style))
1143         return false;
1144
1145     return !element->inlineStyle() || !equivalent->propertyExistsInStyle(EditingStyle::create(element->inlineStyle()).get());
1146 }
1147
1148 static PassRefPtr<MutableStyleProperties> extractEditingProperties(const StyleProperties* style, EditingStyle::PropertiesToInclude propertiesToInclude)
1149 {
1150     if (!style)
1151         return 0;
1152
1153     switch (propertiesToInclude) {
1154     case EditingStyle::AllProperties:
1155     case EditingStyle::EditingPropertiesInEffect:
1156         return copyEditingProperties(style, AllEditingProperties);
1157     case EditingStyle::OnlyEditingInheritableProperties:
1158         return copyEditingProperties(style, OnlyInheritableEditingProperties);
1159     }
1160
1161     ASSERT_NOT_REACHED();
1162     return 0;
1163 }
1164
1165 void EditingStyle::mergeInlineAndImplicitStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
1166 {
1167     RefPtr<EditingStyle> styleFromRules = EditingStyle::create();
1168     styleFromRules->mergeStyleFromRulesForSerialization(element);
1169
1170     if (element->inlineStyle())
1171         styleFromRules->m_mutableStyle->mergeAndOverrideOnConflict(*element->inlineStyle());
1172
1173     styleFromRules->m_mutableStyle = extractEditingProperties(styleFromRules->m_mutableStyle.get(), propertiesToInclude);
1174     mergeStyle(styleFromRules->m_mutableStyle.get(), mode);
1175
1176     for (auto& equivalent : htmlElementEquivalents()) {
1177         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(equivalent.get(), element, mode, *this))
1178             equivalent->addToStyle(element, this);
1179     }
1180
1181     for (auto& equivalent : htmlAttributeEquivalents()) {
1182         if (equivalent->attributeName() == HTMLNames::dirAttr)
1183             continue; // We don't want to include directionality
1184         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(equivalent.get(), element, mode, *this))
1185             equivalent->addToStyle(element, this);
1186     }
1187 }
1188
1189 Ref<EditingStyle> EditingStyle::wrappingStyleForSerialization(Node* context, bool shouldAnnotate)
1190 {
1191     if (shouldAnnotate) {
1192         auto wrappingStyle = EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect);
1193
1194         // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote,
1195         // to help us differentiate those styles from ones that the user has applied.
1196         // This helps us get the color of content pasted into blockquotes right.
1197         wrappingStyle->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInOrBeforeNode(context), isMailBlockquote, CanCrossEditingBoundary));
1198
1199         // Call collapseTextDecorationProperties first or otherwise it'll copy the value over from in-effect to text-decorations.
1200         wrappingStyle->collapseTextDecorationProperties();
1201         
1202         return wrappingStyle;
1203     }
1204
1205     auto wrappingStyle = EditingStyle::create();
1206
1207     // When not annotating for interchange, we only preserve inline style declarations.
1208     for (Node* node = context; node && !node->isDocumentNode(); node = node->parentNode()) {
1209         if (is<StyledElement>(*node) && !isMailBlockquote(node)) {
1210             wrappingStyle->mergeInlineAndImplicitStyleOfElement(downcast<StyledElement>(node), EditingStyle::DoNotOverrideValues,
1211                 EditingStyle::EditingPropertiesInEffect);
1212         }
1213     }
1214
1215     return wrappingStyle;
1216 }
1217
1218
1219 static void mergeTextDecorationValues(CSSValueList& mergedValue, const CSSValueList& valueToMerge)
1220 {
1221     auto& cssValuePool = CSSValuePool::singleton();
1222     Ref<CSSPrimitiveValue> underline = cssValuePool.createIdentifierValue(CSSValueUnderline);
1223     Ref<CSSPrimitiveValue> lineThrough = cssValuePool.createIdentifierValue(CSSValueLineThrough);
1224
1225     if (valueToMerge.hasValue(underline.ptr()) && !mergedValue.hasValue(underline.ptr()))
1226         mergedValue.append(WTFMove(underline));
1227
1228     if (valueToMerge.hasValue(lineThrough.ptr()) && !mergedValue.hasValue(lineThrough.ptr()))
1229         mergedValue.append(WTFMove(lineThrough));
1230 }
1231
1232 void EditingStyle::mergeStyle(const StyleProperties* style, CSSPropertyOverrideMode mode)
1233 {
1234     if (!style)
1235         return;
1236
1237     if (!m_mutableStyle) {
1238         m_mutableStyle = style->mutableCopy();
1239         return;
1240     }
1241
1242     unsigned propertyCount = style->propertyCount();
1243     for (unsigned i = 0; i < propertyCount; ++i) {
1244         StyleProperties::PropertyReference property = style->propertyAt(i);
1245         RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(property.id());
1246
1247         // text decorations never override values.
1248         if ((property.id() == CSSPropertyTextDecoration || property.id() == CSSPropertyWebkitTextDecorationsInEffect)
1249             && is<CSSValueList>(*property.value()) && value) {
1250             if (is<CSSValueList>(*value)) {
1251                 auto newValue = downcast<CSSValueList>(*value).copy();
1252                 mergeTextDecorationValues(newValue, downcast<CSSValueList>(*property.value()));
1253                 m_mutableStyle->setProperty(property.id(), WTFMove(newValue), property.isImportant());
1254                 continue;
1255             }
1256             value = nullptr; // text-decoration: none is equivalent to not having the property.
1257         }
1258
1259         if (mode == OverrideValues || (mode == DoNotOverrideValues && !value))
1260             m_mutableStyle->setProperty(property.id(), property.value(), property.isImportant());
1261     }
1262
1263     int oldFontSizeDelta = m_fontSizeDelta;
1264     extractFontSizeDelta();
1265     m_fontSizeDelta += oldFontSizeDelta;
1266 }
1267
1268 static Ref<MutableStyleProperties> styleFromMatchedRulesForElement(Element* element, unsigned rulesToInclude)
1269 {
1270     auto style = MutableStyleProperties::create();
1271     for (auto& matchedRule : element->styleResolver().styleRulesForElement(element, rulesToInclude)) {
1272         if (matchedRule->isStyleRule())
1273             style->mergeAndOverrideOnConflict(static_pointer_cast<StyleRule>(matchedRule)->properties());
1274     }
1275     
1276     return style;
1277 }
1278
1279 void EditingStyle::mergeStyleFromRules(StyledElement* element)
1280 {
1281     RefPtr<MutableStyleProperties> styleFromMatchedRules = styleFromMatchedRulesForElement(element,
1282         StyleResolver::AuthorCSSRules | StyleResolver::CrossOriginCSSRules);
1283     // Styles from the inline style declaration, held in the variable "style", take precedence 
1284     // over those from matched rules.
1285     if (m_mutableStyle)
1286         styleFromMatchedRules->mergeAndOverrideOnConflict(*m_mutableStyle);
1287
1288     clear();
1289     m_mutableStyle = styleFromMatchedRules;
1290 }
1291
1292 void EditingStyle::mergeStyleFromRulesForSerialization(StyledElement* element)
1293 {
1294     mergeStyleFromRules(element);
1295
1296     // The property value, if it's a percentage, may not reflect the actual computed value.  
1297     // For example: style="height: 1%; overflow: visible;" in quirksmode
1298     // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot copy/paste fidelity problem
1299     RefPtr<MutableStyleProperties> fromComputedStyle = MutableStyleProperties::create();
1300     ComputedStyleExtractor computedStyle(element);
1301
1302     {
1303         unsigned propertyCount = m_mutableStyle->propertyCount();
1304         for (unsigned i = 0; i < propertyCount; ++i) {
1305             StyleProperties::PropertyReference property = m_mutableStyle->propertyAt(i);
1306             CSSValue* value = property.value();
1307             if (!is<CSSPrimitiveValue>(*value))
1308                 continue;
1309             if (downcast<CSSPrimitiveValue>(*value).isPercentage()) {
1310                 if (auto computedPropertyValue = computedStyle.propertyValue(property.id()))
1311                     fromComputedStyle->addParsedProperty(CSSProperty(property.id(), WTFMove(computedPropertyValue)));
1312             }
1313         }
1314     }
1315     m_mutableStyle->mergeAndOverrideOnConflict(*fromComputedStyle);
1316 }
1317
1318 static void removePropertiesInStyle(MutableStyleProperties* styleToRemovePropertiesFrom, MutableStyleProperties* style)
1319 {
1320     unsigned propertyCount = style->propertyCount();
1321     Vector<CSSPropertyID> propertiesToRemove(propertyCount);
1322     for (unsigned i = 0; i < propertyCount; ++i)
1323         propertiesToRemove[i] = style->propertyAt(i).id();
1324
1325     styleToRemovePropertiesFrom->removePropertiesInSet(propertiesToRemove.data(), propertiesToRemove.size());
1326 }
1327
1328 void EditingStyle::removeStyleFromRulesAndContext(StyledElement* element, Node* context)
1329 {
1330     ASSERT(element);
1331     if (!m_mutableStyle)
1332         return;
1333
1334     // 1. Remove style from matched rules because style remain without repeating it in inline style declaration
1335     RefPtr<MutableStyleProperties> styleFromMatchedRules = styleFromMatchedRulesForElement(element, StyleResolver::AllButEmptyCSSRules);
1336     if (styleFromMatchedRules && !styleFromMatchedRules->isEmpty())
1337         m_mutableStyle = getPropertiesNotIn(*m_mutableStyle, *styleFromMatchedRules);
1338
1339     // 2. Remove style present in context and not overriden by matched rules.
1340     RefPtr<EditingStyle> computedStyle = EditingStyle::create(context, EditingPropertiesInEffect);
1341     if (computedStyle->m_mutableStyle) {
1342         if (!computedStyle->m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor))
1343             computedStyle->m_mutableStyle->setProperty(CSSPropertyBackgroundColor, CSSValueTransparent);
1344
1345         removePropertiesInStyle(computedStyle->m_mutableStyle.get(), styleFromMatchedRules.get());
1346         m_mutableStyle = getPropertiesNotIn(*m_mutableStyle, *computedStyle->m_mutableStyle);
1347     }
1348
1349     // 3. If this element is a span and has display: inline or float: none, remove them unless they are overriden by rules.
1350     // These rules are added by serialization code to wrap text nodes.
1351     if (isStyleSpanOrSpanWithOnlyStyleAttribute(element)) {
1352         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyDisplay) && identifierForStyleProperty(*m_mutableStyle, CSSPropertyDisplay) == CSSValueInline)
1353             m_mutableStyle->removeProperty(CSSPropertyDisplay);
1354         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyFloat) && identifierForStyleProperty(*m_mutableStyle, CSSPropertyFloat) == CSSValueNone)
1355             m_mutableStyle->removeProperty(CSSPropertyFloat);
1356     }
1357 }
1358
1359 void EditingStyle::removePropertiesInElementDefaultStyle(Element* element)
1360 {
1361     if (!m_mutableStyle || m_mutableStyle->isEmpty())
1362         return;
1363
1364     RefPtr<MutableStyleProperties> defaultStyle = styleFromMatchedRulesForElement(element, StyleResolver::UAAndUserCSSRules);
1365
1366     removePropertiesInStyle(m_mutableStyle.get(), defaultStyle.get());
1367 }
1368
1369 template<typename T>
1370 void EditingStyle::removeEquivalentProperties(const T& style)
1371 {
1372     Vector<CSSPropertyID> propertiesToRemove;
1373     for (auto& property : m_mutableStyle->m_propertyVector) {
1374         if (style.propertyMatches(property.id(), property.value()))
1375             propertiesToRemove.append(property.id());
1376     }
1377     // FIXME: This should use mass removal.
1378     for (auto& property : propertiesToRemove)
1379         m_mutableStyle->removeProperty(property);
1380 }
1381
1382 void EditingStyle::forceInline()
1383 {
1384     if (!m_mutableStyle)
1385         m_mutableStyle = MutableStyleProperties::create();
1386     const bool propertyIsImportant = true;
1387     m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline, propertyIsImportant);
1388 }
1389
1390 bool EditingStyle::convertPositionStyle()
1391 {
1392     if (!m_mutableStyle)
1393         return false;
1394
1395     auto& cssValuePool = CSSValuePool::singleton();
1396     RefPtr<CSSPrimitiveValue> sticky = cssValuePool.createIdentifierValue(CSSValueWebkitSticky);
1397     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, sticky.get())) {
1398         m_mutableStyle->setProperty(CSSPropertyPosition, cssValuePool.createIdentifierValue(CSSValueStatic), m_mutableStyle->propertyIsImportant(CSSPropertyPosition));
1399         return false;
1400     }
1401     RefPtr<CSSPrimitiveValue> fixed = cssValuePool.createIdentifierValue(CSSValueFixed);
1402     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, fixed.get())) {
1403         m_mutableStyle->setProperty(CSSPropertyPosition, cssValuePool.createIdentifierValue(CSSValueAbsolute), m_mutableStyle->propertyIsImportant(CSSPropertyPosition));
1404         return true;
1405     }
1406     RefPtr<CSSPrimitiveValue> absolute = cssValuePool.createIdentifierValue(CSSValueAbsolute);
1407     if (m_mutableStyle->propertyMatches(CSSPropertyPosition, absolute.get()))
1408         return true;
1409     return false;
1410 }
1411
1412 bool EditingStyle::isFloating()
1413 {
1414     RefPtr<CSSValue> v = m_mutableStyle->getPropertyCSSValue(CSSPropertyFloat);
1415     RefPtr<CSSPrimitiveValue> noneValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNone);
1416     return v && !v->equals(*noneValue);
1417 }
1418
1419 int EditingStyle::legacyFontSize(Document* document) const
1420 {
1421     RefPtr<CSSValue> cssValue = m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize);
1422     if (!is<CSSPrimitiveValue>(cssValue.get()))
1423         return 0;
1424     return legacyFontSizeFromCSSValue(document, downcast<CSSPrimitiveValue>(cssValue.get()),
1425         m_shouldUseFixedDefaultFontSize, AlwaysUseLegacyFontSize);
1426 }
1427
1428 PassRefPtr<EditingStyle> EditingStyle::styleAtSelectionStart(const VisibleSelection& selection, bool shouldUseBackgroundColorInEffect)
1429 {
1430     if (selection.isNone())
1431         return 0;
1432
1433     Position position = adjustedSelectionStartForStyleComputation(selection);
1434
1435     // If the pos is at the end of a text node, then this node is not fully selected. 
1436     // Move it to the next deep equivalent position to avoid removing the style from this node. 
1437     // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we want Position("world", 0) instead. 
1438     // We only do this for range because caret at Position("hello", 5) in <b>hello</b>world should give you font-weight: bold. 
1439     Node* positionNode = position.containerNode(); 
1440     if (selection.isRange() && positionNode && positionNode->isTextNode() && position.computeOffsetInContainerNode() == positionNode->maxCharacterOffset()) 
1441         position = nextVisuallyDistinctCandidate(position); 
1442
1443     Element* element = position.element();
1444     if (!element)
1445         return 0;
1446
1447     RefPtr<EditingStyle> style = EditingStyle::create(element, EditingStyle::AllProperties);
1448     style->mergeTypingStyle(element->document());
1449
1450     // If background color is transparent, traverse parent nodes until we hit a different value or document root
1451     // Also, if the selection is a range, ignore the background color at the start of selection,
1452     // and find the background color of the common ancestor.
1453     if (shouldUseBackgroundColorInEffect && (selection.isRange() || hasTransparentBackgroundColor(style->m_mutableStyle.get()))) {
1454         RefPtr<Range> range(selection.toNormalizedRange());
1455         if (auto value = backgroundColorInEffect(range->commonAncestorContainer()))
1456             style->setProperty(CSSPropertyBackgroundColor, value->cssText());
1457     }
1458
1459     return style;
1460 }
1461
1462 WritingDirection EditingStyle::textDirectionForSelection(const VisibleSelection& selection, EditingStyle* typingStyle, bool& hasNestedOrMultipleEmbeddings)
1463 {
1464     hasNestedOrMultipleEmbeddings = true;
1465
1466     if (selection.isNone())
1467         return NaturalWritingDirection;
1468
1469     Position position = selection.start().downstream();
1470
1471     Node* node = position.deprecatedNode();
1472     if (!node)
1473         return NaturalWritingDirection;
1474
1475     Position end;
1476     if (selection.isRange()) {
1477         end = selection.end().upstream();
1478
1479         Node* pastLast = Range::create(*end.document(), position.parentAnchoredEquivalent(), end.parentAnchoredEquivalent())->pastLastNode();
1480         for (Node* n = node; n && n != pastLast; n = NodeTraversal::next(*n)) {
1481             if (!n->isStyledElement())
1482                 continue;
1483
1484             RefPtr<CSSValue> unicodeBidi = ComputedStyleExtractor(n).propertyValue(CSSPropertyUnicodeBidi);
1485             if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
1486                 continue;
1487
1488             CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
1489             if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride)
1490                 return NaturalWritingDirection;
1491         }
1492     }
1493
1494     if (selection.isCaret()) {
1495         WritingDirection direction;
1496         if (typingStyle && typingStyle->textDirection(direction)) {
1497             hasNestedOrMultipleEmbeddings = false;
1498             return direction;
1499         }
1500         node = selection.visibleStart().deepEquivalent().deprecatedNode();
1501     }
1502
1503     // 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
1504     // to decide.
1505     Node* block = enclosingBlock(node);
1506     WritingDirection foundDirection = NaturalWritingDirection;
1507
1508     for (; node != block; node = node->parentNode()) {
1509         if (!node->isStyledElement())
1510             continue;
1511
1512         ComputedStyleExtractor computedStyle(node);
1513         RefPtr<CSSValue> unicodeBidi = computedStyle.propertyValue(CSSPropertyUnicodeBidi);
1514         if (!is<CSSPrimitiveValue>(unicodeBidi.get()))
1515             continue;
1516
1517         CSSValueID unicodeBidiValue = downcast<CSSPrimitiveValue>(*unicodeBidi).getValueID();
1518         if (unicodeBidiValue == CSSValueNormal)
1519             continue;
1520
1521         if (unicodeBidiValue == CSSValueBidiOverride)
1522             return NaturalWritingDirection;
1523
1524         ASSERT(unicodeBidiValue == CSSValueEmbed);
1525         RefPtr<CSSValue> direction = computedStyle.propertyValue(CSSPropertyDirection);
1526         if (!is<CSSPrimitiveValue>(direction.get()))
1527             continue;
1528
1529         CSSValueID directionValue = downcast<CSSPrimitiveValue>(*direction).getValueID();
1530         if (directionValue != CSSValueLtr && directionValue != CSSValueRtl)
1531             continue;
1532
1533         if (foundDirection != NaturalWritingDirection)
1534             return NaturalWritingDirection;
1535
1536         // In the range case, make sure that the embedding element persists until the end of the range.
1537         if (selection.isRange() && !end.deprecatedNode()->isDescendantOf(node))
1538             return NaturalWritingDirection;
1539         
1540         foundDirection = directionValue == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
1541     }
1542     hasNestedOrMultipleEmbeddings = false;
1543     return foundDirection;
1544 }
1545
1546 static void reconcileTextDecorationProperties(MutableStyleProperties* style)
1547 {    
1548     RefPtr<CSSValue> textDecorationsInEffect = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
1549     RefPtr<CSSValue> textDecoration = style->getPropertyCSSValue(CSSPropertyTextDecoration);
1550     // We shouldn't have both text-decoration and -webkit-text-decorations-in-effect because that wouldn't make sense.
1551     ASSERT(!textDecorationsInEffect || !textDecoration);
1552     if (textDecorationsInEffect) {
1553         style->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText());
1554         style->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
1555         textDecoration = textDecorationsInEffect;
1556     }
1557
1558     // If text-decoration is set to "none", remove the property because we don't want to add redundant "text-decoration: none".
1559     if (textDecoration && !textDecoration->isValueList())
1560         style->removeProperty(CSSPropertyTextDecoration);
1561 }
1562
1563 StyleChange::StyleChange(EditingStyle* style, const Position& position)
1564     : m_applyBold(false)
1565     , m_applyItalic(false)
1566     , m_applyUnderline(false)
1567     , m_applyLineThrough(false)
1568     , m_applySubscript(false)
1569     , m_applySuperscript(false)
1570 {
1571     Document* document = position.deprecatedNode() ? &position.deprecatedNode()->document() : 0;
1572     if (!style || style->isEmpty() || !document || !document->frame())
1573         return;
1574
1575     Node* node = position.containerNode();
1576     if (!node)
1577         return;
1578
1579     ComputedStyleExtractor computedStyle(node);
1580
1581     // FIXME: take care of background-color in effect
1582     RefPtr<MutableStyleProperties> mutableStyle = style->style() ?
1583         getPropertiesNotIn(*style->style(), computedStyle) : MutableStyleProperties::create();
1584
1585     reconcileTextDecorationProperties(mutableStyle.get());
1586     bool shouldStyleWithCSS = document->frame()->editor().shouldStyleWithCSS();
1587     if (!shouldStyleWithCSS)
1588         extractTextStyles(document, *mutableStyle, computedStyle.useFixedFontDefaultSize());
1589
1590     bool shouldAddUnderline = style->underlineChange() == TextDecorationChange::Add;
1591     bool shouldAddStrikeThrough = style->strikeThroughChange() == TextDecorationChange::Add;
1592     if (shouldAddUnderline || shouldAddStrikeThrough) {
1593         RefPtr<CSSValue> value = computedStyle.propertyValue(CSSPropertyWebkitTextDecorationsInEffect);
1594         if (!is<CSSValueList>(value.get()))
1595             value = computedStyle.propertyValue(CSSPropertyTextDecoration);
1596
1597         RefPtr<CSSValueList> valueList;
1598         if (is<CSSValueList>(value.get()))
1599             valueList = downcast<CSSValueList>(value.get());
1600
1601         auto& cssValuePool = CSSValuePool::singleton();
1602         Ref<CSSValue> underline = cssValuePool.createIdentifierValue(CSSValueUnderline);
1603         bool hasUnderline = valueList && valueList->hasValue(underline.ptr());
1604
1605         Ref<CSSValue> lineThrough = cssValuePool.createIdentifierValue(CSSValueLineThrough);
1606         bool hasLineThrough = valueList && valueList->hasValue(lineThrough.ptr());
1607
1608         if (shouldStyleWithCSS) {
1609             valueList = valueList ? valueList->copy() : CSSValueList::createSpaceSeparated();
1610             if (shouldAddUnderline && !hasUnderline)
1611                 valueList->append(WTFMove(underline));
1612             if (shouldAddStrikeThrough && !hasLineThrough)
1613                 valueList->append(WTFMove(lineThrough));
1614             mutableStyle->setProperty(CSSPropertyTextDecoration, valueList.get());
1615         } else {
1616             m_applyUnderline = shouldAddUnderline && !hasUnderline;
1617             m_applyLineThrough = shouldAddStrikeThrough && !hasLineThrough;
1618         }
1619     }
1620
1621     // Changing the whitespace style in a tab span would collapse the tab into a space.
1622     if (isTabSpanTextNode(position.deprecatedNode()) || isTabSpanNode((position.deprecatedNode())))
1623         mutableStyle->removeProperty(CSSPropertyWhiteSpace);
1624
1625     // If unicode-bidi is present in mutableStyle and direction is not, then add direction to mutableStyle.
1626     // FIXME: Shouldn't this be done in getPropertiesNotIn?
1627     if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->style()->getPropertyCSSValue(CSSPropertyDirection))
1628         mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection));
1629
1630     if (!mutableStyle->isEmpty())
1631         m_cssStyle = mutableStyle;
1632 }
1633
1634 bool StyleChange::operator==(const StyleChange& other)
1635 {
1636     if (m_applyBold != other.m_applyBold
1637         || m_applyItalic != other.m_applyItalic
1638         || m_applyUnderline != other.m_applyUnderline
1639         || m_applyLineThrough != other.m_applyLineThrough
1640         || m_applySubscript != other.m_applySubscript
1641         || m_applySuperscript != other.m_applySuperscript
1642         || m_applyFontColor != other.m_applyFontColor
1643         || m_applyFontFace != other.m_applyFontFace
1644         || m_applyFontSize != other.m_applyFontSize)
1645         return false;
1646
1647     return (!m_cssStyle && !other.m_cssStyle)
1648         || (m_cssStyle && other.m_cssStyle && m_cssStyle->asText() == other.m_cssStyle->asText());
1649 }
1650
1651 static void setTextDecorationProperty(MutableStyleProperties& style, const CSSValueList* newTextDecoration, CSSPropertyID propertyID)
1652 {
1653     if (newTextDecoration->length())
1654         style.setProperty(propertyID, newTextDecoration->cssText(), style.propertyIsImportant(propertyID));
1655     else {
1656         // text-decoration: none is redundant since it does not remove any text decorations.
1657         style.removeProperty(propertyID);
1658     }
1659 }
1660
1661 void StyleChange::extractTextStyles(Document* document, MutableStyleProperties& style, bool shouldUseFixedFontDefaultSize)
1662 {
1663     if (identifierForStyleProperty(style, CSSPropertyFontWeight) == CSSValueBold) {
1664         style.removeProperty(CSSPropertyFontWeight);
1665         m_applyBold = true;
1666     }
1667
1668     int fontStyle = identifierForStyleProperty(style, CSSPropertyFontStyle);
1669     if (fontStyle == CSSValueItalic || fontStyle == CSSValueOblique) {
1670         style.removeProperty(CSSPropertyFontStyle);
1671         m_applyItalic = true;
1672     }
1673
1674     // Assuming reconcileTextDecorationProperties has been called, there should not be -webkit-text-decorations-in-effect
1675     // Furthermore, text-decoration: none has been trimmed so that text-decoration property is always a CSSValueList.
1676     RefPtr<CSSValue> textDecoration = style.getPropertyCSSValue(CSSPropertyTextDecoration);
1677     if (is<CSSValueList>(textDecoration.get())) {
1678         auto& cssValuePool = CSSValuePool::singleton();
1679         RefPtr<CSSPrimitiveValue> underline = cssValuePool.createIdentifierValue(CSSValueUnderline);
1680         RefPtr<CSSPrimitiveValue> lineThrough = cssValuePool.createIdentifierValue(CSSValueLineThrough);
1681
1682         RefPtr<CSSValueList> newTextDecoration = downcast<CSSValueList>(*textDecoration).copy();
1683         if (newTextDecoration->removeAll(underline.get()))
1684             m_applyUnderline = true;
1685         if (newTextDecoration->removeAll(lineThrough.get()))
1686             m_applyLineThrough = true;
1687
1688         // If trimTextDecorations, delete underline and line-through
1689         setTextDecorationProperty(style, newTextDecoration.get(), CSSPropertyTextDecoration);
1690     }
1691
1692     int verticalAlign = identifierForStyleProperty(style, CSSPropertyVerticalAlign);
1693     switch (verticalAlign) {
1694     case CSSValueSub:
1695         style.removeProperty(CSSPropertyVerticalAlign);
1696         m_applySubscript = true;
1697         break;
1698     case CSSValueSuper:
1699         style.removeProperty(CSSPropertyVerticalAlign);
1700         m_applySuperscript = true;
1701         break;
1702     }
1703
1704     if (style.getPropertyCSSValue(CSSPropertyColor)) {
1705         m_applyFontColor = Color(textColorFromStyle(style)).serialized();
1706         style.removeProperty(CSSPropertyColor);
1707     }
1708
1709     m_applyFontFace = style.getPropertyValue(CSSPropertyFontFamily);
1710     // Remove single quotes for Outlook 2007 compatibility. See https://bugs.webkit.org/show_bug.cgi?id=79448
1711     m_applyFontFace.replaceWithLiteral('\'', "");
1712     style.removeProperty(CSSPropertyFontFamily);
1713
1714     if (RefPtr<CSSValue> fontSize = style.getPropertyCSSValue(CSSPropertyFontSize)) {
1715         if (!is<CSSPrimitiveValue>(*fontSize))
1716             style.removeProperty(CSSPropertyFontSize); // Can't make sense of the number. Put no font size.
1717         else if (int legacyFontSize = legacyFontSizeFromCSSValue(document, downcast<CSSPrimitiveValue>(fontSize.get()),
1718                 shouldUseFixedFontDefaultSize, UseLegacyFontSizeOnlyIfPixelValuesMatch)) {
1719             m_applyFontSize = String::number(legacyFontSize);
1720             style.removeProperty(CSSPropertyFontSize);
1721         }
1722     }
1723 }
1724
1725 static void diffTextDecorations(MutableStyleProperties& style, CSSPropertyID propertID, CSSValue* refTextDecoration)
1726 {
1727     RefPtr<CSSValue> textDecoration = style.getPropertyCSSValue(propertID);
1728     if (!is<CSSValueList>(textDecoration.get()) || !is<CSSValueList>(refTextDecoration))
1729         return;
1730
1731     RefPtr<CSSValueList> newTextDecoration = downcast<CSSValueList>(*textDecoration).copy();
1732
1733     for (auto& value :  downcast<CSSValueList>(*refTextDecoration))
1734         newTextDecoration->removeAll(&value.get());
1735
1736     setTextDecorationProperty(style, newTextDecoration.get(), propertID);
1737 }
1738
1739 static bool fontWeightIsBold(CSSValue& fontWeight)
1740 {
1741     if (!is<CSSPrimitiveValue>(fontWeight))
1742         return false;
1743
1744     // Because b tag can only bold text, there are only two states in plain html: bold and not bold.
1745     // Collapse all other values to either one of these two states for editing purposes.
1746     switch (downcast<CSSPrimitiveValue>(fontWeight).getValueID()) {
1747         case CSSValue100:
1748         case CSSValue200:
1749         case CSSValue300:
1750         case CSSValue400:
1751         case CSSValue500:
1752         case CSSValueNormal:
1753             return false;
1754         case CSSValueBold:
1755         case CSSValue600:
1756         case CSSValue700:
1757         case CSSValue800:
1758         case CSSValue900:
1759             return true;
1760         default:
1761             break;
1762     }
1763
1764     ASSERT_NOT_REACHED(); // For CSSValueBolder and CSSValueLighter
1765     return false;
1766 }
1767
1768 template<typename T>
1769 static bool fontWeightIsBold(T& style)
1770 {
1771     RefPtr<CSSValue> fontWeight = extractPropertyValue(style, CSSPropertyFontWeight);
1772     return fontWeight && fontWeightIsBold(*fontWeight);
1773 }
1774
1775 template<typename T>
1776 static Ref<MutableStyleProperties> extractPropertiesNotIn(StyleProperties& styleWithRedundantProperties, T& baseStyle)
1777 {
1778     RefPtr<EditingStyle> result = EditingStyle::create(&styleWithRedundantProperties);
1779     result->removeEquivalentProperties(baseStyle);
1780     ASSERT(result->style());
1781     Ref<MutableStyleProperties> mutableStyle = *result->style();
1782
1783     RefPtr<CSSValue> baseTextDecorationsInEffect = extractPropertyValue(baseStyle, CSSPropertyWebkitTextDecorationsInEffect);
1784     diffTextDecorations(mutableStyle, CSSPropertyTextDecoration, baseTextDecorationsInEffect.get());
1785     diffTextDecorations(mutableStyle, CSSPropertyWebkitTextDecorationsInEffect, baseTextDecorationsInEffect.get());
1786
1787     if (extractPropertyValue(baseStyle, CSSPropertyFontWeight) && fontWeightIsBold(mutableStyle) == fontWeightIsBold(baseStyle))
1788         mutableStyle->removeProperty(CSSPropertyFontWeight);
1789
1790     if (extractPropertyValue(baseStyle, CSSPropertyColor) && textColorFromStyle(mutableStyle) == textColorFromStyle(baseStyle))
1791         mutableStyle->removeProperty(CSSPropertyColor);
1792
1793     if (extractPropertyValue(baseStyle, CSSPropertyTextAlign)
1794         && textAlignResolvingStartAndEnd(mutableStyle) == textAlignResolvingStartAndEnd(baseStyle))
1795         mutableStyle->removeProperty(CSSPropertyTextAlign);
1796
1797     if (extractPropertyValue(baseStyle, CSSPropertyBackgroundColor) && backgroundColorFromStyle(mutableStyle) == backgroundColorFromStyle(baseStyle))
1798         mutableStyle->removeProperty(CSSPropertyBackgroundColor);
1799
1800     return mutableStyle;
1801 }
1802
1803 template<typename T>
1804 PassRefPtr<MutableStyleProperties> getPropertiesNotIn(StyleProperties& styleWithRedundantProperties, T& baseStyle)
1805 {
1806     return extractPropertiesNotIn(styleWithRedundantProperties, baseStyle);
1807 }
1808
1809 static bool isCSSValueLength(CSSPrimitiveValue* value)
1810 {
1811     return value->isFontIndependentLength();
1812 }
1813
1814 int legacyFontSizeFromCSSValue(Document* document, CSSPrimitiveValue* value, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode mode)
1815 {
1816     ASSERT(document); // FIXME: This method should take a Document&
1817
1818     if (isCSSValueLength(value)) {
1819         int pixelFontSize = value->getIntValue(CSSPrimitiveValue::CSS_PX);
1820         int legacyFontSize = Style::legacyFontSizeForPixelSize(pixelFontSize, shouldUseFixedFontDefaultSize, *document);
1821         // Use legacy font size only if pixel value matches exactly to that of legacy font size.
1822         int cssPrimitiveEquivalent = legacyFontSize - 1 + CSSValueXSmall;
1823         if (mode == AlwaysUseLegacyFontSize || Style::fontSizeForKeyword(cssPrimitiveEquivalent, shouldUseFixedFontDefaultSize, *document) == pixelFontSize)
1824             return legacyFontSize;
1825
1826         return 0;
1827     }
1828
1829     if (CSSValueXSmall <= value->getValueID() && value->getValueID() <= CSSValueWebkitXxxLarge)
1830         return value->getValueID() - CSSValueXSmall + 1;
1831
1832     return 0;
1833 }
1834
1835 bool isTransparentColorValue(CSSValue* cssValue)
1836 {
1837     if (!cssValue)
1838         return true;
1839     if (!is<CSSPrimitiveValue>(*cssValue))
1840         return false;
1841     CSSPrimitiveValue& value = downcast<CSSPrimitiveValue>(*cssValue);
1842     if (value.isRGBColor())
1843         return !alphaChannel(value.getRGBA32Value());
1844     return value.getValueID() == CSSValueTransparent;
1845 }
1846
1847 bool hasTransparentBackgroundColor(StyleProperties* style)
1848 {
1849     RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(CSSPropertyBackgroundColor);
1850     return isTransparentColorValue(cssValue.get());
1851 }
1852
1853 RefPtr<CSSValue> backgroundColorInEffect(Node* node)
1854 {
1855     for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) {
1856         if (RefPtr<CSSValue> value = ComputedStyleExtractor(ancestor).propertyValue(CSSPropertyBackgroundColor)) {
1857             if (!isTransparentColorValue(value.get()))
1858                 return value;
1859         }
1860     }
1861     return nullptr;
1862 }
1863
1864 }