Upstream version 10.39.225.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 "bindings/core/v8/ExceptionState.h"
26 #include "core/HTMLNames.h"
27 #include "core/css/CSSStyleSheet.h"
28 #include "core/css/StylePropertySet.h"
29 #include "core/css/parser/CSSParser.h"
30 #include "core/dom/Element.h"
31 #include "core/dom/MutationObserverInterestGroup.h"
32 #include "core/dom/MutationRecord.h"
33 #include "core/inspector/InspectorInstrumentation.h"
34 #include "platform/RuntimeEnabledFeatures.h"
35
36 namespace blink {
37
38 namespace {
39
40 class StyleAttributeMutationScope {
41     WTF_MAKE_NONCOPYABLE(StyleAttributeMutationScope);
42     STACK_ALLOCATED();
43 public:
44     StyleAttributeMutationScope(AbstractPropertySetCSSStyleDeclaration* decl)
45     {
46         InspectorInstrumentation::willMutateStyle(decl);
47         ++s_scopeCount;
48
49         if (s_scopeCount != 1) {
50             ASSERT(s_currentDecl == decl);
51             return;
52         }
53
54         ASSERT(!s_currentDecl);
55         s_currentDecl = decl;
56
57         if (!s_currentDecl->parentElement())
58             return;
59
60         bool shouldReadOldValue = false;
61
62         m_mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(*s_currentDecl->parentElement(), HTMLNames::styleAttr);
63         if (m_mutationRecipients && m_mutationRecipients->isOldValueRequested())
64             shouldReadOldValue = true;
65
66         AtomicString oldValue;
67         if (shouldReadOldValue)
68             oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr);
69
70         if (m_mutationRecipients) {
71             AtomicString requestedOldValue = m_mutationRecipients->isOldValueRequested() ? oldValue : nullAtom;
72             m_mutation = MutationRecord::createAttributes(s_currentDecl->parentElement(), HTMLNames::styleAttr, requestedOldValue);
73         }
74     }
75
76     ~StyleAttributeMutationScope()
77     {
78         --s_scopeCount;
79         if (s_scopeCount)
80             return;
81
82         if (m_mutation && s_shouldDeliver)
83             m_mutationRecipients->enqueueMutationRecord(m_mutation);
84
85         s_shouldDeliver = false;
86
87         // We have to clear internal state before calling Inspector's code.
88         AbstractPropertySetCSSStyleDeclaration* localCopyStyleDecl = s_currentDecl;
89         s_currentDecl = 0;
90         InspectorInstrumentation::didMutateStyle(localCopyStyleDecl, localCopyStyleDecl->parentElement());
91
92         if (!s_shouldNotifyInspector)
93             return;
94
95         s_shouldNotifyInspector = false;
96         if (localCopyStyleDecl->parentElement())
97             InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl->parentElement());
98     }
99
100     void enqueueMutationRecord()
101     {
102         s_shouldDeliver = true;
103     }
104
105     void didInvalidateStyleAttr()
106     {
107         s_shouldNotifyInspector = true;
108     }
109
110 private:
111     static unsigned s_scopeCount;
112     static AbstractPropertySetCSSStyleDeclaration* s_currentDecl;
113     static bool s_shouldNotifyInspector;
114     static bool s_shouldDeliver;
115
116     OwnPtrWillBeMember<MutationObserverInterestGroup> m_mutationRecipients;
117     RefPtrWillBeMember<MutationRecord> m_mutation;
118 };
119
120 unsigned StyleAttributeMutationScope::s_scopeCount = 0;
121 AbstractPropertySetCSSStyleDeclaration* StyleAttributeMutationScope::s_currentDecl = 0;
122 bool StyleAttributeMutationScope::s_shouldNotifyInspector = false;
123 bool StyleAttributeMutationScope::s_shouldDeliver = false;
124
125 } // namespace
126
127 #if !ENABLE(OILPAN)
128 void PropertySetCSSStyleDeclaration::ref()
129 {
130     m_propertySet->ref();
131 }
132
133 void PropertySetCSSStyleDeclaration::deref()
134 {
135     m_propertySet->deref();
136 }
137 #endif
138
139 void PropertySetCSSStyleDeclaration::trace(Visitor* visitor)
140 {
141     visitor->trace(m_propertySet);
142     AbstractPropertySetCSSStyleDeclaration::trace(visitor);
143 }
144
145 unsigned AbstractPropertySetCSSStyleDeclaration::length() const
146 {
147     return propertySet().propertyCount();
148 }
149
150 String AbstractPropertySetCSSStyleDeclaration::item(unsigned i) const
151 {
152     if (i >= propertySet().propertyCount())
153         return "";
154     return propertySet().propertyAt(i).cssName();
155 }
156
157 String AbstractPropertySetCSSStyleDeclaration::cssText() const
158 {
159     return propertySet().asText();
160 }
161
162 void AbstractPropertySetCSSStyleDeclaration::setCSSText(const String& text, ExceptionState& exceptionState)
163 {
164     StyleAttributeMutationScope mutationScope(this);
165     willMutate();
166
167     // FIXME: Detect syntax errors and set exceptionState.
168     propertySet().parseDeclaration(text, contextStyleSheet());
169
170     didMutate(PropertyChanged);
171
172     mutationScope.enqueueMutationRecord();
173 }
174
175 PassRefPtrWillBeRawPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
176 {
177     CSSPropertyID propertyID = cssPropertyID(propertyName);
178     if (!propertyID)
179         return nullptr;
180     return cloneAndCacheForCSSOM(propertySet().getPropertyCSSValue(propertyID).get());
181 }
182
183 String AbstractPropertySetCSSStyleDeclaration::getPropertyValue(const String &propertyName)
184 {
185     CSSPropertyID propertyID = cssPropertyID(propertyName);
186     if (!propertyID)
187         return String();
188     return propertySet().getPropertyValue(propertyID);
189 }
190
191 String AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
192 {
193     CSSPropertyID propertyID = cssPropertyID(propertyName);
194     if (!propertyID)
195         return String();
196     return propertySet().propertyIsImportant(propertyID) ? "important" : "";
197 }
198
199 String AbstractPropertySetCSSStyleDeclaration::getPropertyShorthand(const String& propertyName)
200 {
201     CSSPropertyID propertyID = cssPropertyID(propertyName);
202     if (!propertyID)
203         return String();
204     CSSPropertyID shorthandID = propertySet().getPropertyShorthand(propertyID);
205     if (!shorthandID)
206         return String();
207     return getPropertyNameString(shorthandID);
208 }
209
210 bool AbstractPropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyName)
211 {
212     CSSPropertyID propertyID = cssPropertyID(propertyName);
213     if (!propertyID)
214         return false;
215     return propertySet().isPropertyImplicit(propertyID);
216 }
217
218 void AbstractPropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionState& exceptionState)
219 {
220     CSSPropertyID propertyID = cssPropertyID(propertyName);
221     if (!propertyID)
222         return;
223
224     bool important = equalIgnoringCase(priority, "important");
225     if (!important && !priority.isEmpty())
226         return;
227
228     setPropertyInternal(propertyID, value, important, exceptionState);
229 }
230
231 String AbstractPropertySetCSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionState& exceptionState)
232 {
233     StyleAttributeMutationScope mutationScope(this);
234     CSSPropertyID propertyID = cssPropertyID(propertyName);
235     if (!propertyID)
236         return String();
237
238     willMutate();
239
240     String result;
241     bool changed = propertySet().removeProperty(propertyID, &result);
242
243     didMutate(changed ? PropertyChanged : NoChanges);
244
245     if (changed)
246         mutationScope.enqueueMutationRecord();
247     return result;
248 }
249
250 PassRefPtrWillBeRawPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID)
251 {
252     return propertySet().getPropertyCSSValue(propertyID);
253 }
254
255 String AbstractPropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID)
256 {
257     return propertySet().getPropertyValue(propertyID);
258 }
259
260 void AbstractPropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionState&)
261 {
262     StyleAttributeMutationScope mutationScope(this);
263     willMutate();
264
265     bool changed = propertySet().setProperty(propertyID, value, important, contextStyleSheet());
266
267     didMutate(changed ? PropertyChanged : NoChanges);
268
269     if (changed)
270         mutationScope.enqueueMutationRecord();
271 }
272
273 CSSValue* AbstractPropertySetCSSStyleDeclaration::cloneAndCacheForCSSOM(CSSValue* internalValue)
274 {
275     if (!internalValue)
276         return 0;
277
278     // The map is here to maintain the object identity of the CSSValues over multiple invocations.
279     // FIXME: It is likely that the identity is not important for web compatibility and this code should be removed.
280     if (!m_cssomCSSValueClones)
281         m_cssomCSSValueClones = adoptPtrWillBeNoop(new WillBeHeapHashMap<RawPtrWillBeMember<CSSValue>, RefPtrWillBeMember<CSSValue> >);
282
283     RefPtrWillBeMember<CSSValue>& clonedValue = m_cssomCSSValueClones->add(internalValue, RefPtrWillBeMember<CSSValue>()).storedValue->value;
284     if (!clonedValue)
285         clonedValue = internalValue->cloneForCSSOM();
286     return clonedValue.get();
287 }
288
289 StyleSheetContents* AbstractPropertySetCSSStyleDeclaration::contextStyleSheet() const
290 {
291     CSSStyleSheet* cssStyleSheet = parentStyleSheet();
292     return cssStyleSheet ? cssStyleSheet->contents() : 0;
293 }
294
295 PassRefPtrWillBeRawPtr<MutableStylePropertySet> AbstractPropertySetCSSStyleDeclaration::copyProperties() const
296 {
297     return propertySet().mutableCopy();
298 }
299
300 bool AbstractPropertySetCSSStyleDeclaration::cssPropertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
301 {
302     return propertySet().propertyMatches(propertyID, propertyValue);
303 }
304
305 void AbstractPropertySetCSSStyleDeclaration::trace(Visitor* visitor)
306 {
307 #if ENABLE(OILPAN)
308     visitor->trace(m_cssomCSSValueClones);
309 #endif
310     CSSStyleDeclaration::trace(visitor);
311 }
312
313 StyleRuleCSSStyleDeclaration::StyleRuleCSSStyleDeclaration(MutableStylePropertySet& propertySetArg, CSSRule* parentRule)
314     : PropertySetCSSStyleDeclaration(propertySetArg)
315 #if !ENABLE(OILPAN)
316     , m_refCount(1)
317 #endif
318     , m_parentRule(parentRule)
319 {
320 #if !ENABLE(OILPAN)
321     m_propertySet->ref();
322 #endif
323 }
324
325 StyleRuleCSSStyleDeclaration::~StyleRuleCSSStyleDeclaration()
326 {
327 #if !ENABLE(OILPAN)
328     m_propertySet->deref();
329 #endif
330 }
331
332 #if !ENABLE(OILPAN)
333 void StyleRuleCSSStyleDeclaration::ref()
334 {
335     ++m_refCount;
336 }
337
338 void StyleRuleCSSStyleDeclaration::deref()
339 {
340     ASSERT(m_refCount);
341     if (!--m_refCount)
342         delete this;
343 }
344 #endif
345
346 void StyleRuleCSSStyleDeclaration::willMutate()
347 {
348     if (m_parentRule && m_parentRule->parentStyleSheet())
349         m_parentRule->parentStyleSheet()->willMutateRules();
350 }
351
352 void StyleRuleCSSStyleDeclaration::didMutate(MutationType type)
353 {
354     if (type == PropertyChanged)
355         m_cssomCSSValueClones.clear();
356
357     // Style sheet mutation needs to be signaled even if the change failed. willMutateRules/didMutateRules must pair.
358     if (m_parentRule && m_parentRule->parentStyleSheet())
359         m_parentRule->parentStyleSheet()->didMutateRules();
360 }
361
362 CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
363 {
364     return m_parentRule ? m_parentRule->parentStyleSheet() : 0;
365 }
366
367 void StyleRuleCSSStyleDeclaration::reattach(MutableStylePropertySet& propertySet)
368 {
369 #if !ENABLE(OILPAN)
370     m_propertySet->deref();
371 #endif
372     m_propertySet = &propertySet;
373 #if !ENABLE(OILPAN)
374     m_propertySet->ref();
375 #endif
376 }
377
378 void StyleRuleCSSStyleDeclaration::trace(Visitor* visitor)
379 {
380     visitor->trace(m_parentRule);
381     PropertySetCSSStyleDeclaration::trace(visitor);
382 }
383
384 MutableStylePropertySet& InlineCSSStyleDeclaration::propertySet() const
385 {
386     return m_parentElement->ensureMutableInlineStyle();
387 }
388
389 void InlineCSSStyleDeclaration::didMutate(MutationType type)
390 {
391     if (type == NoChanges)
392         return;
393
394     m_cssomCSSValueClones.clear();
395
396     if (!m_parentElement)
397         return;
398
399     m_parentElement->clearMutableInlineStyleIfEmpty();
400     m_parentElement->setNeedsStyleRecalc(LocalStyleChange);
401     m_parentElement->invalidateStyleAttribute();
402     StyleAttributeMutationScope(this).didInvalidateStyleAttr();
403 }
404
405 CSSStyleSheet* InlineCSSStyleDeclaration::parentStyleSheet() const
406 {
407     return m_parentElement ? &m_parentElement->document().elementSheet() : 0;
408 }
409
410 #if !ENABLE(OILPAN)
411 void InlineCSSStyleDeclaration::ref()
412 {
413     m_parentElement->ref();
414 }
415
416 void InlineCSSStyleDeclaration::deref()
417 {
418     m_parentElement->deref();
419 }
420 #endif
421
422 void InlineCSSStyleDeclaration::trace(Visitor* visitor)
423 {
424     visitor->trace(m_parentElement);
425     AbstractPropertySetCSSStyleDeclaration::trace(visitor);
426 }
427
428 } // namespace blink