1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "config.h"
22 #include "CSSStyleDeclaration.h"
23 
24 #include "CSSMutableStyleDeclaration.h"
25 #include "CSSMutableValue.h"
26 #include "CSSParser.h"
27 #include "CSSProperty.h"
28 #include "CSSPropertyNames.h"
29 #include "CSSRule.h"
30 #include "Node.h"
31 #include "SVGElement.h"
32 #include <wtf/ASCIICType.h>
33 
34 using namespace WTF;
35 
36 namespace WebCore {
37 
CSSStyleDeclaration(CSSRule * parent)38 CSSStyleDeclaration::CSSStyleDeclaration(CSSRule* parent)
39     : StyleBase(parent)
40 {
41 }
42 
getPropertyCSSValue(const String & propertyName)43 PassRefPtr<CSSValue> CSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
44 {
45     int propID = cssPropertyID(propertyName);
46     if (!propID)
47         return 0;
48 
49     // Short-cut, not involving any change to the refcount.
50     if (!isMutableStyleDeclaration())
51         return getPropertyCSSValue(propID);
52 
53     // Slow path.
54     RefPtr<CSSValue> value = getPropertyCSSValue(propID);
55     if (!value || !value->isMutableValue())
56         return value.release();
57 
58     Node* node = static_cast<CSSMutableStyleDeclaration*>(this)->node();
59     if (!node || !node->isStyledElement())
60         return value.release();
61 
62     Node* associatedNode = static_cast<CSSMutableValue*>(value.get())->node();
63     if (associatedNode) {
64         ASSERT(associatedNode == node);
65         return value.release();
66     }
67 
68     static_cast<CSSMutableValue*>(value.get())->setNode(node);
69     return value.release();
70 }
71 
getPropertyValue(const String & propertyName)72 String CSSStyleDeclaration::getPropertyValue(const String &propertyName)
73 {
74     int propID = cssPropertyID(propertyName);
75     if (!propID)
76         return String();
77     return getPropertyValue(propID);
78 }
79 
getPropertyPriority(const String & propertyName)80 String CSSStyleDeclaration::getPropertyPriority(const String& propertyName)
81 {
82     int propID = cssPropertyID(propertyName);
83     if (!propID)
84         return String();
85     return getPropertyPriority(propID) ? "important" : "";
86 }
87 
getPropertyShorthand(const String & propertyName)88 String CSSStyleDeclaration::getPropertyShorthand(const String& propertyName)
89 {
90     int propID = cssPropertyID(propertyName);
91     if (!propID)
92         return String();
93     int shorthandID = getPropertyShorthand(propID);
94     if (!shorthandID)
95         return String();
96     return getPropertyName(static_cast<CSSPropertyID>(shorthandID));
97 }
98 
isPropertyImplicit(const String & propertyName)99 bool CSSStyleDeclaration::isPropertyImplicit(const String& propertyName)
100 {
101     int propID = cssPropertyID(propertyName);
102     if (!propID)
103         return false;
104     return isPropertyImplicit(propID);
105 }
106 
setProperty(const String & propertyName,const String & value,ExceptionCode & ec)107 void CSSStyleDeclaration::setProperty(const String& propertyName, const String& value, ExceptionCode& ec)
108 {
109     size_t important = value.find("!important", 0, false);
110     int propertyID = cssPropertyID(propertyName);
111     if (!propertyID)
112         return;
113     if (important == notFound)
114         setProperty(propertyID, value, false, ec);
115     else
116         setProperty(propertyID, value.left(important - 1), true, ec);
117 }
118 
setProperty(const String & propertyName,const String & value,const String & priority,ExceptionCode & ec)119 void CSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode& ec)
120 {
121     int propID = cssPropertyID(propertyName);
122     if (!propID) {
123         // FIXME: Should we raise an exception here?
124         return;
125     }
126     bool important = priority.find("important", 0, false) != notFound;
127     setProperty(propID, value, important, ec);
128 }
129 
removeProperty(const String & propertyName,ExceptionCode & ec)130 String CSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionCode& ec)
131 {
132     int propID = cssPropertyID(propertyName);
133     if (!propID)
134         return String();
135     return removeProperty(propID, ec);
136 }
137 
isPropertyName(const String & propertyName)138 bool CSSStyleDeclaration::isPropertyName(const String& propertyName)
139 {
140     return cssPropertyID(propertyName);
141 }
142 
parentRule() const143 CSSRule* CSSStyleDeclaration::parentRule() const
144 {
145     return (parent() && parent()->isRule()) ? static_cast<CSSRule*>(parent()) : 0;
146 }
147 
cssPropertyMatches(const CSSProperty * property) const148 bool CSSStyleDeclaration::cssPropertyMatches(const CSSProperty* property) const
149 {
150     RefPtr<CSSValue> value = getPropertyCSSValue(property->id());
151     return value && value->cssText() == property->value()->cssText();
152 }
153 
diff(CSSMutableStyleDeclaration * style) const154 void CSSStyleDeclaration::diff(CSSMutableStyleDeclaration* style) const
155 {
156     if (!style)
157         return;
158 
159     Vector<int> propertiesToRemove;
160     {
161         CSSMutableStyleDeclaration::const_iterator end = style->end();
162         for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
163             const CSSProperty& property = *it;
164             if (cssPropertyMatches(&property))
165                 propertiesToRemove.append(property.id());
166         }
167     }
168 
169     // FIXME: This should use mass removal.
170     for (unsigned i = 0; i < propertiesToRemove.size(); i++)
171         style->removeProperty(propertiesToRemove[i]);
172 }
173 
copyPropertiesInSet(const int * set,unsigned length) const174 PassRefPtr<CSSMutableStyleDeclaration> CSSStyleDeclaration::copyPropertiesInSet(const int* set, unsigned length) const
175 {
176     Vector<CSSProperty> list;
177     list.reserveInitialCapacity(length);
178     for (unsigned i = 0; i < length; i++) {
179         RefPtr<CSSValue> value = getPropertyCSSValue(set[i]);
180         if (value)
181             list.append(CSSProperty(set[i], value.release(), false));
182     }
183     return CSSMutableStyleDeclaration::create(list);
184 }
185 
186 } // namespace WebCore
187