1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef EditingStyle_h
32#define EditingStyle_h
33
34#include "CSSPropertyNames.h"
35#include "PlatformString.h"
36#include "WritingDirection.h"
37#include <wtf/Forward.h>
38#include <wtf/RefCounted.h>
39#include <wtf/RefPtr.h>
40#include <wtf/Vector.h>
41
42namespace WebCore {
43
44class CSSStyleDeclaration;
45class CSSComputedStyleDeclaration;
46class CSSMutableStyleDeclaration;
47class CSSPrimitiveValue;
48class Document;
49class HTMLElement;
50class Node;
51class Position;
52class QualifiedName;
53class RenderStyle;
54class StyledElement;
55
56enum TriState { FalseTriState, TrueTriState, MixedTriState };
57
58class EditingStyle : public RefCounted<EditingStyle> {
59public:
60
61    enum PropertiesToInclude { AllProperties, OnlyInheritableProperties };
62    enum ShouldPreserveWritingDirection { PreserveWritingDirection, DoNotPreserveWritingDirection };
63    enum ShouldExtractMatchingStyle { ExtractMatchingStyle, DoNotExtractMatchingStyle };
64    static float NoFontDelta;
65
66    static PassRefPtr<EditingStyle> create()
67    {
68        return adoptRef(new EditingStyle());
69    }
70
71    static PassRefPtr<EditingStyle> create(Node* node, PropertiesToInclude propertiesToInclude = OnlyInheritableProperties)
72    {
73        return adoptRef(new EditingStyle(node, propertiesToInclude));
74    }
75
76    static PassRefPtr<EditingStyle> create(const Position& position)
77    {
78        return adoptRef(new EditingStyle(position));
79    }
80
81    static PassRefPtr<EditingStyle> create(const CSSStyleDeclaration* style)
82    {
83        return adoptRef(new EditingStyle(style));
84    }
85
86    static PassRefPtr<EditingStyle> create(int propertyID, const String& value)
87    {
88        return adoptRef(new EditingStyle(propertyID, value));
89    }
90
91    ~EditingStyle();
92
93    CSSMutableStyleDeclaration* style() { return m_mutableStyle.get(); }
94    bool textDirection(WritingDirection&) const;
95    bool isEmpty() const;
96    void setStyle(PassRefPtr<CSSMutableStyleDeclaration>);
97    void overrideWithStyle(const CSSMutableStyleDeclaration*);
98    void clear();
99    PassRefPtr<EditingStyle> copy() const;
100    PassRefPtr<EditingStyle> extractAndRemoveBlockProperties();
101    PassRefPtr<EditingStyle> extractAndRemoveTextDirection();
102    void removeBlockProperties();
103    void removeStyleAddedByNode(Node*);
104    void removeStyleConflictingWithStyleOfNode(Node*);
105    void removeNonEditingProperties();
106    void collapseTextDecorationProperties();
107    enum ShouldIgnoreTextOnlyProperties { IgnoreTextOnlyProperties, DoNotIgnoreTextOnlyProperties };
108    TriState triStateOfStyle(CSSStyleDeclaration*, ShouldIgnoreTextOnlyProperties = DoNotIgnoreTextOnlyProperties) const;
109    bool conflictsWithInlineStyleOfElement(StyledElement* element) const { return conflictsWithInlineStyleOfElement(element, 0, 0); }
110    bool conflictsWithInlineStyleOfElement(StyledElement* element, EditingStyle* extractedStyle, Vector<CSSPropertyID>& conflictingProperties) const
111    {
112        return conflictsWithInlineStyleOfElement(element, extractedStyle, &conflictingProperties);
113    }
114    bool conflictsWithImplicitStyleOfElement(HTMLElement*, EditingStyle* extractedStyle = 0, ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const;
115    bool conflictsWithImplicitStyleOfAttributes(HTMLElement*) const;
116    bool extractConflictingImplicitStyleOfAttributes(HTMLElement*, ShouldPreserveWritingDirection, EditingStyle* extractedStyle,
117            Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle) const;
118    bool styleIsPresentInComputedStyleOfNode(Node*) const;
119    void prepareToApplyAt(const Position&, ShouldPreserveWritingDirection = DoNotPreserveWritingDirection);
120    void mergeTypingStyle(Document*);
121    void mergeInlineStyleOfElement(StyledElement*);
122
123    float fontSizeDelta() const { return m_fontSizeDelta; }
124    bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; }
125    bool shouldUseFixedDefaultFontSize() const { return m_shouldUseFixedDefaultFontSize; }
126
127private:
128    EditingStyle();
129    EditingStyle(Node*, PropertiesToInclude);
130    EditingStyle(const Position&);
131    EditingStyle(const CSSStyleDeclaration*);
132    EditingStyle(int propertyID, const String& value);
133    void init(Node*, PropertiesToInclude);
134    void removeTextFillAndStrokeColorsIfNeeded(RenderStyle*);
135    void setProperty(int propertyID, const String& value, bool important = false);
136    void replaceFontSizeByKeywordIfPossible(RenderStyle*, CSSComputedStyleDeclaration*);
137    void extractFontSizeDelta();
138    bool conflictsWithInlineStyleOfElement(StyledElement*, EditingStyle* extractedStyle, Vector<CSSPropertyID>* conflictingProperties) const;
139    void mergeStyle(CSSMutableStyleDeclaration*);
140
141    RefPtr<CSSMutableStyleDeclaration> m_mutableStyle;
142    bool m_shouldUseFixedDefaultFontSize;
143    float m_fontSizeDelta;
144
145    friend class HTMLElementEquivalent;
146    friend class HTMLAttributeEquivalent;
147};
148
149class StyleChange {
150public:
151    StyleChange(EditingStyle*, const Position&);
152
153    String cssStyle() const { return m_cssStyle; }
154    bool applyBold() const { return m_applyBold; }
155    bool applyItalic() const { return m_applyItalic; }
156    bool applyUnderline() const { return m_applyUnderline; }
157    bool applyLineThrough() const { return m_applyLineThrough; }
158    bool applySubscript() const { return m_applySubscript; }
159    bool applySuperscript() const { return m_applySuperscript; }
160    bool applyFontColor() const { return m_applyFontColor.length() > 0; }
161    bool applyFontFace() const { return m_applyFontFace.length() > 0; }
162    bool applyFontSize() const { return m_applyFontSize.length() > 0; }
163
164    String fontColor() { return m_applyFontColor; }
165    String fontFace() { return m_applyFontFace; }
166    String fontSize() { return m_applyFontSize; }
167
168    bool operator==(const StyleChange& other)
169    {
170        return m_cssStyle == other.m_cssStyle
171            && m_applyBold == other.m_applyBold
172            && m_applyItalic == other.m_applyItalic
173            && m_applyUnderline == other.m_applyUnderline
174            && m_applyLineThrough == other.m_applyLineThrough
175            && m_applySubscript == other.m_applySubscript
176            && m_applySuperscript == other.m_applySuperscript
177            && m_applyFontColor == other.m_applyFontColor
178            && m_applyFontFace == other.m_applyFontFace
179            && m_applyFontSize == other.m_applyFontSize;
180    }
181    bool operator!=(const StyleChange& other)
182    {
183        return !(*this == other);
184    }
185private:
186    void extractTextStyles(Document*, CSSMutableStyleDeclaration*, bool shouldUseFixedFontDefaultSize);
187
188    String m_cssStyle;
189    bool m_applyBold;
190    bool m_applyItalic;
191    bool m_applyUnderline;
192    bool m_applyLineThrough;
193    bool m_applySubscript;
194    bool m_applySuperscript;
195    String m_applyFontColor;
196    String m_applyFontFace;
197    String m_applyFontSize;
198};
199
200// FIXME: Remove these functions or make them non-global to discourage using CSSStyleDeclaration directly.
201int getIdentifierValue(CSSStyleDeclaration*, int propertyID);
202enum LegacyFontSizeMode { AlwaysUseLegacyFontSize, UseLegacyFontSizeOnlyIfPixelValuesMatch };
203int legacyFontSizeFromCSSValue(Document*, CSSPrimitiveValue*, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode);
204
205} // namespace WebCore
206
207#endif // EditingStyle_h
208