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