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