2010-11-08 Ryosuke Niwa <rniwa@webkit.org>
[WebKit-https.git] / WebCore / editing / EditingStyle.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009 Apple Computer, Inc.
3  * Copyright (C) 2010 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 "Frame.h"
34 #include "RenderStyle.h"
35 #include "SelectionController.h"
36
37 namespace WebCore {
38
39 // Editing style properties must be preserved during editing operation.
40 // e.g. when a user inserts a new paragraph, all properties listed here must be copied to the new paragraph.
41 // FIXME: The current editingStyleProperties contains all inheritableProperties but we may not need to preserve all inheritable properties
42 static const int editingStyleProperties[] = {
43     // CSS inheritable properties
44     CSSPropertyBorderCollapse,
45     CSSPropertyColor,
46     CSSPropertyFontFamily,
47     CSSPropertyFontSize,
48     CSSPropertyFontStyle,
49     CSSPropertyFontVariant,
50     CSSPropertyFontWeight,
51     CSSPropertyLetterSpacing,
52     CSSPropertyLineHeight,
53     CSSPropertyOrphans,
54     CSSPropertyTextAlign,
55     CSSPropertyTextIndent,
56     CSSPropertyTextTransform,
57     CSSPropertyWhiteSpace,
58     CSSPropertyWidows,
59     CSSPropertyWordSpacing,
60     CSSPropertyWebkitBorderHorizontalSpacing,
61     CSSPropertyWebkitBorderVerticalSpacing,
62     CSSPropertyWebkitTextDecorationsInEffect,
63     CSSPropertyWebkitTextFillColor,
64     CSSPropertyWebkitTextSizeAdjust,
65     CSSPropertyWebkitTextStrokeColor,
66     CSSPropertyWebkitTextStrokeWidth,
67 };
68 size_t numEditingStyleProperties = sizeof(editingStyleProperties) / sizeof(editingStyleProperties[0]);
69
70 static PassRefPtr<CSSMutableStyleDeclaration> copyEditingProperties(CSSStyleDeclaration* style)
71 {
72     return style->copyPropertiesInSet(editingStyleProperties, numEditingStyleProperties);
73 }
74
75 static PassRefPtr<CSSMutableStyleDeclaration> editingStyleFromComputedStyle(PassRefPtr<CSSComputedStyleDeclaration> style)
76 {
77     if (!style)
78         return CSSMutableStyleDeclaration::create();
79     return copyEditingProperties(style.get());
80 }
81
82 EditingStyle::EditingStyle()
83     : m_shouldUseFixedDefaultFontSize(false)
84 {
85 }
86
87 EditingStyle::EditingStyle(Node* node)
88     : m_shouldUseFixedDefaultFontSize(false)
89 {
90     init(node);
91 }
92
93 EditingStyle::EditingStyle(const Position& position)
94     : m_shouldUseFixedDefaultFontSize(false)
95 {
96     init(position.node());
97 }
98
99 EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
100     : m_mutableStyle(style->copy())
101     , m_shouldUseFixedDefaultFontSize(false)
102 {
103 }
104
105 void EditingStyle::init(Node* node)
106 {
107     RefPtr<CSSComputedStyleDeclaration> computedStyleAtPosition = computedStyle(node);
108     m_mutableStyle = editingStyleFromComputedStyle(computedStyleAtPosition);
109
110     if (node && node->computedStyle()) {
111         RenderStyle* renderStyle = node->computedStyle();
112         removeTextFillAndStrokeColorsIfNeeded(renderStyle);
113         replaceFontSizeByKeywordIfPossible(renderStyle, computedStyleAtPosition.get());
114     }
115
116     m_shouldUseFixedDefaultFontSize = computedStyleAtPosition->useFixedFontDefaultSize();
117 }
118
119 void EditingStyle::removeTextFillAndStrokeColorsIfNeeded(RenderStyle* renderStyle)
120 {
121     // If a node's text fill color is invalid, then its children use 
122     // their font-color as their text fill color (they don't
123     // inherit it).  Likewise for stroke color.
124     ExceptionCode ec = 0;
125     if (!renderStyle->textFillColor().isValid())
126         m_mutableStyle->removeProperty(CSSPropertyWebkitTextFillColor, ec);
127     if (!renderStyle->textStrokeColor().isValid())
128         m_mutableStyle->removeProperty(CSSPropertyWebkitTextStrokeColor, ec);
129     ASSERT(!ec);
130 }
131
132 void EditingStyle::replaceFontSizeByKeywordIfPossible(RenderStyle* renderStyle, CSSComputedStyleDeclaration* computedStyle)
133 {
134     ASSERT(renderStyle);
135     if (renderStyle->fontDescription().keywordSize())
136         m_mutableStyle->setProperty(CSSPropertyFontSize, computedStyle->getFontSizeCSSValuePreferringKeyword()->cssText());
137 }
138
139 bool EditingStyle::isEmpty() const
140 {
141     return !m_mutableStyle || m_mutableStyle->isEmpty();
142 }
143
144 void EditingStyle::setStyle(PassRefPtr<CSSMutableStyleDeclaration> style)
145 {
146     m_mutableStyle = style;
147     // FIXME: We should be able to figure out whether or not font is fixed width for mutable style.
148     // We need to check font-family is monospace as in FontDescription but we don't want to duplicate code here.
149     m_shouldUseFixedDefaultFontSize = false;
150 }
151
152 void EditingStyle::clear()
153 {
154     m_mutableStyle.clear();
155     m_shouldUseFixedDefaultFontSize = false;
156 }
157
158 void EditingStyle::removeBlockProperties()
159 {
160     if (!m_mutableStyle)
161         return;
162
163     m_mutableStyle->removeBlockProperties();
164 }
165
166 void EditingStyle::removeStyleAddedByNode(Node* node)
167 {
168     if (!node || !node->parentNode())
169         return;
170     RefPtr<CSSMutableStyleDeclaration> parentStyle = editingStyleFromComputedStyle(computedStyle(node->parentNode()));
171     RefPtr<CSSMutableStyleDeclaration> nodeStyle = editingStyleFromComputedStyle(computedStyle(node));
172     parentStyle->diff(nodeStyle.get());
173     nodeStyle->diff(m_mutableStyle.get());
174 }
175
176 void EditingStyle::removeStyleConflictingWithStyleOfNode(Node* node)
177 {
178     if (!node || !node->parentNode())
179         return;
180     RefPtr<CSSMutableStyleDeclaration> parentStyle = editingStyleFromComputedStyle(computedStyle(node->parentNode()));
181     RefPtr<CSSMutableStyleDeclaration> nodeStyle = editingStyleFromComputedStyle(computedStyle(node));
182     parentStyle->diff(nodeStyle.get());
183
184     CSSMutableStyleDeclaration::const_iterator end = nodeStyle->end();
185     for (CSSMutableStyleDeclaration::const_iterator it = nodeStyle->begin(); it != end; ++it)
186         m_mutableStyle->removeProperty(it->id());
187 }
188
189 void EditingStyle::removeNonEditingProperties()
190 {
191     if (m_mutableStyle)
192         m_mutableStyle = copyEditingProperties(m_mutableStyle.get());
193 }
194
195 void EditingStyle::prepareToApplyAt(const Position& position)
196 {
197     // ReplaceSelectionCommand::handleStyleSpans() requires that this function only removes the editing style.
198     // If this function was modified in the future to delete all redundant properties, then add a boolean value to indicate
199     // which one of editingStyleAtPosition or computedStyle is called.
200     RefPtr<EditingStyle> style = EditingStyle::create(position);
201     style->m_mutableStyle->diff(m_mutableStyle.get());
202
203     // if alpha value is zero, we don't add the background color.
204     RefPtr<CSSValue> backgroundColor = m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor);
205     if (backgroundColor && backgroundColor->isPrimitiveValue()
206         && !alphaChannel(static_cast<CSSPrimitiveValue*>(backgroundColor.get())->getRGBA32Value())) {
207         ExceptionCode ec;
208         m_mutableStyle->removeProperty(CSSPropertyBackgroundColor, ec);
209     }
210 }
211
212 PassRefPtr<EditingStyle> editingStyleIncludingTypingStyle(const Position& position)
213 {
214     RefPtr<EditingStyle> editingStyle = EditingStyle::create(position);
215     RefPtr<CSSMutableStyleDeclaration> typingStyle = position.node()->document()->frame()->selection()->typingStyle();
216     if (typingStyle)
217         editingStyle->style()->merge(copyEditingProperties(typingStyle.get()).get());
218     return editingStyle;
219 }
220     
221 }