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.
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.
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.
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.
23 #include "core/css/PropertySetCSSStyleDeclaration.h"
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"
40 class StyleAttributeMutationScope {
41 WTF_MAKE_NONCOPYABLE(StyleAttributeMutationScope);
44 StyleAttributeMutationScope(AbstractPropertySetCSSStyleDeclaration* decl)
46 InspectorInstrumentation::willMutateStyle(decl);
49 if (s_scopeCount != 1) {
50 ASSERT(s_currentDecl == decl);
54 ASSERT(!s_currentDecl);
57 if (!s_currentDecl->parentElement())
60 bool shouldReadOldValue = false;
62 m_mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(*s_currentDecl->parentElement(), HTMLNames::styleAttr);
63 if (m_mutationRecipients && m_mutationRecipients->isOldValueRequested())
64 shouldReadOldValue = true;
66 AtomicString oldValue;
67 if (shouldReadOldValue)
68 oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr);
70 if (m_mutationRecipients) {
71 AtomicString requestedOldValue = m_mutationRecipients->isOldValueRequested() ? oldValue : nullAtom;
72 m_mutation = MutationRecord::createAttributes(s_currentDecl->parentElement(), HTMLNames::styleAttr, requestedOldValue);
76 ~StyleAttributeMutationScope()
82 if (m_mutation && s_shouldDeliver)
83 m_mutationRecipients->enqueueMutationRecord(m_mutation);
85 s_shouldDeliver = false;
87 // We have to clear internal state before calling Inspector's code.
88 AbstractPropertySetCSSStyleDeclaration* localCopyStyleDecl = s_currentDecl;
90 InspectorInstrumentation::didMutateStyle(localCopyStyleDecl, localCopyStyleDecl->parentElement());
92 if (!s_shouldNotifyInspector)
95 s_shouldNotifyInspector = false;
96 if (localCopyStyleDecl->parentElement())
97 InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl->parentElement());
100 void enqueueMutationRecord()
102 s_shouldDeliver = true;
105 void didInvalidateStyleAttr()
107 s_shouldNotifyInspector = true;
111 static unsigned s_scopeCount;
112 static AbstractPropertySetCSSStyleDeclaration* s_currentDecl;
113 static bool s_shouldNotifyInspector;
114 static bool s_shouldDeliver;
116 OwnPtrWillBeMember<MutationObserverInterestGroup> m_mutationRecipients;
117 RefPtrWillBeMember<MutationRecord> m_mutation;
120 unsigned StyleAttributeMutationScope::s_scopeCount = 0;
121 AbstractPropertySetCSSStyleDeclaration* StyleAttributeMutationScope::s_currentDecl = 0;
122 bool StyleAttributeMutationScope::s_shouldNotifyInspector = false;
123 bool StyleAttributeMutationScope::s_shouldDeliver = false;
128 void PropertySetCSSStyleDeclaration::ref()
130 m_propertySet->ref();
133 void PropertySetCSSStyleDeclaration::deref()
135 m_propertySet->deref();
139 void PropertySetCSSStyleDeclaration::trace(Visitor* visitor)
141 visitor->trace(m_propertySet);
142 AbstractPropertySetCSSStyleDeclaration::trace(visitor);
145 unsigned AbstractPropertySetCSSStyleDeclaration::length() const
147 return propertySet().propertyCount();
150 String AbstractPropertySetCSSStyleDeclaration::item(unsigned i) const
152 if (i >= propertySet().propertyCount())
154 return propertySet().propertyAt(i).cssName();
157 String AbstractPropertySetCSSStyleDeclaration::cssText() const
159 return propertySet().asText();
162 void AbstractPropertySetCSSStyleDeclaration::setCSSText(const String& text, ExceptionState& exceptionState)
164 StyleAttributeMutationScope mutationScope(this);
167 // FIXME: Detect syntax errors and set exceptionState.
168 propertySet().parseDeclaration(text, contextStyleSheet());
170 didMutate(PropertyChanged);
172 mutationScope.enqueueMutationRecord();
175 PassRefPtrWillBeRawPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
177 CSSPropertyID propertyID = cssPropertyID(propertyName);
180 return cloneAndCacheForCSSOM(propertySet().getPropertyCSSValue(propertyID).get());
183 String AbstractPropertySetCSSStyleDeclaration::getPropertyValue(const String &propertyName)
185 CSSPropertyID propertyID = cssPropertyID(propertyName);
188 return propertySet().getPropertyValue(propertyID);
191 String AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
193 CSSPropertyID propertyID = cssPropertyID(propertyName);
196 return propertySet().propertyIsImportant(propertyID) ? "important" : "";
199 String AbstractPropertySetCSSStyleDeclaration::getPropertyShorthand(const String& propertyName)
201 CSSPropertyID propertyID = cssPropertyID(propertyName);
204 CSSPropertyID shorthandID = propertySet().getPropertyShorthand(propertyID);
207 return getPropertyNameString(shorthandID);
210 bool AbstractPropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyName)
212 CSSPropertyID propertyID = cssPropertyID(propertyName);
215 return propertySet().isPropertyImplicit(propertyID);
218 void AbstractPropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionState& exceptionState)
220 CSSPropertyID propertyID = cssPropertyID(propertyName);
224 bool important = equalIgnoringCase(priority, "important");
225 if (!important && !priority.isEmpty())
228 setPropertyInternal(propertyID, value, important, exceptionState);
231 String AbstractPropertySetCSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionState& exceptionState)
233 StyleAttributeMutationScope mutationScope(this);
234 CSSPropertyID propertyID = cssPropertyID(propertyName);
241 bool changed = propertySet().removeProperty(propertyID, &result);
243 didMutate(changed ? PropertyChanged : NoChanges);
246 mutationScope.enqueueMutationRecord();
250 PassRefPtrWillBeRawPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID)
252 return propertySet().getPropertyCSSValue(propertyID);
255 String AbstractPropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID)
257 return propertySet().getPropertyValue(propertyID);
260 void AbstractPropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionState&)
262 StyleAttributeMutationScope mutationScope(this);
265 bool changed = propertySet().setProperty(propertyID, value, important, contextStyleSheet());
267 didMutate(changed ? PropertyChanged : NoChanges);
270 mutationScope.enqueueMutationRecord();
273 CSSValue* AbstractPropertySetCSSStyleDeclaration::cloneAndCacheForCSSOM(CSSValue* internalValue)
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> >);
283 RefPtrWillBeMember<CSSValue>& clonedValue = m_cssomCSSValueClones->add(internalValue, RefPtrWillBeMember<CSSValue>()).storedValue->value;
285 clonedValue = internalValue->cloneForCSSOM();
286 return clonedValue.get();
289 StyleSheetContents* AbstractPropertySetCSSStyleDeclaration::contextStyleSheet() const
291 CSSStyleSheet* cssStyleSheet = parentStyleSheet();
292 return cssStyleSheet ? cssStyleSheet->contents() : 0;
295 PassRefPtrWillBeRawPtr<MutableStylePropertySet> AbstractPropertySetCSSStyleDeclaration::copyProperties() const
297 return propertySet().mutableCopy();
300 bool AbstractPropertySetCSSStyleDeclaration::cssPropertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
302 return propertySet().propertyMatches(propertyID, propertyValue);
305 void AbstractPropertySetCSSStyleDeclaration::trace(Visitor* visitor)
308 visitor->trace(m_cssomCSSValueClones);
310 CSSStyleDeclaration::trace(visitor);
313 StyleRuleCSSStyleDeclaration::StyleRuleCSSStyleDeclaration(MutableStylePropertySet& propertySetArg, CSSRule* parentRule)
314 : PropertySetCSSStyleDeclaration(propertySetArg)
318 , m_parentRule(parentRule)
321 m_propertySet->ref();
325 StyleRuleCSSStyleDeclaration::~StyleRuleCSSStyleDeclaration()
328 m_propertySet->deref();
333 void StyleRuleCSSStyleDeclaration::ref()
338 void StyleRuleCSSStyleDeclaration::deref()
346 void StyleRuleCSSStyleDeclaration::willMutate()
348 if (m_parentRule && m_parentRule->parentStyleSheet())
349 m_parentRule->parentStyleSheet()->willMutateRules();
352 void StyleRuleCSSStyleDeclaration::didMutate(MutationType type)
354 if (type == PropertyChanged)
355 m_cssomCSSValueClones.clear();
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();
362 CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
364 return m_parentRule ? m_parentRule->parentStyleSheet() : 0;
367 void StyleRuleCSSStyleDeclaration::reattach(MutableStylePropertySet& propertySet)
370 m_propertySet->deref();
372 m_propertySet = &propertySet;
374 m_propertySet->ref();
378 void StyleRuleCSSStyleDeclaration::trace(Visitor* visitor)
380 visitor->trace(m_parentRule);
381 PropertySetCSSStyleDeclaration::trace(visitor);
384 MutableStylePropertySet& InlineCSSStyleDeclaration::propertySet() const
386 return m_parentElement->ensureMutableInlineStyle();
389 void InlineCSSStyleDeclaration::didMutate(MutationType type)
391 if (type == NoChanges)
394 m_cssomCSSValueClones.clear();
396 if (!m_parentElement)
399 m_parentElement->clearMutableInlineStyleIfEmpty();
400 m_parentElement->setNeedsStyleRecalc(LocalStyleChange);
401 m_parentElement->invalidateStyleAttribute();
402 StyleAttributeMutationScope(this).didInvalidateStyleAttr();
405 CSSStyleSheet* InlineCSSStyleDeclaration::parentStyleSheet() const
407 return m_parentElement ? &m_parentElement->document().elementSheet() : 0;
411 void InlineCSSStyleDeclaration::ref()
413 m_parentElement->ref();
416 void InlineCSSStyleDeclaration::deref()
418 m_parentElement->deref();
422 void InlineCSSStyleDeclaration::trace(Visitor* visitor)
424 visitor->trace(m_parentElement);
425 AbstractPropertySetCSSStyleDeclaration::trace(visitor);