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 "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"
44 class StyleAttributeMutationScope {
45 WTF_MAKE_NONCOPYABLE(StyleAttributeMutationScope);
47 StyleAttributeMutationScope(AbstractPropertySetCSSStyleDeclaration* decl)
49 InspectorInstrumentation::willMutateStyle(decl);
52 if (s_scopeCount != 1) {
53 ASSERT(s_currentDecl == decl);
57 ASSERT(!s_currentDecl);
60 if (!s_currentDecl->parentElement())
63 bool shouldReadOldValue = false;
65 m_mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(*s_currentDecl->parentElement(), HTMLNames::styleAttr);
66 if (m_mutationRecipients && m_mutationRecipients->isOldValueRequested())
67 shouldReadOldValue = true;
69 AtomicString oldValue;
70 if (shouldReadOldValue)
71 oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr);
73 if (m_mutationRecipients) {
74 AtomicString requestedOldValue = m_mutationRecipients->isOldValueRequested() ? oldValue : nullAtom;
75 m_mutation = MutationRecord::createAttributes(s_currentDecl->parentElement(), HTMLNames::styleAttr, requestedOldValue);
79 ~StyleAttributeMutationScope()
85 if (m_mutation && s_shouldDeliver)
86 m_mutationRecipients->enqueueMutationRecord(m_mutation);
88 s_shouldDeliver = false;
90 // We have to clear internal state before calling Inspector's code.
91 AbstractPropertySetCSSStyleDeclaration* localCopyStyleDecl = s_currentDecl;
93 InspectorInstrumentation::didMutateStyle(localCopyStyleDecl, localCopyStyleDecl->parentElement());
95 if (!s_shouldNotifyInspector)
98 s_shouldNotifyInspector = false;
99 if (localCopyStyleDecl->parentElement())
100 InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl->parentElement());
103 void enqueueMutationRecord()
105 s_shouldDeliver = true;
108 void didInvalidateStyleAttr()
110 s_shouldNotifyInspector = true;
114 static unsigned s_scopeCount;
115 static AbstractPropertySetCSSStyleDeclaration* s_currentDecl;
116 static bool s_shouldNotifyInspector;
117 static bool s_shouldDeliver;
119 OwnPtr<MutationObserverInterestGroup> m_mutationRecipients;
120 RefPtr<MutationRecord> m_mutation;
123 unsigned StyleAttributeMutationScope::s_scopeCount = 0;
124 AbstractPropertySetCSSStyleDeclaration* StyleAttributeMutationScope::s_currentDecl = 0;
125 bool StyleAttributeMutationScope::s_shouldNotifyInspector = false;
126 bool StyleAttributeMutationScope::s_shouldDeliver = false;
130 void PropertySetCSSStyleDeclaration::ref()
132 m_propertySet->ref();
135 void PropertySetCSSStyleDeclaration::deref()
137 m_propertySet->deref();
140 unsigned AbstractPropertySetCSSStyleDeclaration::length() const
142 return propertySet()->propertyCount();
145 String AbstractPropertySetCSSStyleDeclaration::item(unsigned i) const
147 if (i >= propertySet()->propertyCount())
149 return propertySet()->propertyAt(i).cssName();
152 String AbstractPropertySetCSSStyleDeclaration::cssText() const
154 return propertySet()->asText();
157 void AbstractPropertySetCSSStyleDeclaration::setCSSText(const String& text, ExceptionState& exceptionState)
159 if (parentElement()) {
160 ContentSecurityPolicy* csp = parentElement()->document().contentSecurityPolicy();
161 if (!csp->allowStyleEval()) {
162 exceptionState.throwSecurityError(csp->styleEvalDisabledErrorMessage());
167 StyleAttributeMutationScope mutationScope(this);
170 // FIXME: Detect syntax errors and set exceptionState.
171 propertySet()->parseDeclaration(text, contextStyleSheet());
173 didMutate(PropertyChanged);
175 mutationScope.enqueueMutationRecord();
178 PassRefPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
180 CSSPropertyID propertyID = cssPropertyID(propertyName);
183 return cloneAndCacheForCSSOM(propertySet()->getPropertyCSSValue(propertyID).get());
186 String AbstractPropertySetCSSStyleDeclaration::getPropertyValue(const String &propertyName)
188 CSSPropertyID propertyID = cssPropertyID(propertyName);
191 return propertySet()->getPropertyValue(propertyID);
194 String AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
196 CSSPropertyID propertyID = cssPropertyID(propertyName);
199 return propertySet()->propertyIsImportant(propertyID) ? "important" : "";
202 String AbstractPropertySetCSSStyleDeclaration::getPropertyShorthand(const String& propertyName)
204 CSSPropertyID propertyID = cssPropertyID(propertyName);
207 CSSPropertyID shorthandID = propertySet()->getPropertyShorthand(propertyID);
210 return getPropertyNameString(shorthandID);
213 bool AbstractPropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyName)
215 CSSPropertyID propertyID = cssPropertyID(propertyName);
218 return propertySet()->isPropertyImplicit(propertyID);
221 void AbstractPropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionState& exceptionState)
223 StyleAttributeMutationScope mutationScope(this);
224 CSSPropertyID propertyID = cssPropertyID(propertyName);
228 bool important = priority.find("important", 0, false) != kNotFound;
232 bool changed = propertySet()->setProperty(propertyID, value, important, contextStyleSheet());
234 didMutate(changed ? PropertyChanged : NoChanges);
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();
243 String AbstractPropertySetCSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionState& exceptionState)
245 StyleAttributeMutationScope mutationScope(this);
246 CSSPropertyID propertyID = cssPropertyID(propertyName);
253 bool changed = propertySet()->removeProperty(propertyID, &result);
255 didMutate(changed ? PropertyChanged : NoChanges);
258 mutationScope.enqueueMutationRecord();
262 PassRefPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID)
264 return propertySet()->getPropertyCSSValue(propertyID);
267 String AbstractPropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID)
269 return propertySet()->getPropertyValue(propertyID);
272 void AbstractPropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionState&)
274 StyleAttributeMutationScope mutationScope(this);
277 bool changed = propertySet()->setProperty(propertyID, value, important, contextStyleSheet());
279 didMutate(changed ? PropertyChanged : NoChanges);
282 mutationScope.enqueueMutationRecord();
285 CSSValue* AbstractPropertySetCSSStyleDeclaration::cloneAndCacheForCSSOM(CSSValue* internalValue)
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> >);
295 RefPtr<CSSValue>& clonedValue = m_cssomCSSValueClones->add(internalValue, RefPtr<CSSValue>()).storedValue->value;
297 clonedValue = internalValue->cloneForCSSOM();
298 return clonedValue.get();
301 StyleSheetContents* AbstractPropertySetCSSStyleDeclaration::contextStyleSheet() const
303 CSSStyleSheet* cssStyleSheet = parentStyleSheet();
304 return cssStyleSheet ? cssStyleSheet->contents() : 0;
307 PassRefPtr<MutableStylePropertySet> AbstractPropertySetCSSStyleDeclaration::copyProperties() const
309 return propertySet()->mutableCopy();
312 bool AbstractPropertySetCSSStyleDeclaration::cssPropertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
314 return propertySet()->propertyMatches(propertyID, propertyValue);
317 StyleRuleCSSStyleDeclaration::StyleRuleCSSStyleDeclaration(MutableStylePropertySet* propertySetArg, CSSRule* parentRule)
318 : PropertySetCSSStyleDeclaration(propertySetArg)
320 , m_parentRule(parentRule)
322 m_propertySet->ref();
325 StyleRuleCSSStyleDeclaration::~StyleRuleCSSStyleDeclaration()
327 m_propertySet->deref();
330 void StyleRuleCSSStyleDeclaration::ref()
335 void StyleRuleCSSStyleDeclaration::deref()
342 void StyleRuleCSSStyleDeclaration::willMutate()
344 if (m_parentRule && m_parentRule->parentStyleSheet())
345 m_parentRule->parentStyleSheet()->willMutateRules();
348 void StyleRuleCSSStyleDeclaration::didMutate(MutationType type)
350 if (type == PropertyChanged)
351 m_cssomCSSValueClones.clear();
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();
358 CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
360 return m_parentRule ? m_parentRule->parentStyleSheet() : 0;
363 void StyleRuleCSSStyleDeclaration::reattach(MutableStylePropertySet* propertySet)
366 m_propertySet->deref();
367 m_propertySet = propertySet;
368 m_propertySet->ref();
371 MutableStylePropertySet* InlineCSSStyleDeclaration::propertySet() const
373 return m_parentElement->ensureMutableInlineStyle();
376 void InlineCSSStyleDeclaration::didMutate(MutationType type)
378 if (type == NoChanges)
381 m_cssomCSSValueClones.clear();
383 if (!m_parentElement)
386 m_parentElement->clearMutableInlineStyleIfEmpty();
387 m_parentElement->setNeedsStyleRecalc(LocalStyleChange);
388 m_parentElement->invalidateStyleAttribute();
389 StyleAttributeMutationScope(this).didInvalidateStyleAttr();
392 CSSStyleSheet* InlineCSSStyleDeclaration::parentStyleSheet() const
394 return m_parentElement ? m_parentElement->document().elementSheet() : 0;
397 void InlineCSSStyleDeclaration::ref()
399 m_parentElement->ref();
402 void InlineCSSStyleDeclaration::deref()
404 m_parentElement->deref();
407 } // namespace WebCore