2 * Copyright (C) 2007, 2008, 2009 Apple Computer, Inc.
3 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "EditingStyle.h"
30 #include "ApplyStyleCommand.h"
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSMutableStyleDeclaration.h"
34 #include "RenderStyle.h"
35 #include "SelectionController.h"
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,
46 CSSPropertyFontFamily,
49 CSSPropertyFontVariant,
50 CSSPropertyFontWeight,
51 CSSPropertyLetterSpacing,
52 CSSPropertyLineHeight,
55 CSSPropertyTextIndent,
56 CSSPropertyTextTransform,
57 CSSPropertyWhiteSpace,
59 CSSPropertyWordSpacing,
60 CSSPropertyWebkitBorderHorizontalSpacing,
61 CSSPropertyWebkitBorderVerticalSpacing,
62 CSSPropertyWebkitTextDecorationsInEffect,
63 CSSPropertyWebkitTextFillColor,
64 CSSPropertyWebkitTextSizeAdjust,
65 CSSPropertyWebkitTextStrokeColor,
66 CSSPropertyWebkitTextStrokeWidth,
68 size_t numEditingStyleProperties = sizeof(editingStyleProperties) / sizeof(editingStyleProperties[0]);
70 static PassRefPtr<CSSMutableStyleDeclaration> copyEditingProperties(CSSStyleDeclaration* style)
72 return style->copyPropertiesInSet(editingStyleProperties, numEditingStyleProperties);
75 static PassRefPtr<CSSMutableStyleDeclaration> editingStyleFromComputedStyle(PassRefPtr<CSSComputedStyleDeclaration> style)
78 return CSSMutableStyleDeclaration::create();
79 return copyEditingProperties(style.get());
82 EditingStyle::EditingStyle()
83 : m_shouldUseFixedDefaultFontSize(false)
87 EditingStyle::EditingStyle(Node* node)
88 : m_shouldUseFixedDefaultFontSize(false)
93 EditingStyle::EditingStyle(const Position& position)
94 : m_shouldUseFixedDefaultFontSize(false)
96 init(position.node());
99 EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
100 : m_mutableStyle(style->copy())
101 , m_shouldUseFixedDefaultFontSize(false)
105 void EditingStyle::init(Node* node)
107 RefPtr<CSSComputedStyleDeclaration> computedStyleAtPosition = computedStyle(node);
108 m_mutableStyle = editingStyleFromComputedStyle(computedStyleAtPosition);
110 if (node && node->computedStyle()) {
111 RenderStyle* renderStyle = node->computedStyle();
112 removeTextFillAndStrokeColorsIfNeeded(renderStyle);
113 replaceFontSizeByKeywordIfPossible(renderStyle, computedStyleAtPosition.get());
116 m_shouldUseFixedDefaultFontSize = computedStyleAtPosition->useFixedFontDefaultSize();
119 void EditingStyle::removeTextFillAndStrokeColorsIfNeeded(RenderStyle* renderStyle)
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);
132 void EditingStyle::replaceFontSizeByKeywordIfPossible(RenderStyle* renderStyle, CSSComputedStyleDeclaration* computedStyle)
135 if (renderStyle->fontDescription().keywordSize())
136 m_mutableStyle->setProperty(CSSPropertyFontSize, computedStyle->getFontSizeCSSValuePreferringKeyword()->cssText());
139 bool EditingStyle::isEmpty() const
141 return !m_mutableStyle || m_mutableStyle->isEmpty();
144 void EditingStyle::setStyle(PassRefPtr<CSSMutableStyleDeclaration> style)
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;
152 void EditingStyle::clear()
154 m_mutableStyle.clear();
155 m_shouldUseFixedDefaultFontSize = false;
158 void EditingStyle::removeBlockProperties()
163 m_mutableStyle->removeBlockProperties();
166 void EditingStyle::removeStyleAddedByNode(Node* node)
168 if (!node || !node->parentNode())
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());
176 void EditingStyle::removeStyleConflictingWithStyleOfNode(Node* node)
178 if (!node || !node->parentNode())
180 RefPtr<CSSMutableStyleDeclaration> parentStyle = editingStyleFromComputedStyle(computedStyle(node->parentNode()));
181 RefPtr<CSSMutableStyleDeclaration> nodeStyle = editingStyleFromComputedStyle(computedStyle(node));
182 parentStyle->diff(nodeStyle.get());
184 CSSMutableStyleDeclaration::const_iterator end = nodeStyle->end();
185 for (CSSMutableStyleDeclaration::const_iterator it = nodeStyle->begin(); it != end; ++it)
186 m_mutableStyle->removeProperty(it->id());
189 void EditingStyle::removeNonEditingProperties()
192 m_mutableStyle = copyEditingProperties(m_mutableStyle.get());
195 void EditingStyle::prepareToApplyAt(const Position& position)
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());
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())) {
208 m_mutableStyle->removeProperty(CSSPropertyBackgroundColor, ec);
212 PassRefPtr<EditingStyle> editingStyleIncludingTypingStyle(const Position& position)
214 RefPtr<EditingStyle> editingStyle = EditingStyle::create(position);
215 RefPtr<CSSMutableStyleDeclaration> typingStyle = position.node()->document()->frame()->selection()->typingStyle();
217 editingStyle->style()->merge(copyEditingProperties(typingStyle.get()).get());