tizen beta release
[framework/web/webkit-efl.git] / Source / WebCore / editing / EditingStyle.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009 Apple Computer, 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 "CSSMutableStyleDeclaration.h"
33 #include "CSSParser.h"
34 #include "CSSStyleRule.h"
35 #include "CSSStyleSelector.h"
36 #include "CSSValueKeywords.h"
37 #include "CSSValueList.h"
38 #include "Frame.h"
39 #include "FrameSelection.h"
40 #include "HTMLFontElement.h"
41 #include "HTMLInterchange.h"
42 #include "HTMLNames.h"
43 #include "Node.h"
44 #include "Position.h"
45 #include "QualifiedName.h"
46 #include "RenderStyle.h"
47 #include "StyledElement.h"
48 #include "htmlediting.h"
49 #include "visible_units.h"
50 #include <wtf/HashSet.h>
51
52 namespace WebCore {
53
54 // Editing style properties must be preserved during editing operation.
55 // e.g. when a user inserts a new paragraph, all properties listed here must be copied to the new paragraph.
56 static const int editingProperties[] = {
57     CSSPropertyBackgroundColor,
58     CSSPropertyTextDecoration,
59
60     // CSS inheritable properties
61     CSSPropertyColor,
62     CSSPropertyFontFamily,
63     CSSPropertyFontSize,
64     CSSPropertyFontStyle,
65     CSSPropertyFontVariant,
66     CSSPropertyFontWeight,
67     CSSPropertyLetterSpacing,
68     CSSPropertyLineHeight,
69     CSSPropertyOrphans,
70     CSSPropertyTextAlign,
71     CSSPropertyTextIndent,
72     CSSPropertyTextTransform,
73     CSSPropertyWhiteSpace,
74     CSSPropertyWidows,
75     CSSPropertyWordSpacing,
76     CSSPropertyWebkitTextDecorationsInEffect,
77     CSSPropertyWebkitTextFillColor,
78     CSSPropertyWebkitTextSizeAdjust,
79     CSSPropertyWebkitTextStrokeColor,
80     CSSPropertyWebkitTextStrokeWidth,
81 };
82
83 static PassRefPtr<CSSMutableStyleDeclaration> copyEditingProperties(CSSStyleDeclaration* style, bool includeNonInheritableProperties = false)
84 {
85     if (includeNonInheritableProperties)
86         return style->copyPropertiesInSet(editingProperties, WTF_ARRAY_LENGTH(editingProperties));
87     return style->copyPropertiesInSet(editingProperties + 2, WTF_ARRAY_LENGTH(editingProperties) - 2);
88 }
89
90 static inline bool isEditingProperty(int id)
91 {
92     for (size_t i = 0; i < WTF_ARRAY_LENGTH(editingProperties); ++i) {
93         if (editingProperties[i] == id)
94             return true;
95     }
96     return false;
97 }
98
99 static PassRefPtr<CSSMutableStyleDeclaration> editingStyleFromComputedStyle(PassRefPtr<CSSComputedStyleDeclaration> style)
100 {
101     if (!style)
102         return CSSMutableStyleDeclaration::create();
103     return copyEditingProperties(style.get());
104 }
105
106 static RefPtr<CSSMutableStyleDeclaration> getPropertiesNotIn(CSSStyleDeclaration* styleWithRedundantProperties, CSSStyleDeclaration* baseStyle);
107 enum LegacyFontSizeMode { AlwaysUseLegacyFontSize, UseLegacyFontSizeOnlyIfPixelValuesMatch };
108 static int legacyFontSizeFromCSSValue(Document*, CSSPrimitiveValue*, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode);
109 static bool hasTransparentBackgroundColor(CSSStyleDeclaration*);
110 static PassRefPtr<CSSValue> backgroundColorInEffect(Node*);
111
112 class HTMLElementEquivalent {
113 public:
114     static PassOwnPtr<HTMLElementEquivalent> create(CSSPropertyID propertyID, int primitiveValue, const QualifiedName& tagName)
115     {
116         return adoptPtr(new HTMLElementEquivalent(propertyID, primitiveValue, tagName));
117     }
118
119     virtual ~HTMLElementEquivalent() { }
120     virtual bool matches(const Element* element) const { return !m_tagName || element->hasTagName(*m_tagName); }
121     virtual bool hasAttribute() const { return false; }
122     virtual bool propertyExistsInStyle(CSSStyleDeclaration* style) const { return style && style->getPropertyCSSValue(m_propertyID); }
123     virtual bool valueIsPresentInStyle(Element*, CSSStyleDeclaration*) const;
124     virtual void addToStyle(Element*, EditingStyle*) const;
125
126 protected:
127     HTMLElementEquivalent(CSSPropertyID);
128     HTMLElementEquivalent(CSSPropertyID, const QualifiedName& tagName);
129     HTMLElementEquivalent(CSSPropertyID, int primitiveValue, const QualifiedName& tagName);
130     const int m_propertyID;
131     const RefPtr<CSSPrimitiveValue> m_primitiveValue;
132     const QualifiedName* m_tagName; // We can store a pointer because HTML tag names are const global.
133 };
134
135 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id)
136     : m_propertyID(id)
137     , m_tagName(0)
138 {
139 }
140
141 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, const QualifiedName& tagName)
142     : m_propertyID(id)
143     , m_tagName(&tagName)
144 {
145 }
146
147 HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, int primitiveValue, const QualifiedName& tagName)
148     : m_propertyID(id)
149     , m_primitiveValue(CSSPrimitiveValue::createIdentifier(primitiveValue))
150     , m_tagName(&tagName)
151 {
152     ASSERT(primitiveValue != CSSValueInvalid);
153 }
154
155 bool HTMLElementEquivalent::valueIsPresentInStyle(Element* element, CSSStyleDeclaration* style) const
156 {
157     RefPtr<CSSValue> value = style->getPropertyCSSValue(m_propertyID);
158     return matches(element) && value && value->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(value.get())->getIdent() == m_primitiveValue->getIdent();
159 }
160
161 void HTMLElementEquivalent::addToStyle(Element*, EditingStyle* style) const
162 {
163     style->setProperty(m_propertyID, m_primitiveValue->cssText());
164 }
165
166 class HTMLTextDecorationEquivalent : public HTMLElementEquivalent {
167 public:
168     static PassOwnPtr<HTMLElementEquivalent> create(int primitiveValue, const QualifiedName& tagName)
169     {
170         return adoptPtr(new HTMLTextDecorationEquivalent(primitiveValue, tagName));
171     }
172     virtual bool propertyExistsInStyle(CSSStyleDeclaration*) const;
173     virtual bool valueIsPresentInStyle(Element*, CSSStyleDeclaration*) const;
174
175 private:
176     HTMLTextDecorationEquivalent(int primitiveValue, const QualifiedName& tagName);
177 };
178
179 HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent(int primitiveValue, const QualifiedName& tagName)
180     : HTMLElementEquivalent(CSSPropertyTextDecoration, primitiveValue, tagName)
181     // m_propertyID is used in HTMLElementEquivalent::addToStyle
182 {
183 }
184
185 bool HTMLTextDecorationEquivalent::propertyExistsInStyle(CSSStyleDeclaration* style) const
186 {
187     return style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) || style->getPropertyCSSValue(CSSPropertyTextDecoration);
188 }
189
190 bool HTMLTextDecorationEquivalent::valueIsPresentInStyle(Element* element, CSSStyleDeclaration* style) const
191 {
192     RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
193     if (!styleValue)
194         styleValue = style->getPropertyCSSValue(CSSPropertyTextDecoration);
195     return matches(element) && styleValue && styleValue->isValueList() && static_cast<CSSValueList*>(styleValue.get())->hasValue(m_primitiveValue.get());
196 }
197
198 class HTMLAttributeEquivalent : public HTMLElementEquivalent {
199 public:
200     static PassOwnPtr<HTMLAttributeEquivalent> create(CSSPropertyID propertyID, const QualifiedName& tagName, const QualifiedName& attrName)
201     {
202         return adoptPtr(new HTMLAttributeEquivalent(propertyID, tagName, attrName));
203     }
204     static PassOwnPtr<HTMLAttributeEquivalent> create(CSSPropertyID propertyID, const QualifiedName& attrName)
205     {
206         return adoptPtr(new HTMLAttributeEquivalent(propertyID, attrName));
207     }
208
209     bool matches(const Element* elem) const { return HTMLElementEquivalent::matches(elem) && elem->hasAttribute(m_attrName); }
210     virtual bool hasAttribute() const { return true; }
211     virtual bool valueIsPresentInStyle(Element*, CSSStyleDeclaration*) const;
212     virtual void addToStyle(Element*, EditingStyle*) const;
213     virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
214     inline const QualifiedName& attributeName() const { return m_attrName; }
215
216 protected:
217     HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& tagName, const QualifiedName& attrName);
218     HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName);
219     const QualifiedName& m_attrName; // We can store a reference because HTML attribute names are const global.
220 };
221
222 HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& tagName, const QualifiedName& attrName)
223     : HTMLElementEquivalent(id, tagName)
224     , m_attrName(attrName)
225 {
226 }
227
228 HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, const QualifiedName& attrName)
229     : HTMLElementEquivalent(id)
230     , m_attrName(attrName)
231 {
232 }
233
234 bool HTMLAttributeEquivalent::valueIsPresentInStyle(Element* element, CSSStyleDeclaration* style) const
235 {
236     RefPtr<CSSValue> value = attributeValueAsCSSValue(element);
237     RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(m_propertyID);
238     
239     // FIXME: This is very inefficient way of comparing values
240     // but we can't string compare attribute value and CSS property value.
241     return value && styleValue && value->cssText() == styleValue->cssText();
242 }
243
244 void HTMLAttributeEquivalent::addToStyle(Element* element, EditingStyle* style) const
245 {
246     if (RefPtr<CSSValue> value = attributeValueAsCSSValue(element))
247         style->setProperty(m_propertyID, value->cssText());
248 }
249
250 PassRefPtr<CSSValue> HTMLAttributeEquivalent::attributeValueAsCSSValue(Element* element) const
251 {
252     ASSERT(element);
253     if (!element->hasAttribute(m_attrName))
254         return 0;
255     
256     RefPtr<CSSMutableStyleDeclaration> dummyStyle;
257     dummyStyle = CSSMutableStyleDeclaration::create();
258     dummyStyle->setProperty(m_propertyID, element->getAttribute(m_attrName));
259     return dummyStyle->getPropertyCSSValue(m_propertyID);
260 }
261
262 class HTMLFontSizeEquivalent : public HTMLAttributeEquivalent {
263 public:
264     static PassOwnPtr<HTMLFontSizeEquivalent> create()
265     {
266         return adoptPtr(new HTMLFontSizeEquivalent());
267     }
268     virtual PassRefPtr<CSSValue> attributeValueAsCSSValue(Element*) const;
269
270 private:
271     HTMLFontSizeEquivalent();
272 };
273
274 HTMLFontSizeEquivalent::HTMLFontSizeEquivalent()
275     : HTMLAttributeEquivalent(CSSPropertyFontSize, HTMLNames::fontTag, HTMLNames::sizeAttr)
276 {
277 }
278
279 PassRefPtr<CSSValue> HTMLFontSizeEquivalent::attributeValueAsCSSValue(Element* element) const
280 {
281     ASSERT(element);
282     if (!element->hasAttribute(m_attrName))
283         return 0;
284     int size;
285     if (!HTMLFontElement::cssValueFromFontSizeNumber(element->getAttribute(m_attrName), size))
286         return 0;
287     return CSSPrimitiveValue::createIdentifier(size);
288 }
289
290 float EditingStyle::NoFontDelta = 0.0f;
291
292 EditingStyle::EditingStyle()
293     : m_shouldUseFixedDefaultFontSize(false)
294     , m_fontSizeDelta(NoFontDelta)
295 {
296 }
297
298 EditingStyle::EditingStyle(Node* node, PropertiesToInclude propertiesToInclude)
299     : m_shouldUseFixedDefaultFontSize(false)
300     , m_fontSizeDelta(NoFontDelta)
301 {
302     init(node, propertiesToInclude);
303 }
304
305 EditingStyle::EditingStyle(const Position& position, PropertiesToInclude propertiesToInclude)
306     : m_shouldUseFixedDefaultFontSize(false)
307     , m_fontSizeDelta(NoFontDelta)
308 {
309     init(position.deprecatedNode(), propertiesToInclude);
310 }
311
312 EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
313     : m_mutableStyle(style ? style->copy() : 0)
314     , m_shouldUseFixedDefaultFontSize(false)
315     , m_fontSizeDelta(NoFontDelta)
316 {
317     extractFontSizeDelta();
318 }
319
320 EditingStyle::EditingStyle(int propertyID, const String& value)
321     : m_mutableStyle(0)
322     , m_shouldUseFixedDefaultFontSize(false)
323     , m_fontSizeDelta(NoFontDelta)
324 {
325     setProperty(propertyID, value);
326 }
327
328 EditingStyle::~EditingStyle()
329 {
330 }
331
332 static RGBA32 cssValueToRGBA(CSSValue* colorValue)
333 {
334     if (!colorValue || !colorValue->isPrimitiveValue())
335         return Color::transparent;
336     
337     CSSPrimitiveValue* primitiveColor = static_cast<CSSPrimitiveValue*>(colorValue);
338     if (primitiveColor->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR)
339         return primitiveColor->getRGBA32Value();
340     
341     RGBA32 rgba = 0;
342     CSSParser::parseColor(rgba, colorValue->cssText());
343     return rgba;
344 }
345
346 static inline RGBA32 getRGBAFontColor(CSSStyleDeclaration* style)
347 {
348     return cssValueToRGBA(style->getPropertyCSSValue(CSSPropertyColor).get());
349 }
350
351 static inline RGBA32 rgbaBackgroundColorInEffect(Node* node)
352 {
353     return cssValueToRGBA(backgroundColorInEffect(node).get());
354 }
355
356 void EditingStyle::init(Node* node, PropertiesToInclude propertiesToInclude)
357 {
358     if (isTabSpanTextNode(node))
359         node = tabSpanNode(node)->parentNode();
360     else if (isTabSpanNode(node))
361         node = node->parentNode();
362
363     RefPtr<CSSComputedStyleDeclaration> computedStyleAtPosition = computedStyle(node);
364     m_mutableStyle = propertiesToInclude == AllProperties && computedStyleAtPosition ? computedStyleAtPosition->copy() : editingStyleFromComputedStyle(computedStyleAtPosition);
365
366     if (propertiesToInclude == EditingPropertiesInEffect) {
367         if (RefPtr<CSSValue> value = backgroundColorInEffect(node))
368             m_mutableStyle->setProperty(CSSPropertyBackgroundColor, value->cssText());
369         if (RefPtr<CSSValue> value = computedStyleAtPosition->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect))
370             m_mutableStyle->setProperty(CSSPropertyTextDecoration, value->cssText());
371     }
372
373     if (node && node->computedStyle()) {
374         RenderStyle* renderStyle = node->computedStyle();
375         removeTextFillAndStrokeColorsIfNeeded(renderStyle);
376         replaceFontSizeByKeywordIfPossible(renderStyle, computedStyleAtPosition.get());
377     }
378
379     m_shouldUseFixedDefaultFontSize = computedStyleAtPosition->useFixedFontDefaultSize();
380     extractFontSizeDelta();
381 }
382
383 void EditingStyle::removeTextFillAndStrokeColorsIfNeeded(RenderStyle* renderStyle)
384 {
385     // If a node's text fill color is invalid, then its children use 
386     // their font-color as their text fill color (they don't
387     // inherit it).  Likewise for stroke color.
388     ExceptionCode ec = 0;
389     if (!renderStyle->textFillColor().isValid())
390         m_mutableStyle->removeProperty(CSSPropertyWebkitTextFillColor, ec);
391     if (!renderStyle->textStrokeColor().isValid())
392         m_mutableStyle->removeProperty(CSSPropertyWebkitTextStrokeColor, ec);
393     ASSERT(!ec);
394 }
395
396 void EditingStyle::setProperty(int propertyID, const String& value, bool important)
397 {
398     if (!m_mutableStyle)
399         m_mutableStyle = CSSMutableStyleDeclaration::create();
400
401     ExceptionCode ec;
402     m_mutableStyle->setProperty(propertyID, value, important, ec);
403 }
404
405 void EditingStyle::replaceFontSizeByKeywordIfPossible(RenderStyle* renderStyle, CSSComputedStyleDeclaration* computedStyle)
406 {
407     ASSERT(renderStyle);
408     if (renderStyle->fontDescription().keywordSize())
409         m_mutableStyle->setProperty(CSSPropertyFontSize, computedStyle->getFontSizeCSSValuePreferringKeyword()->cssText());
410 }
411
412 void EditingStyle::extractFontSizeDelta()
413 {
414     if (!m_mutableStyle)
415         return;
416
417     if (m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize)) {
418         // Explicit font size overrides any delta.
419         m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
420         return;
421     }
422
423     // Get the adjustment amount out of the style.
424     RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitFontSizeDelta);
425     if (!value || !value->isPrimitiveValue())
426         return;
427
428     CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value.get());
429
430     // Only PX handled now. If we handle more types in the future, perhaps
431     // a switch statement here would be more appropriate.
432     if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_PX)
433         return;
434
435     m_fontSizeDelta = primitiveValue->getFloatValue();
436     m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
437 }
438
439 bool EditingStyle::isEmpty() const
440 {
441     return (!m_mutableStyle || m_mutableStyle->isEmpty()) && m_fontSizeDelta == NoFontDelta;
442 }
443
444 bool EditingStyle::textDirection(WritingDirection& writingDirection) const
445 {
446     if (!m_mutableStyle)
447         return false;
448
449     RefPtr<CSSValue> unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
450     if (!unicodeBidi || !unicodeBidi->isPrimitiveValue())
451         return false;
452
453     int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
454     if (unicodeBidiValue == CSSValueEmbed) {
455         RefPtr<CSSValue> direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
456         if (!direction || !direction->isPrimitiveValue())
457             return false;
458
459         writingDirection = static_cast<CSSPrimitiveValue*>(direction.get())->getIdent() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
460
461         return true;
462     }
463
464     if (unicodeBidiValue == CSSValueNormal) {
465         writingDirection = NaturalWritingDirection;
466         return true;
467     }
468
469     return false;
470 }
471
472 void EditingStyle::setStyle(PassRefPtr<CSSMutableStyleDeclaration> style)
473 {
474     m_mutableStyle = style;
475     // FIXME: We should be able to figure out whether or not font is fixed width for mutable style.
476     // We need to check font-family is monospace as in FontDescription but we don't want to duplicate code here.
477     m_shouldUseFixedDefaultFontSize = false;
478     extractFontSizeDelta();
479 }
480
481 void EditingStyle::overrideWithStyle(const CSSMutableStyleDeclaration* style)
482 {
483     if (!style || !style->length())
484         return;
485     if (!m_mutableStyle)
486         m_mutableStyle = CSSMutableStyleDeclaration::create();
487     m_mutableStyle->merge(style);
488     extractFontSizeDelta();
489 }
490
491 void EditingStyle::clear()
492 {
493     m_mutableStyle.clear();
494     m_shouldUseFixedDefaultFontSize = false;
495     m_fontSizeDelta = NoFontDelta;
496 }
497
498 PassRefPtr<EditingStyle> EditingStyle::copy() const
499 {
500     RefPtr<EditingStyle> copy = EditingStyle::create();
501     if (m_mutableStyle)
502         copy->m_mutableStyle = m_mutableStyle->copy();
503     copy->m_shouldUseFixedDefaultFontSize = m_shouldUseFixedDefaultFontSize;
504     copy->m_fontSizeDelta = m_fontSizeDelta;
505     return copy;
506 }
507
508 PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveBlockProperties()
509 {
510     RefPtr<EditingStyle> blockProperties = EditingStyle::create();
511     if (!m_mutableStyle)
512         return blockProperties;
513
514     blockProperties->m_mutableStyle = m_mutableStyle->copyBlockProperties();
515     m_mutableStyle->removeBlockProperties();
516
517     return blockProperties;
518 }
519
520 PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveTextDirection()
521 {
522     RefPtr<EditingStyle> textDirection = EditingStyle::create();
523     textDirection->m_mutableStyle = CSSMutableStyleDeclaration::create();
524     textDirection->m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed, m_mutableStyle->getPropertyPriority(CSSPropertyUnicodeBidi));
525     textDirection->m_mutableStyle->setProperty(CSSPropertyDirection, m_mutableStyle->getPropertyValue(CSSPropertyDirection),
526         m_mutableStyle->getPropertyPriority(CSSPropertyDirection));
527
528     m_mutableStyle->removeProperty(CSSPropertyUnicodeBidi);
529     m_mutableStyle->removeProperty(CSSPropertyDirection);
530
531     return textDirection;
532 }
533
534 void EditingStyle::removeBlockProperties()
535 {
536     if (!m_mutableStyle)
537         return;
538
539     m_mutableStyle->removeBlockProperties();
540 }
541
542 void EditingStyle::removeStyleAddedByNode(Node* node)
543 {
544     if (!node || !node->parentNode())
545         return;
546     RefPtr<CSSMutableStyleDeclaration> parentStyle = editingStyleFromComputedStyle(computedStyle(node->parentNode()));
547     RefPtr<CSSMutableStyleDeclaration> nodeStyle = editingStyleFromComputedStyle(computedStyle(node));
548     parentStyle->diff(nodeStyle.get());
549     nodeStyle->diff(m_mutableStyle.get());
550 }
551
552 void EditingStyle::removeStyleConflictingWithStyleOfNode(Node* node)
553 {
554     if (!node || !node->parentNode() || !m_mutableStyle)
555         return;
556     RefPtr<CSSMutableStyleDeclaration> parentStyle = editingStyleFromComputedStyle(computedStyle(node->parentNode()));
557     RefPtr<CSSMutableStyleDeclaration> nodeStyle = editingStyleFromComputedStyle(computedStyle(node));
558     parentStyle->diff(nodeStyle.get());
559
560     CSSMutableStyleDeclaration::const_iterator end = nodeStyle->end();
561     for (CSSMutableStyleDeclaration::const_iterator it = nodeStyle->begin(); it != end; ++it)
562         m_mutableStyle->removeProperty(it->id());
563 }
564
565 void EditingStyle::removeNonEditingProperties()
566 {
567     if (m_mutableStyle)
568         m_mutableStyle = copyEditingProperties(m_mutableStyle.get());
569 }
570
571 void EditingStyle::collapseTextDecorationProperties()
572 {
573     if (!m_mutableStyle)
574         return;
575
576     RefPtr<CSSValue> textDecorationsInEffect = m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
577     if (!textDecorationsInEffect)
578         return;
579
580     if (textDecorationsInEffect->isValueList())
581         m_mutableStyle->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText(), m_mutableStyle->getPropertyPriority(CSSPropertyTextDecoration));
582     else
583         m_mutableStyle->removeProperty(CSSPropertyTextDecoration);
584     m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
585 }
586
587 // CSS properties that create a visual difference only when applied to text.
588 static const int textOnlyProperties[] = {
589     CSSPropertyTextDecoration,
590     CSSPropertyWebkitTextDecorationsInEffect,
591     CSSPropertyFontStyle,
592     CSSPropertyFontWeight,
593     CSSPropertyColor,
594 };
595
596 TriState EditingStyle::triStateOfStyle(EditingStyle* style) const
597 {
598     if (!style || !style->m_mutableStyle)
599         return FalseTriState;
600     return triStateOfStyle(style->m_mutableStyle.get(), DoNotIgnoreTextOnlyProperties);
601 }
602
603 TriState EditingStyle::triStateOfStyle(CSSStyleDeclaration* styleToCompare, ShouldIgnoreTextOnlyProperties shouldIgnoreTextOnlyProperties) const
604 {
605     RefPtr<CSSMutableStyleDeclaration> difference = getPropertiesNotIn(m_mutableStyle.get(), styleToCompare);
606
607     if (shouldIgnoreTextOnlyProperties == IgnoreTextOnlyProperties)
608         difference->removePropertiesInSet(textOnlyProperties, WTF_ARRAY_LENGTH(textOnlyProperties));
609
610     if (!difference->length())
611         return TrueTriState;
612     if (difference->length() == m_mutableStyle->length())
613         return FalseTriState;
614
615     return MixedTriState;
616 }
617
618 TriState EditingStyle::triStateOfStyle(const VisibleSelection& selection) const
619 {
620     if (!selection.isCaretOrRange())
621         return FalseTriState;
622
623     if (selection.isCaret())
624         return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection).get());
625
626     TriState state = FalseTriState;
627     for (Node* node = selection.start().deprecatedNode(); node; node = node->traverseNextNode()) {
628         RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
629         if (nodeStyle) {
630             TriState nodeState = triStateOfStyle(nodeStyle.get(), node->isTextNode() ? EditingStyle::DoNotIgnoreTextOnlyProperties : EditingStyle::IgnoreTextOnlyProperties);
631             if (node == selection.start().deprecatedNode())
632                 state = nodeState;
633             else if (state != nodeState && node->isTextNode()) {
634                 state = MixedTriState;
635                 break;
636             }
637         }
638         if (node == selection.end().deprecatedNode())
639             break;
640     }
641
642     return state;
643 }
644
645 bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const
646 {
647     ASSERT(element);
648     ASSERT(!conflictingProperties || conflictingProperties->isEmpty());
649
650     CSSMutableStyleDeclaration* inlineStyle = element->inlineStyleDecl();
651     if (!m_mutableStyle || !inlineStyle)
652         return false;
653
654     CSSMutableStyleDeclaration::const_iterator end = m_mutableStyle->end();
655     for (CSSMutableStyleDeclaration::const_iterator it = m_mutableStyle->begin(); it != end; ++it) {
656         CSSPropertyID propertyID = static_cast<CSSPropertyID>(it->id());
657
658         // We don't override whitespace property of a tab span because that would collapse the tab into a space.
659         if (propertyID == CSSPropertyWhiteSpace && isTabSpanNode(element))
660             continue;
661
662         if (propertyID == CSSPropertyWebkitTextDecorationsInEffect && inlineStyle->getPropertyCSSValue(CSSPropertyTextDecoration)) {
663             if (!conflictingProperties)
664                 return true;
665             conflictingProperties->append(CSSPropertyTextDecoration);
666             if (extractedStyle)
667                 extractedStyle->setProperty(CSSPropertyTextDecoration, inlineStyle->getPropertyValue(CSSPropertyTextDecoration), inlineStyle->getPropertyPriority(CSSPropertyTextDecoration));
668             continue;
669         }
670
671         if (!inlineStyle->getPropertyCSSValue(propertyID))
672             continue;
673
674         if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) {
675             if (!conflictingProperties)
676                 return true;
677             conflictingProperties->append(CSSPropertyDirection);
678             if (extractedStyle)
679                 extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->getPropertyPriority(propertyID));
680         }
681
682         if (!conflictingProperties)
683             return true;
684
685         conflictingProperties->append(propertyID);
686
687         if (extractedStyle)
688             extractedStyle->setProperty(propertyID, inlineStyle->getPropertyValue(propertyID), inlineStyle->getPropertyPriority(propertyID));
689     }
690
691     return conflictingProperties && !conflictingProperties->isEmpty();
692 }
693
694 static const Vector<OwnPtr<HTMLElementEquivalent> >& htmlElementEquivalents()
695 {
696     DEFINE_STATIC_LOCAL(Vector<OwnPtr<HTMLElementEquivalent> >, HTMLElementEquivalents, ());
697
698     if (!HTMLElementEquivalents.size()) {
699         HTMLElementEquivalents.append(HTMLElementEquivalent::create(CSSPropertyFontWeight, CSSValueBold, HTMLNames::bTag));
700         HTMLElementEquivalents.append(HTMLElementEquivalent::create(CSSPropertyFontWeight, CSSValueBold, HTMLNames::strongTag));
701         HTMLElementEquivalents.append(HTMLElementEquivalent::create(CSSPropertyVerticalAlign, CSSValueSub, HTMLNames::subTag));
702         HTMLElementEquivalents.append(HTMLElementEquivalent::create(CSSPropertyVerticalAlign, CSSValueSuper, HTMLNames::supTag));
703         HTMLElementEquivalents.append(HTMLElementEquivalent::create(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::iTag));
704         HTMLElementEquivalents.append(HTMLElementEquivalent::create(CSSPropertyFontStyle, CSSValueItalic, HTMLNames::emTag));
705
706         HTMLElementEquivalents.append(HTMLTextDecorationEquivalent::create(CSSValueUnderline, HTMLNames::uTag));
707         HTMLElementEquivalents.append(HTMLTextDecorationEquivalent::create(CSSValueLineThrough, HTMLNames::sTag));
708         HTMLElementEquivalents.append(HTMLTextDecorationEquivalent::create(CSSValueLineThrough, HTMLNames::strikeTag));
709     }
710
711     return HTMLElementEquivalents;
712 }
713
714
715 bool EditingStyle::conflictsWithImplicitStyleOfElement(HTMLElement* element, EditingStyle* extractedStyle, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
716 {
717     if (!m_mutableStyle)
718         return false;
719
720     const Vector<OwnPtr<HTMLElementEquivalent> >& HTMLElementEquivalents = htmlElementEquivalents();
721     for (size_t i = 0; i < HTMLElementEquivalents.size(); ++i) {
722         const HTMLElementEquivalent* equivalent = HTMLElementEquivalents[i].get();
723         if (equivalent->matches(element) && equivalent->propertyExistsInStyle(m_mutableStyle.get())
724             && (shouldExtractMatchingStyle == ExtractMatchingStyle || !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))) {
725             if (extractedStyle)
726                 equivalent->addToStyle(element, extractedStyle);
727             return true;
728         }
729     }
730     return false;
731 }
732
733 static const Vector<OwnPtr<HTMLAttributeEquivalent> >& htmlAttributeEquivalents()
734 {
735     DEFINE_STATIC_LOCAL(Vector<OwnPtr<HTMLAttributeEquivalent> >, HTMLAttributeEquivalents, ());
736
737     if (!HTMLAttributeEquivalents.size()) {
738         // elementIsStyledSpanOrHTMLEquivalent depends on the fact each HTMLAttriuteEquivalent matches exactly one attribute
739         // of exactly one element except dirAttr.
740         HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyColor, HTMLNames::fontTag, HTMLNames::colorAttr));
741         HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyFontFamily, HTMLNames::fontTag, HTMLNames::faceAttr));
742         HTMLAttributeEquivalents.append(HTMLFontSizeEquivalent::create());
743
744         HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyDirection, HTMLNames::dirAttr));
745         HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create(CSSPropertyUnicodeBidi, HTMLNames::dirAttr));
746     }
747
748     return HTMLAttributeEquivalents;
749 }
750
751 bool EditingStyle::conflictsWithImplicitStyleOfAttributes(HTMLElement* element) const
752 {
753     ASSERT(element);
754     if (!m_mutableStyle)
755         return false;
756
757     const Vector<OwnPtr<HTMLAttributeEquivalent> >& HTMLAttributeEquivalents = htmlAttributeEquivalents();
758     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
759         if (HTMLAttributeEquivalents[i]->matches(element) && HTMLAttributeEquivalents[i]->propertyExistsInStyle(m_mutableStyle.get())
760             && !HTMLAttributeEquivalents[i]->valueIsPresentInStyle(element, m_mutableStyle.get()))
761             return true;
762     }
763
764     return false;
765 }
766
767 bool EditingStyle::extractConflictingImplicitStyleOfAttributes(HTMLElement* element, ShouldPreserveWritingDirection shouldPreserveWritingDirection,
768     EditingStyle* extractedStyle, Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle shouldExtractMatchingStyle) const
769 {
770     ASSERT(element);
771     // HTMLAttributeEquivalent::addToStyle doesn't support unicode-bidi and direction properties
772     ASSERT(!extractedStyle || shouldPreserveWritingDirection == PreserveWritingDirection);
773     if (!m_mutableStyle)
774         return false;
775
776     const Vector<OwnPtr<HTMLAttributeEquivalent> >& HTMLAttributeEquivalents = htmlAttributeEquivalents();
777     bool removed = false;
778     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
779         const HTMLAttributeEquivalent* equivalent = HTMLAttributeEquivalents[i].get();
780
781         // unicode-bidi and direction are pushed down separately so don't push down with other styles.
782         if (shouldPreserveWritingDirection == PreserveWritingDirection && equivalent->attributeName() == HTMLNames::dirAttr)
783             continue;
784
785         if (!equivalent->matches(element) || !equivalent->propertyExistsInStyle(m_mutableStyle.get())
786             || (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && equivalent->valueIsPresentInStyle(element, m_mutableStyle.get())))
787             continue;
788
789         if (extractedStyle)
790             equivalent->addToStyle(element, extractedStyle);
791         conflictingAttributes.append(equivalent->attributeName());
792         removed = true;
793     }
794
795     return removed;
796 }
797
798 bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const
799 {
800     return !m_mutableStyle || !getPropertiesNotIn(m_mutableStyle.get(), computedStyle(node).get())->length();
801 }
802
803 bool EditingStyle::elementIsStyledSpanOrHTMLEquivalent(const HTMLElement* element)
804 {
805     bool elementIsSpanOrElementEquivalent = false;
806     if (element->hasTagName(HTMLNames::spanTag))
807         elementIsSpanOrElementEquivalent = true;
808     else {
809         const Vector<OwnPtr<HTMLElementEquivalent> >& HTMLElementEquivalents = htmlElementEquivalents();
810         size_t i;
811         for (i = 0; i < HTMLElementEquivalents.size(); ++i) {
812             if (HTMLElementEquivalents[i]->matches(element)) {
813                 elementIsSpanOrElementEquivalent = true;
814                 break;
815             }
816         }
817     }
818
819     const NamedNodeMap* attributeMap = element->attributeMap();
820     if (!attributeMap || attributeMap->isEmpty())
821         return elementIsSpanOrElementEquivalent; // span, b, etc... without any attributes
822
823     unsigned matchedAttributes = 0;
824     const Vector<OwnPtr<HTMLAttributeEquivalent> >& HTMLAttributeEquivalents = htmlAttributeEquivalents();
825     for (size_t i = 0; i < HTMLAttributeEquivalents.size(); ++i) {
826         if (HTMLAttributeEquivalents[i]->matches(element) && HTMLAttributeEquivalents[i]->attributeName() != HTMLNames::dirAttr)
827             matchedAttributes++;
828     }
829
830     if (!elementIsSpanOrElementEquivalent && !matchedAttributes)
831         return false; // element is not a span, a html element equivalent, or font element.
832     
833     if (element->getAttribute(HTMLNames::classAttr) == AppleStyleSpanClass)
834         matchedAttributes++;
835
836     if (element->hasAttribute(HTMLNames::styleAttr)) {
837         if (CSSMutableStyleDeclaration* style = element->inlineStyleDecl()) {
838             CSSMutableStyleDeclaration::const_iterator end = style->end();
839             for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
840                 if (!isEditingProperty(it->id()))
841                     return false;
842             }
843         }
844         matchedAttributes++;
845     }
846
847     // font with color attribute, span with style attribute, etc...
848     ASSERT(matchedAttributes <= attributeMap->length());
849     return matchedAttributes >= attributeMap->length();
850 }
851
852 void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
853 {
854     if (!m_mutableStyle)
855         return;
856
857     // ReplaceSelectionCommand::handleStyleSpans() requires that this function only removes the editing style.
858     // If this function was modified in the future to delete all redundant properties, then add a boolean value to indicate
859     // which one of editingStyleAtPosition or computedStyle is called.
860     RefPtr<EditingStyle> style = EditingStyle::create(position, EditingPropertiesInEffect);
861
862     RefPtr<CSSValue> unicodeBidi;
863     RefPtr<CSSValue> direction;
864     if (shouldPreserveWritingDirection == PreserveWritingDirection) {
865         unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
866         direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
867     }
868
869     style->m_mutableStyle->diff(m_mutableStyle.get());
870     if (getRGBAFontColor(m_mutableStyle.get()) == getRGBAFontColor(style->m_mutableStyle.get()))
871         m_mutableStyle->removeProperty(CSSPropertyColor);
872
873     if (hasTransparentBackgroundColor(m_mutableStyle.get())
874         || cssValueToRGBA(m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor).get()) == rgbaBackgroundColorInEffect(position.containerNode()))
875         m_mutableStyle->removeProperty(CSSPropertyBackgroundColor);
876
877     if (unicodeBidi && unicodeBidi->isPrimitiveValue()) {
878         m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent());
879         if (direction && direction->isPrimitiveValue())
880             m_mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSPrimitiveValue*>(direction.get())->getIdent());
881     }
882 }
883
884 void EditingStyle::mergeTypingStyle(Document* document)
885 {
886     ASSERT(document);
887
888     RefPtr<EditingStyle> typingStyle = document->frame()->selection()->typingStyle();
889     if (!typingStyle || typingStyle == this)
890         return;
891
892     mergeStyle(typingStyle->style(), OverrideValues);
893 }
894
895 void EditingStyle::mergeInlineStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
896 {
897     ASSERT(element);
898     if (!element->inlineStyleDecl())
899         return;
900
901     switch (propertiesToInclude) {
902     case AllProperties:
903         mergeStyle(element->inlineStyleDecl(), mode);
904         return;
905     case OnlyEditingInheritableProperties:
906     case EditingPropertiesInEffect:
907         mergeStyle(copyEditingProperties(element->inlineStyleDecl(), propertiesToInclude == EditingPropertiesInEffect).get(), mode);
908         return;
909     }
910 }
911
912 static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl(const HTMLElementEquivalent* equivalent, const StyledElement* element,
913     EditingStyle::CSSPropertyOverrideMode mode, CSSMutableStyleDeclaration* style)
914 {
915     return equivalent->matches(element) && !equivalent->propertyExistsInStyle(element->inlineStyleDecl())
916         && (mode == EditingStyle::OverrideValues || !equivalent->propertyExistsInStyle(style));
917 }
918
919 void EditingStyle::mergeInlineAndImplicitStyleOfElement(StyledElement* element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude)
920 {
921     mergeInlineStyleOfElement(element, mode, propertiesToInclude);
922
923     const Vector<OwnPtr<HTMLElementEquivalent> >& elementEquivalents = htmlElementEquivalents();
924     for (size_t i = 0; i < elementEquivalents.size(); ++i) {
925         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(elementEquivalents[i].get(), element, mode, m_mutableStyle.get()))
926             elementEquivalents[i]->addToStyle(element, this);
927     }
928
929     const Vector<OwnPtr<HTMLAttributeEquivalent> >& attributeEquivalents = htmlAttributeEquivalents();
930     for (size_t i = 0; i < attributeEquivalents.size(); ++i) {
931         if (attributeEquivalents[i]->attributeName() == HTMLNames::dirAttr)
932             continue; // We don't want to include directionality
933         if (elementMatchesAndPropertyIsNotInInlineStyleDecl(attributeEquivalents[i].get(), element, mode, m_mutableStyle.get()))
934             attributeEquivalents[i]->addToStyle(element, this);
935     }
936 }
937
938 PassRefPtr<EditingStyle> EditingStyle::wrappingStyleForSerialization(Node* context, bool shouldAnnotate)
939 {
940     RefPtr<EditingStyle> wrappingStyle;
941     if (shouldAnnotate) {
942         wrappingStyle = EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect);
943
944         // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote,
945         // to help us differentiate those styles from ones that the user has applied.
946         // This helps us get the color of content pasted into blockquotes right.
947         wrappingStyle->removeStyleAddedByNode(enclosingNodeOfType(firstPositionInOrBeforeNode(context), isMailBlockquote, CanCrossEditingBoundary));
948
949         // Call collapseTextDecorationProperties first or otherwise it'll copy the value over from in-effect to text-decorations.
950         wrappingStyle->collapseTextDecorationProperties();
951         
952         return wrappingStyle.release();
953     }
954
955     wrappingStyle = EditingStyle::create();
956
957     // When not annotating for interchange, we only preserve inline style declarations.
958     for (Node* node = context; node && !node->isDocumentNode(); node = node->parentNode()) {
959         if (node->isStyledElement()) {
960             wrappingStyle->mergeInlineAndImplicitStyleOfElement(static_cast<StyledElement*>(node), EditingStyle::DoNotOverrideValues,
961                 EditingStyle::EditingPropertiesInEffect);
962         }
963     }
964
965     return wrappingStyle.release();
966 }
967
968
969 static void mergeTextDecorationValues(CSSValueList* mergedValue, const CSSValueList* valueToMerge)
970 {
971     DEFINE_STATIC_LOCAL(const RefPtr<CSSPrimitiveValue>, underline, (CSSPrimitiveValue::createIdentifier(CSSValueUnderline)));
972     DEFINE_STATIC_LOCAL(const RefPtr<CSSPrimitiveValue>, lineThrough, (CSSPrimitiveValue::createIdentifier(CSSValueLineThrough)));
973
974     if (valueToMerge->hasValue(underline.get()) && !mergedValue->hasValue(underline.get()))
975         mergedValue->append(underline.get());
976
977     if (valueToMerge->hasValue(lineThrough.get()) && !mergedValue->hasValue(lineThrough.get()))
978         mergedValue->append(lineThrough.get());
979 }
980
981 void EditingStyle::mergeStyle(CSSMutableStyleDeclaration* style, CSSPropertyOverrideMode mode)
982 {
983     if (!style)
984         return;
985
986     if (!m_mutableStyle) {
987         m_mutableStyle = style->copy();
988         return;
989     }
990
991     CSSMutableStyleDeclaration::const_iterator end = style->end();
992     for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
993         RefPtr<CSSValue> value = m_mutableStyle->getPropertyCSSValue(it->id());
994         ExceptionCode ec;
995
996         // text decorations never override values
997         if ((it->id() == CSSPropertyTextDecoration || it->id() == CSSPropertyWebkitTextDecorationsInEffect) && it->value()->isValueList() && value) {
998             if (value->isValueList()) {
999                 mergeTextDecorationValues(static_cast<CSSValueList*>(value.get()), static_cast<CSSValueList*>(it->value()));
1000                 continue;
1001             }
1002             value = 0; // text-decoration: none is equivalent to not having the property
1003         }
1004
1005         if (mode == OverrideValues || (mode == DoNotOverrideValues && !value))
1006             m_mutableStyle->setProperty(it->id(), it->value()->cssText(), it->isImportant(), ec);
1007     }
1008 }
1009
1010 static PassRefPtr<CSSMutableStyleDeclaration> styleFromMatchedRulesForElement(Element* element, unsigned rulesToInclude)
1011 {
1012     RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
1013     RefPtr<CSSRuleList> matchedRules = element->document()->styleSelector()->styleRulesForElement(element, rulesToInclude);
1014     if (matchedRules) {
1015         for (unsigned i = 0; i < matchedRules->length(); i++) {
1016             if (matchedRules->item(i)->type() == CSSRule::STYLE_RULE) {
1017                 RefPtr<CSSMutableStyleDeclaration> s = static_cast<CSSStyleRule*>(matchedRules->item(i))->style();
1018                 style->merge(s.get(), true);
1019             }
1020         }
1021     }
1022     
1023     return style.release();
1024 }
1025
1026 void EditingStyle::mergeStyleFromRules(StyledElement* element)
1027 {
1028     RefPtr<CSSMutableStyleDeclaration> styleFromMatchedRules = styleFromMatchedRulesForElement(element,
1029         CSSStyleSelector::AuthorCSSRules | CSSStyleSelector::CrossOriginCSSRules);
1030     // Styles from the inline style declaration, held in the variable "style", take precedence 
1031     // over those from matched rules.
1032     if (m_mutableStyle)
1033         styleFromMatchedRules->merge(m_mutableStyle.get());
1034
1035     clear();
1036     m_mutableStyle = styleFromMatchedRules;
1037 }
1038
1039 void EditingStyle::mergeStyleFromRulesForSerialization(StyledElement* element)
1040 {
1041     mergeStyleFromRules(element);
1042
1043     // The property value, if it's a percentage, may not reflect the actual computed value.  
1044     // For example: style="height: 1%; overflow: visible;" in quirksmode
1045     // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot copy/paste fidelity problem
1046     RefPtr<CSSComputedStyleDeclaration> computedStyleForElement = computedStyle(element);
1047     RefPtr<CSSMutableStyleDeclaration> fromComputedStyle = CSSMutableStyleDeclaration::create();
1048     {
1049         CSSMutableStyleDeclaration::const_iterator end = m_mutableStyle->end();
1050         for (CSSMutableStyleDeclaration::const_iterator it = m_mutableStyle->begin(); it != end; ++it) {
1051             const CSSProperty& property = *it;
1052             CSSValue* value = property.value();
1053             if (!value->isPrimitiveValue())
1054                 continue;
1055             if (static_cast<CSSPrimitiveValue*>(value)->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) {
1056                 if (RefPtr<CSSValue> computedPropertyValue = computedStyleForElement->getPropertyCSSValue(property.id()))
1057                     fromComputedStyle->addParsedProperty(CSSProperty(property.id(), computedPropertyValue));
1058             }
1059         }
1060     }
1061     m_mutableStyle->merge(fromComputedStyle.get());
1062 }
1063
1064 static void removePropertiesInStyle(CSSMutableStyleDeclaration* styleToRemovePropertiesFrom, CSSMutableStyleDeclaration* style)
1065 {
1066     Vector<int> propertiesToRemove(style->length());
1067     size_t i = 0;
1068     CSSMutableStyleDeclaration::const_iterator end = style->end();
1069     for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it, ++i)
1070         propertiesToRemove[i] = it->id();
1071
1072     styleToRemovePropertiesFrom->removePropertiesInSet(propertiesToRemove.data(), propertiesToRemove.size());
1073 }
1074
1075 void EditingStyle::removeStyleFromRulesAndContext(StyledElement* element, Node* context)
1076 {
1077     ASSERT(element);
1078     if (!m_mutableStyle)
1079         return;
1080
1081     // 1. Remove style from matched rules because style remain without repeating it in inline style declaration
1082     RefPtr<CSSMutableStyleDeclaration> styleFromMatchedRules = styleFromMatchedRulesForElement(element, CSSStyleSelector::AllButEmptyCSSRules);
1083     if (styleFromMatchedRules && styleFromMatchedRules->length())
1084         m_mutableStyle = getPropertiesNotIn(m_mutableStyle.get(), styleFromMatchedRules.get());
1085
1086     // 2. Remove style present in context and not overriden by matched rules.
1087     RefPtr<EditingStyle> computedStyle = EditingStyle::create(context, EditingPropertiesInEffect);
1088     if (computedStyle->m_mutableStyle) {
1089         if (!computedStyle->m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor))
1090             computedStyle->m_mutableStyle->setProperty(CSSPropertyBackgroundColor, CSSValueTransparent);
1091
1092         removePropertiesInStyle(computedStyle->m_mutableStyle.get(), styleFromMatchedRules.get());
1093         m_mutableStyle = getPropertiesNotIn(m_mutableStyle.get(), computedStyle->m_mutableStyle.get());
1094     }
1095
1096     // 3. If this element is a span and has display: inline or float: none, remove them unless they are overriden by rules.
1097     // These rules are added by serialization code to wrap text nodes.
1098     if (isStyleSpanOrSpanWithOnlyStyleAttribute(element)) {
1099         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyDisplay) && getIdentifierValue(m_mutableStyle.get(), CSSPropertyDisplay) == CSSValueInline)
1100             m_mutableStyle->removeProperty(CSSPropertyDisplay);
1101         if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyFloat) && getIdentifierValue(m_mutableStyle.get(), CSSPropertyFloat) == CSSValueNone)
1102             m_mutableStyle->removeProperty(CSSPropertyFloat);
1103     }
1104 }
1105
1106 void EditingStyle::removePropertiesInElementDefaultStyle(Element* element)
1107 {
1108     if (!m_mutableStyle || !m_mutableStyle->length())
1109         return;
1110
1111     RefPtr<CSSMutableStyleDeclaration> defaultStyle = styleFromMatchedRulesForElement(element, CSSStyleSelector::UAAndUserCSSRules);
1112
1113     removePropertiesInStyle(m_mutableStyle.get(), defaultStyle.get());
1114 }
1115
1116 void EditingStyle::forceInline()
1117 {
1118     if (!m_mutableStyle)
1119         m_mutableStyle = CSSMutableStyleDeclaration::create();
1120     const bool propertyIsImportant = true;
1121     m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline, propertyIsImportant);
1122 }
1123
1124 int EditingStyle::legacyFontSize(Document* document) const
1125 {
1126     RefPtr<CSSValue> cssValue = m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize);
1127     if (!cssValue || !cssValue->isPrimitiveValue())
1128         return 0;
1129     return legacyFontSizeFromCSSValue(document, static_cast<CSSPrimitiveValue*>(cssValue.get()),
1130         m_shouldUseFixedDefaultFontSize, AlwaysUseLegacyFontSize);
1131 }
1132
1133 PassRefPtr<EditingStyle> EditingStyle::styleAtSelectionStart(const VisibleSelection& selection, bool shouldUseBackgroundColorInEffect)
1134 {
1135     if (selection.isNone())
1136         return 0;
1137
1138     Position position = adjustedSelectionStartForStyleComputation(selection);
1139
1140     // If the pos is at the end of a text node, then this node is not fully selected. 
1141     // Move it to the next deep equivalent position to avoid removing the style from this node. 
1142     // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we want Position("world", 0) instead. 
1143     // We only do this for range because caret at Position("hello", 5) in <b>hello</b>world should give you font-weight: bold. 
1144     Node* positionNode = position.containerNode(); 
1145     if (selection.isRange() && positionNode && positionNode->isTextNode() && position.computeOffsetInContainerNode() == positionNode->maxCharacterOffset()) 
1146         position = nextVisuallyDistinctCandidate(position); 
1147
1148     Element* element = position.element();
1149     if (!element)
1150         return 0;
1151
1152     RefPtr<EditingStyle> style = EditingStyle::create(element, EditingStyle::AllProperties);
1153     style->mergeTypingStyle(element->document());
1154
1155     // If background color is transparent, traverse parent nodes until we hit a different value or document root
1156     // Also, if the selection is a range, ignore the background color at the start of selection,
1157     // and find the background color of the common ancestor.
1158     if (shouldUseBackgroundColorInEffect && (selection.isRange() || hasTransparentBackgroundColor(style->m_mutableStyle.get()))) {
1159         RefPtr<Range> range(selection.toNormalizedRange());
1160         ExceptionCode ec = 0;
1161         if (PassRefPtr<CSSValue> value = backgroundColorInEffect(range->commonAncestorContainer(ec)))
1162             style->setProperty(CSSPropertyBackgroundColor, value->cssText());
1163     }
1164
1165     return style;
1166 }
1167
1168 static void reconcileTextDecorationProperties(CSSMutableStyleDeclaration* style)
1169 {    
1170     RefPtr<CSSValue> textDecorationsInEffect = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
1171     RefPtr<CSSValue> textDecoration = style->getPropertyCSSValue(CSSPropertyTextDecoration);
1172     // We shouldn't have both text-decoration and -webkit-text-decorations-in-effect because that wouldn't make sense.
1173     ASSERT(!textDecorationsInEffect || !textDecoration);
1174     if (textDecorationsInEffect) {
1175         style->setProperty(CSSPropertyTextDecoration, textDecorationsInEffect->cssText());
1176         style->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
1177         textDecoration = textDecorationsInEffect;
1178     }
1179
1180     // If text-decoration is set to "none", remove the property because we don't want to add redundant "text-decoration: none".
1181     if (textDecoration && !textDecoration->isValueList())
1182         style->removeProperty(CSSPropertyTextDecoration);
1183 }
1184
1185 StyleChange::StyleChange(EditingStyle* style, const Position& position)
1186     : m_applyBold(false)
1187     , m_applyItalic(false)
1188     , m_applyUnderline(false)
1189     , m_applyLineThrough(false)
1190     , m_applySubscript(false)
1191     , m_applySuperscript(false)
1192 {
1193     Document* document = position.anchorNode() ? position.anchorNode()->document() : 0;
1194     if (!style || !style->style() || !document || !document->frame())
1195         return;
1196
1197     RefPtr<CSSComputedStyleDeclaration> computedStyle = position.computedStyle();
1198     // FIXME: take care of background-color in effect
1199     RefPtr<CSSMutableStyleDeclaration> mutableStyle = getPropertiesNotIn(style->style(), computedStyle.get());
1200
1201     reconcileTextDecorationProperties(mutableStyle.get());
1202     if (!document->frame()->editor()->shouldStyleWithCSS())
1203         extractTextStyles(document, mutableStyle.get(), computedStyle->useFixedFontDefaultSize());
1204
1205     // Changing the whitespace style in a tab span would collapse the tab into a space.
1206     if (isTabSpanTextNode(position.deprecatedNode()) || isTabSpanNode((position.deprecatedNode())))
1207         mutableStyle->removeProperty(CSSPropertyWhiteSpace);
1208
1209     // If unicode-bidi is present in mutableStyle and direction is not, then add direction to mutableStyle.
1210     // FIXME: Shouldn't this be done in getPropertiesNotIn?
1211     if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->style()->getPropertyCSSValue(CSSPropertyDirection))
1212         mutableStyle->setProperty(CSSPropertyDirection, style->style()->getPropertyValue(CSSPropertyDirection));
1213
1214     // Save the result for later
1215     m_cssStyle = mutableStyle->cssText().stripWhiteSpace();
1216 }
1217
1218 static void setTextDecorationProperty(CSSMutableStyleDeclaration* style, const CSSValueList* newTextDecoration, int propertyID)
1219 {
1220     if (newTextDecoration->length())
1221         style->setProperty(propertyID, newTextDecoration->cssText(), style->getPropertyPriority(propertyID));
1222     else {
1223         // text-decoration: none is redundant since it does not remove any text decorations.
1224         ASSERT(!style->getPropertyPriority(propertyID));
1225         style->removeProperty(propertyID);
1226     }
1227 }
1228
1229 void StyleChange::extractTextStyles(Document* document, CSSMutableStyleDeclaration* style, bool shouldUseFixedFontDefaultSize)
1230 {
1231     ASSERT(style);
1232
1233     if (getIdentifierValue(style, CSSPropertyFontWeight) == CSSValueBold) {
1234         style->removeProperty(CSSPropertyFontWeight);
1235         m_applyBold = true;
1236     }
1237
1238     int fontStyle = getIdentifierValue(style, CSSPropertyFontStyle);
1239     if (fontStyle == CSSValueItalic || fontStyle == CSSValueOblique) {
1240         style->removeProperty(CSSPropertyFontStyle);
1241         m_applyItalic = true;
1242     }
1243
1244     // Assuming reconcileTextDecorationProperties has been called, there should not be -webkit-text-decorations-in-effect
1245     // Furthermore, text-decoration: none has been trimmed so that text-decoration property is always a CSSValueList.
1246     RefPtr<CSSValue> textDecoration = style->getPropertyCSSValue(CSSPropertyTextDecoration);
1247     if (textDecoration && textDecoration->isValueList()) {
1248         DEFINE_STATIC_LOCAL(RefPtr<CSSPrimitiveValue>, underline, (CSSPrimitiveValue::createIdentifier(CSSValueUnderline)));
1249         DEFINE_STATIC_LOCAL(RefPtr<CSSPrimitiveValue>, lineThrough, (CSSPrimitiveValue::createIdentifier(CSSValueLineThrough)));
1250
1251         RefPtr<CSSValueList> newTextDecoration = static_cast<CSSValueList*>(textDecoration.get())->copy();
1252         if (newTextDecoration->removeAll(underline.get()))
1253             m_applyUnderline = true;
1254         if (newTextDecoration->removeAll(lineThrough.get()))
1255             m_applyLineThrough = true;
1256
1257         // If trimTextDecorations, delete underline and line-through
1258         setTextDecorationProperty(style, newTextDecoration.get(), CSSPropertyTextDecoration);
1259     }
1260
1261     int verticalAlign = getIdentifierValue(style, CSSPropertyVerticalAlign);
1262     switch (verticalAlign) {
1263     case CSSValueSub:
1264         style->removeProperty(CSSPropertyVerticalAlign);
1265         m_applySubscript = true;
1266         break;
1267     case CSSValueSuper:
1268         style->removeProperty(CSSPropertyVerticalAlign);
1269         m_applySuperscript = true;
1270         break;
1271     }
1272
1273     if (style->getPropertyCSSValue(CSSPropertyColor)) {
1274         m_applyFontColor = Color(getRGBAFontColor(style)).serialized();
1275         style->removeProperty(CSSPropertyColor);
1276     }
1277
1278     m_applyFontFace = style->getPropertyValue(CSSPropertyFontFamily);
1279     style->removeProperty(CSSPropertyFontFamily);
1280
1281     if (RefPtr<CSSValue> fontSize = style->getPropertyCSSValue(CSSPropertyFontSize)) {
1282         if (!fontSize->isPrimitiveValue())
1283             style->removeProperty(CSSPropertyFontSize); // Can't make sense of the number. Put no font size.
1284         else if (int legacyFontSize = legacyFontSizeFromCSSValue(document, static_cast<CSSPrimitiveValue*>(fontSize.get()),
1285                 shouldUseFixedFontDefaultSize, UseLegacyFontSizeOnlyIfPixelValuesMatch)) {
1286             m_applyFontSize = String::number(legacyFontSize);
1287             style->removeProperty(CSSPropertyFontSize);
1288         }
1289     }
1290 }
1291
1292 static void diffTextDecorations(CSSMutableStyleDeclaration* style, int propertID, CSSValue* refTextDecoration)
1293 {
1294     RefPtr<CSSValue> textDecoration = style->getPropertyCSSValue(propertID);
1295     if (!textDecoration || !textDecoration->isValueList() || !refTextDecoration || !refTextDecoration->isValueList())
1296         return;
1297
1298     RefPtr<CSSValueList> newTextDecoration = static_cast<CSSValueList*>(textDecoration.get())->copy();
1299     CSSValueList* valuesInRefTextDecoration = static_cast<CSSValueList*>(refTextDecoration);
1300
1301     for (size_t i = 0; i < valuesInRefTextDecoration->length(); i++)
1302         newTextDecoration->removeAll(valuesInRefTextDecoration->item(i));
1303
1304     setTextDecorationProperty(style, newTextDecoration.get(), propertID);
1305 }
1306
1307 static bool fontWeightIsBold(CSSStyleDeclaration* style)
1308 {
1309     ASSERT(style);
1310     RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSSPropertyFontWeight);
1311
1312     if (!fontWeight)
1313         return false;
1314     if (!fontWeight->isPrimitiveValue())
1315         return false;
1316
1317     // Because b tag can only bold text, there are only two states in plain html: bold and not bold.
1318     // Collapse all other values to either one of these two states for editing purposes.
1319     switch (static_cast<CSSPrimitiveValue*>(fontWeight.get())->getIdent()) {
1320         case CSSValue100:
1321         case CSSValue200:
1322         case CSSValue300:
1323         case CSSValue400:
1324         case CSSValue500:
1325         case CSSValueNormal:
1326             return false;
1327         case CSSValueBold:
1328         case CSSValue600:
1329         case CSSValue700:
1330         case CSSValue800:
1331         case CSSValue900:
1332             return true;
1333     }
1334
1335     ASSERT_NOT_REACHED(); // For CSSValueBolder and CSSValueLighter
1336     return false; // Make compiler happy
1337 }
1338
1339 static int getTextAlignment(CSSStyleDeclaration* style)
1340 {
1341     int textAlign = getIdentifierValue(style, CSSPropertyTextAlign);
1342     switch (textAlign) {
1343     case CSSValueCenter:
1344     case CSSValueWebkitCenter:
1345         return CSSValueCenter;
1346     case CSSValueJustify:
1347         return CSSValueJustify;
1348     case CSSValueLeft:
1349     case CSSValueWebkitLeft:
1350         return CSSValueLeft;
1351     case CSSValueRight:
1352     case CSSValueWebkitRight:
1353         return CSSValueRight;
1354     }
1355     return CSSValueInvalid;
1356 }
1357
1358 RefPtr<CSSMutableStyleDeclaration> getPropertiesNotIn(CSSStyleDeclaration* styleWithRedundantProperties, CSSStyleDeclaration* baseStyle)
1359 {
1360     ASSERT(styleWithRedundantProperties);
1361     ASSERT(baseStyle);
1362     RefPtr<CSSMutableStyleDeclaration> result = styleWithRedundantProperties->copy();
1363
1364     baseStyle->diff(result.get());
1365
1366     RefPtr<CSSValue> baseTextDecorationsInEffect = baseStyle->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
1367     diffTextDecorations(result.get(), CSSPropertyTextDecoration, baseTextDecorationsInEffect.get());
1368     diffTextDecorations(result.get(), CSSPropertyWebkitTextDecorationsInEffect, baseTextDecorationsInEffect.get());
1369
1370     if (baseStyle->getPropertyCSSValue(CSSPropertyFontSize) && fontWeightIsBold(result.get()) == fontWeightIsBold(baseStyle))
1371         result->removeProperty(CSSPropertyFontWeight);
1372
1373     if (baseStyle->getPropertyCSSValue(CSSPropertyColor) && getRGBAFontColor(result.get()) == getRGBAFontColor(baseStyle))
1374         result->removeProperty(CSSPropertyColor);
1375
1376     if (baseStyle->getPropertyCSSValue(CSSPropertyTextAlign) && getTextAlignment(result.get()) == getTextAlignment(baseStyle))
1377         result->removeProperty(CSSPropertyTextAlign);
1378
1379     return result;
1380 }
1381
1382 int getIdentifierValue(CSSStyleDeclaration* style, int propertyID)
1383 {
1384     if (!style)
1385         return 0;
1386
1387     RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID);
1388     if (!value || !value->isPrimitiveValue())
1389         return 0;
1390
1391     return static_cast<CSSPrimitiveValue*>(value.get())->getIdent();
1392 }
1393
1394 static bool isCSSValueLength(CSSPrimitiveValue* value)
1395 {
1396     return value->primitiveType() >= CSSPrimitiveValue::CSS_PX && value->primitiveType() <= CSSPrimitiveValue::CSS_PC;
1397 }
1398
1399 int legacyFontSizeFromCSSValue(Document* document, CSSPrimitiveValue* value, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode mode)
1400 {
1401     if (isCSSValueLength(value)) {
1402         int pixelFontSize = value->getIntValue(CSSPrimitiveValue::CSS_PX);
1403         int legacyFontSize = CSSStyleSelector::legacyFontSize(document, pixelFontSize, shouldUseFixedFontDefaultSize);
1404         // Use legacy font size only if pixel value matches exactly to that of legacy font size.
1405         int cssPrimitiveEquivalent = legacyFontSize - 1 + CSSValueXSmall;
1406         if (mode == AlwaysUseLegacyFontSize || CSSStyleSelector::fontSizeForKeyword(document, cssPrimitiveEquivalent, shouldUseFixedFontDefaultSize) == pixelFontSize)
1407             return legacyFontSize;
1408
1409         return 0;
1410     }
1411
1412     if (CSSValueXSmall <= value->getIdent() && value->getIdent() <= CSSValueWebkitXxxLarge)
1413         return value->getIdent() - CSSValueXSmall + 1;
1414
1415     return 0;
1416 }
1417
1418 bool hasTransparentBackgroundColor(CSSStyleDeclaration* style)
1419 {
1420     RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(CSSPropertyBackgroundColor);
1421     if (!cssValue)
1422         return true;
1423     
1424     if (!cssValue->isPrimitiveValue())
1425         return false;
1426     CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(cssValue.get());
1427     
1428     if (value->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR)
1429         return !alphaChannel(value->getRGBA32Value());
1430     
1431     return value->getIdent() == CSSValueTransparent;
1432 }
1433
1434 PassRefPtr<CSSValue> backgroundColorInEffect(Node* node)
1435 {
1436     for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) {
1437         RefPtr<CSSComputedStyleDeclaration> ancestorStyle = computedStyle(ancestor);
1438         if (!hasTransparentBackgroundColor(ancestorStyle.get()))
1439             return ancestorStyle->getPropertyCSSValue(CSSPropertyBackgroundColor);
1440     }
1441     return 0;
1442 }
1443
1444 }