Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / PropertySetCSSStyleDeclaration.cpp
1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
4  * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "core/css/PropertySetCSSStyleDeclaration.h"
24
25 #include "HTMLNames.h"
26 #include "RuntimeEnabledFeatures.h"
27 #include "bindings/v8/ExceptionState.h"
28 #include "core/css/parser/BisonCSSParser.h"
29 #include "core/css/CSSStyleSheet.h"
30 #include "core/css/StylePropertySet.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/Element.h"
33 #include "core/dom/MutationObserverInterestGroup.h"
34 #include "core/dom/MutationRecord.h"
35 #include "core/frame/ContentSecurityPolicy.h"
36 #include "core/inspector/InspectorInstrumentation.h"
37
38 using namespace std;
39
40 namespace WebCore {
41
42 namespace {
43
44 class StyleAttributeMutationScope {
45     WTF_MAKE_NONCOPYABLE(StyleAttributeMutationScope);
46 public:
47     StyleAttributeMutationScope(AbstractPropertySetCSSStyleDeclaration* decl)
48     {
49         InspectorInstrumentation::willMutateStyle(decl);
50         ++s_scopeCount;
51
52         if (s_scopeCount != 1) {
53             ASSERT(s_currentDecl == decl);
54             return;
55         }
56
57         ASSERT(!s_currentDecl);
58         s_currentDecl = decl;
59
60         if (!s_currentDecl->parentElement())
61             return;
62
63         bool shouldReadOldValue = false;
64
65         m_mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(*s_currentDecl->parentElement(), HTMLNames::styleAttr);
66         if (m_mutationRecipients && m_mutationRecipients->isOldValueRequested())
67             shouldReadOldValue = true;
68
69         AtomicString oldValue;
70         if (shouldReadOldValue)
71             oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr);
72
73         if (m_mutationRecipients) {
74             AtomicString requestedOldValue = m_mutationRecipients->isOldValueRequested() ? oldValue : nullAtom;
75             m_mutation = MutationRecord::createAttributes(s_currentDecl->parentElement(), HTMLNames::styleAttr, requestedOldValue);
76         }
77     }
78
79     ~StyleAttributeMutationScope()
80     {
81         --s_scopeCount;
82         if (s_scopeCount)
83             return;
84
85         if (m_mutation && s_shouldDeliver)
86             m_mutationRecipients->enqueueMutationRecord(m_mutation);
87
88         s_shouldDeliver = false;
89
90         // We have to clear internal state before calling Inspector's code.
91         AbstractPropertySetCSSStyleDeclaration* localCopyStyleDecl = s_currentDecl;
92         s_currentDecl = 0;
93         InspectorInstrumentation::didMutateStyle(localCopyStyleDecl, localCopyStyleDecl->parentElement());
94
95         if (!s_shouldNotifyInspector)
96             return;
97
98         s_shouldNotifyInspector = false;
99         if (localCopyStyleDecl->parentElement())
100             InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl->parentElement());
101     }
102
103     void enqueueMutationRecord()
104     {
105         s_shouldDeliver = true;
106     }
107
108     void didInvalidateStyleAttr()
109     {
110         s_shouldNotifyInspector = true;
111     }
112
113 private:
114     static unsigned s_scopeCount;
115     static AbstractPropertySetCSSStyleDeclaration* s_currentDecl;
116     static bool s_shouldNotifyInspector;
117     static bool s_shouldDeliver;
118
119     OwnPtr<MutationObserverInterestGroup> m_mutationRecipients;
120     RefPtr<MutationRecord> m_mutation;
121 };
122
123 unsigned StyleAttributeMutationScope::s_scopeCount = 0;
124 AbstractPropertySetCSSStyleDeclaration* StyleAttributeMutationScope::s_currentDecl = 0;
125 bool StyleAttributeMutationScope::s_shouldNotifyInspector = false;
126 bool StyleAttributeMutationScope::s_shouldDeliver = false;
127
128 } // namespace
129
130 void PropertySetCSSStyleDeclaration::ref()
131 {
132     m_propertySet->ref();
133 }
134
135 void PropertySetCSSStyleDeclaration::deref()
136 {
137     m_propertySet->deref();
138 }
139
140 unsigned AbstractPropertySetCSSStyleDeclaration::length() const
141 {
142     return propertySet()->propertyCount();
143 }
144
145 String AbstractPropertySetCSSStyleDeclaration::item(unsigned i) const
146 {
147     if (i >= propertySet()->propertyCount())
148         return "";
149     return propertySet()->propertyAt(i).cssName();
150 }
151
152 String AbstractPropertySetCSSStyleDeclaration::cssText() const
153 {
154     return propertySet()->asText();
155 }
156
157 void AbstractPropertySetCSSStyleDeclaration::setCSSText(const String& text, ExceptionState& exceptionState)
158 {
159     if (parentElement()) {
160         ContentSecurityPolicy* csp = parentElement()->document().contentSecurityPolicy();
161         if (!csp->allowStyleEval()) {
162             exceptionState.throwSecurityError(csp->styleEvalDisabledErrorMessage());
163             return;
164         }
165     }
166
167     StyleAttributeMutationScope mutationScope(this);
168     willMutate();
169
170     // FIXME: Detect syntax errors and set exceptionState.
171     propertySet()->parseDeclaration(text, contextStyleSheet());
172
173     didMutate(PropertyChanged);
174
175     mutationScope.enqueueMutationRecord();
176 }
177
178 PassRefPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
179 {
180     CSSPropertyID propertyID = cssPropertyID(propertyName);
181     if (!propertyID)
182         return 0;
183     return cloneAndCacheForCSSOM(propertySet()->getPropertyCSSValue(propertyID).get());
184 }
185
186 String AbstractPropertySetCSSStyleDeclaration::getPropertyValue(const String &propertyName)
187 {
188     CSSPropertyID propertyID = cssPropertyID(propertyName);
189     if (!propertyID)
190         return String();
191     return propertySet()->getPropertyValue(propertyID);
192 }
193
194 String AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
195 {
196     CSSPropertyID propertyID = cssPropertyID(propertyName);
197     if (!propertyID)
198         return String();
199     return propertySet()->propertyIsImportant(propertyID) ? "important" : "";
200 }
201
202 String AbstractPropertySetCSSStyleDeclaration::getPropertyShorthand(const String& propertyName)
203 {
204     CSSPropertyID propertyID = cssPropertyID(propertyName);
205     if (!propertyID)
206         return String();
207     CSSPropertyID shorthandID = propertySet()->getPropertyShorthand(propertyID);
208     if (!shorthandID)
209         return String();
210     return getPropertyNameString(shorthandID);
211 }
212
213 bool AbstractPropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyName)
214 {
215     CSSPropertyID propertyID = cssPropertyID(propertyName);
216     if (!propertyID)
217         return false;
218     return propertySet()->isPropertyImplicit(propertyID);
219 }
220
221 void AbstractPropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionState& exceptionState)
222 {
223     StyleAttributeMutationScope mutationScope(this);
224     CSSPropertyID propertyID = cssPropertyID(propertyName);
225     if (!propertyID)
226         return;
227
228     bool important = priority.find("important", 0, false) != kNotFound;
229
230     willMutate();
231
232     bool changed = propertySet()->setProperty(propertyID, value, important, contextStyleSheet());
233
234     didMutate(changed ? PropertyChanged : NoChanges);
235
236     if (changed) {
237         // CSS DOM requires raising SyntaxError of parsing failed, but this is too dangerous for compatibility,
238         // see <http://bugs.webkit.org/show_bug.cgi?id=7296>.
239         mutationScope.enqueueMutationRecord();
240     }
241 }
242
243 String AbstractPropertySetCSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionState& exceptionState)
244 {
245     StyleAttributeMutationScope mutationScope(this);
246     CSSPropertyID propertyID = cssPropertyID(propertyName);
247     if (!propertyID)
248         return String();
249
250     willMutate();
251
252     String result;
253     bool changed = propertySet()->removeProperty(propertyID, &result);
254
255     didMutate(changed ? PropertyChanged : NoChanges);
256
257     if (changed)
258         mutationScope.enqueueMutationRecord();
259     return result;
260 }
261
262 PassRefPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID)
263 {
264     return propertySet()->getPropertyCSSValue(propertyID);
265 }
266
267 String AbstractPropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID)
268 {
269     return propertySet()->getPropertyValue(propertyID);
270 }
271
272 void AbstractPropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionState&)
273 {
274     StyleAttributeMutationScope mutationScope(this);
275     willMutate();
276
277     bool changed = propertySet()->setProperty(propertyID, value, important, contextStyleSheet());
278
279     didMutate(changed ? PropertyChanged : NoChanges);
280
281     if (changed)
282         mutationScope.enqueueMutationRecord();
283 }
284
285 CSSValue* AbstractPropertySetCSSStyleDeclaration::cloneAndCacheForCSSOM(CSSValue* internalValue)
286 {
287     if (!internalValue)
288         return 0;
289
290     // The map is here to maintain the object identity of the CSSValues over multiple invocations.
291     // FIXME: It is likely that the identity is not important for web compatibility and this code should be removed.
292     if (!m_cssomCSSValueClones)
293         m_cssomCSSValueClones = adoptPtr(new HashMap<CSSValue*, RefPtr<CSSValue> >);
294
295     RefPtr<CSSValue>& clonedValue = m_cssomCSSValueClones->add(internalValue, RefPtr<CSSValue>()).storedValue->value;
296     if (!clonedValue)
297         clonedValue = internalValue->cloneForCSSOM();
298     return clonedValue.get();
299 }
300
301 StyleSheetContents* AbstractPropertySetCSSStyleDeclaration::contextStyleSheet() const
302 {
303     CSSStyleSheet* cssStyleSheet = parentStyleSheet();
304     return cssStyleSheet ? cssStyleSheet->contents() : 0;
305 }
306
307 PassRefPtr<MutableStylePropertySet> AbstractPropertySetCSSStyleDeclaration::copyProperties() const
308 {
309     return propertySet()->mutableCopy();
310 }
311
312 bool AbstractPropertySetCSSStyleDeclaration::cssPropertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
313 {
314     return propertySet()->propertyMatches(propertyID, propertyValue);
315 }
316
317 StyleRuleCSSStyleDeclaration::StyleRuleCSSStyleDeclaration(MutableStylePropertySet* propertySetArg, CSSRule* parentRule)
318     : PropertySetCSSStyleDeclaration(propertySetArg)
319     , m_refCount(1)
320     , m_parentRule(parentRule)
321 {
322     m_propertySet->ref();
323 }
324
325 StyleRuleCSSStyleDeclaration::~StyleRuleCSSStyleDeclaration()
326 {
327     m_propertySet->deref();
328 }
329
330 void StyleRuleCSSStyleDeclaration::ref()
331 {
332     ++m_refCount;
333 }
334
335 void StyleRuleCSSStyleDeclaration::deref()
336 {
337     ASSERT(m_refCount);
338     if (!--m_refCount)
339         delete this;
340 }
341
342 void StyleRuleCSSStyleDeclaration::willMutate()
343 {
344     if (m_parentRule && m_parentRule->parentStyleSheet())
345         m_parentRule->parentStyleSheet()->willMutateRules();
346 }
347
348 void StyleRuleCSSStyleDeclaration::didMutate(MutationType type)
349 {
350     if (type == PropertyChanged)
351         m_cssomCSSValueClones.clear();
352
353     // Style sheet mutation needs to be signaled even if the change failed. willMutateRules/didMutateRules must pair.
354     if (m_parentRule && m_parentRule->parentStyleSheet())
355         m_parentRule->parentStyleSheet()->didMutateRules();
356 }
357
358 CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
359 {
360     return m_parentRule ? m_parentRule->parentStyleSheet() : 0;
361 }
362
363 void StyleRuleCSSStyleDeclaration::reattach(MutableStylePropertySet* propertySet)
364 {
365     ASSERT(propertySet);
366     m_propertySet->deref();
367     m_propertySet = propertySet;
368     m_propertySet->ref();
369 }
370
371 MutableStylePropertySet* InlineCSSStyleDeclaration::propertySet() const
372 {
373     return m_parentElement->ensureMutableInlineStyle();
374 }
375
376 void InlineCSSStyleDeclaration::didMutate(MutationType type)
377 {
378     if (type == NoChanges)
379         return;
380
381     m_cssomCSSValueClones.clear();
382
383     if (!m_parentElement)
384         return;
385
386     m_parentElement->clearMutableInlineStyleIfEmpty();
387     m_parentElement->setNeedsStyleRecalc(LocalStyleChange);
388     m_parentElement->invalidateStyleAttribute();
389     StyleAttributeMutationScope(this).didInvalidateStyleAttr();
390 }
391
392 CSSStyleSheet* InlineCSSStyleDeclaration::parentStyleSheet() const
393 {
394     return m_parentElement ? m_parentElement->document().elementSheet() : 0;
395 }
396
397 void InlineCSSStyleDeclaration::ref()
398 {
399     m_parentElement->ref();
400 }
401
402 void InlineCSSStyleDeclaration::deref()
403 {
404     m_parentElement->deref();
405 }
406
407 } // namespace WebCore