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/CSSKeyframesRule.h"
28 #include "core/css/CSSStyleSheet.h"
29 #include "core/css/StylePropertySet.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
)
48 if (s_scopeCount
!= 1) {
49 ASSERT(s_currentDecl
== decl
);
53 ASSERT(!s_currentDecl
);
56 if (!s_currentDecl
->parentElement())
59 bool shouldReadOldValue
= false;
61 m_mutationRecipients
= MutationObserverInterestGroup::createForAttributesMutation(*s_currentDecl
->parentElement(), HTMLNames::styleAttr
);
62 if (m_mutationRecipients
&& m_mutationRecipients
->isOldValueRequested())
63 shouldReadOldValue
= true;
65 AtomicString oldValue
;
66 if (shouldReadOldValue
)
67 oldValue
= s_currentDecl
->parentElement()->getAttribute(HTMLNames::styleAttr
);
69 if (m_mutationRecipients
) {
70 AtomicString requestedOldValue
= m_mutationRecipients
->isOldValueRequested() ? oldValue
: nullAtom
;
71 m_mutation
= MutationRecord::createAttributes(s_currentDecl
->parentElement(), HTMLNames::styleAttr
, requestedOldValue
);
75 ~StyleAttributeMutationScope()
81 if (m_mutation
&& s_shouldDeliver
)
82 m_mutationRecipients
->enqueueMutationRecord(m_mutation
);
84 s_shouldDeliver
= false;
86 // We have to clear internal state before calling Inspector's code.
87 AbstractPropertySetCSSStyleDeclaration
* localCopyStyleDecl
= s_currentDecl
;
90 if (!s_shouldNotifyInspector
)
93 s_shouldNotifyInspector
= false;
94 if (localCopyStyleDecl
->parentElement())
95 InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl
->parentElement());
98 void enqueueMutationRecord()
100 s_shouldDeliver
= true;
103 void didInvalidateStyleAttr()
105 s_shouldNotifyInspector
= true;
109 static unsigned s_scopeCount
;
110 static AbstractPropertySetCSSStyleDeclaration
* s_currentDecl
;
111 static bool s_shouldNotifyInspector
;
112 static bool s_shouldDeliver
;
114 OwnPtrWillBeMember
<MutationObserverInterestGroup
> m_mutationRecipients
;
115 RefPtrWillBeMember
<MutationRecord
> m_mutation
;
118 unsigned StyleAttributeMutationScope::s_scopeCount
= 0;
119 AbstractPropertySetCSSStyleDeclaration
* StyleAttributeMutationScope::s_currentDecl
= 0;
120 bool StyleAttributeMutationScope::s_shouldNotifyInspector
= false;
121 bool StyleAttributeMutationScope::s_shouldDeliver
= false;
126 void PropertySetCSSStyleDeclaration::ref()
128 m_propertySet
->ref();
131 void PropertySetCSSStyleDeclaration::deref()
133 m_propertySet
->deref();
137 DEFINE_TRACE(PropertySetCSSStyleDeclaration
)
139 visitor
->trace(m_propertySet
);
140 AbstractPropertySetCSSStyleDeclaration::trace(visitor
);
143 unsigned AbstractPropertySetCSSStyleDeclaration::length() const
145 return propertySet().propertyCount();
148 String
AbstractPropertySetCSSStyleDeclaration::item(unsigned i
) const
150 if (i
>= propertySet().propertyCount())
152 return getPropertyName(propertySet().propertyAt(i
).id());
155 String
AbstractPropertySetCSSStyleDeclaration::cssText() const
157 return propertySet().asText();
160 void AbstractPropertySetCSSStyleDeclaration::setCSSText(const String
& text
, ExceptionState
&)
162 StyleAttributeMutationScope
mutationScope(this);
165 propertySet().parseDeclarationList(text
, contextStyleSheet());
167 didMutate(PropertyChanged
);
169 mutationScope
.enqueueMutationRecord();
172 String
AbstractPropertySetCSSStyleDeclaration::getPropertyValue(const String
&propertyName
)
174 CSSPropertyID propertyID
= cssPropertyID(propertyName
);
177 return propertySet().getPropertyValue(propertyID
);
180 String
AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(const String
& propertyName
)
182 CSSPropertyID propertyID
= cssPropertyID(propertyName
);
185 return propertySet().propertyIsImportant(propertyID
) ? "important" : "";
188 String
AbstractPropertySetCSSStyleDeclaration::getPropertyShorthand(const String
& propertyName
)
190 CSSPropertyID propertyID
= cssPropertyID(propertyName
);
193 CSSPropertyID shorthandID
= propertySet().getPropertyShorthand(propertyID
);
196 return getPropertyNameString(shorthandID
);
199 bool AbstractPropertySetCSSStyleDeclaration::isPropertyImplicit(const String
& propertyName
)
201 CSSPropertyID propertyID
= cssPropertyID(propertyName
);
204 return propertySet().isPropertyImplicit(propertyID
);
207 void AbstractPropertySetCSSStyleDeclaration::setProperty(const String
& propertyName
, const String
& value
, const String
& priority
, ExceptionState
& exceptionState
)
209 CSSPropertyID propertyID
= unresolvedCSSPropertyID(propertyName
);
213 bool important
= equalIgnoringCase(priority
, "important");
214 if (!important
&& !priority
.isEmpty())
217 setPropertyInternal(propertyID
, value
, important
, exceptionState
);
220 String
AbstractPropertySetCSSStyleDeclaration::removeProperty(const String
& propertyName
, ExceptionState
& exceptionState
)
222 StyleAttributeMutationScope
mutationScope(this);
223 CSSPropertyID propertyID
= cssPropertyID(propertyName
);
230 bool changed
= propertySet().removeProperty(propertyID
, &result
);
232 didMutate(changed
? PropertyChanged
: NoChanges
);
235 mutationScope
.enqueueMutationRecord();
239 PassRefPtrWillBeRawPtr
<CSSValue
> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID
)
241 return propertySet().getPropertyCSSValue(propertyID
);
244 String
AbstractPropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID
)
246 return propertySet().getPropertyValue(propertyID
);
249 void AbstractPropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID unresolvedProperty
, const String
& value
, bool important
, ExceptionState
&)
251 StyleAttributeMutationScope
mutationScope(this);
254 bool changed
= propertySet().setProperty(unresolvedProperty
, value
, important
, contextStyleSheet());
256 didMutate(changed
? PropertyChanged
: NoChanges
);
259 mutationScope
.enqueueMutationRecord();
262 StyleSheetContents
* AbstractPropertySetCSSStyleDeclaration::contextStyleSheet() const
264 CSSStyleSheet
* cssStyleSheet
= parentStyleSheet();
265 return cssStyleSheet
? cssStyleSheet
->contents() : nullptr;
268 bool AbstractPropertySetCSSStyleDeclaration::cssPropertyMatches(CSSPropertyID propertyID
, const CSSValue
* propertyValue
) const
270 return propertySet().propertyMatches(propertyID
, propertyValue
);
273 DEFINE_TRACE(AbstractPropertySetCSSStyleDeclaration
)
275 CSSStyleDeclaration::trace(visitor
);
278 StyleRuleCSSStyleDeclaration::StyleRuleCSSStyleDeclaration(MutableStylePropertySet
& propertySetArg
, CSSRule
* parentRule
)
279 : PropertySetCSSStyleDeclaration(propertySetArg
)
283 , m_parentRule(parentRule
)
286 m_propertySet
->ref();
290 StyleRuleCSSStyleDeclaration::~StyleRuleCSSStyleDeclaration()
293 m_propertySet
->deref();
298 void StyleRuleCSSStyleDeclaration::ref()
303 void StyleRuleCSSStyleDeclaration::deref()
311 void StyleRuleCSSStyleDeclaration::willMutate()
313 if (m_parentRule
&& m_parentRule
->parentStyleSheet())
314 m_parentRule
->parentStyleSheet()->willMutateRules();
317 void StyleRuleCSSStyleDeclaration::didMutate(MutationType type
)
319 // Style sheet mutation needs to be signaled even if the change failed. willMutateRules/didMutateRules must pair.
320 if (m_parentRule
&& m_parentRule
->parentStyleSheet())
321 m_parentRule
->parentStyleSheet()->didMutateRules();
324 CSSStyleSheet
* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
326 return m_parentRule
? m_parentRule
->parentStyleSheet() : nullptr;
329 void StyleRuleCSSStyleDeclaration::reattach(MutableStylePropertySet
& propertySet
)
332 m_propertySet
->deref();
334 m_propertySet
= &propertySet
;
336 m_propertySet
->ref();
340 DEFINE_TRACE(StyleRuleCSSStyleDeclaration
)
342 visitor
->trace(m_parentRule
);
343 PropertySetCSSStyleDeclaration::trace(visitor
);
346 MutableStylePropertySet
& InlineCSSStyleDeclaration::propertySet() const
348 return m_parentElement
->ensureMutableInlineStyle();
351 void InlineCSSStyleDeclaration::didMutate(MutationType type
)
353 if (type
== NoChanges
)
356 if (!m_parentElement
)
359 m_parentElement
->clearMutableInlineStyleIfEmpty();
360 m_parentElement
->setNeedsStyleRecalc(LocalStyleChange
, StyleChangeReasonForTracing::create(StyleChangeReason::InlineCSSStyleMutated
));
361 m_parentElement
->invalidateStyleAttribute();
362 StyleAttributeMutationScope(this).didInvalidateStyleAttr();
365 CSSStyleSheet
* InlineCSSStyleDeclaration::parentStyleSheet() const
367 return m_parentElement
? &m_parentElement
->document().elementSheet() : nullptr;
371 void InlineCSSStyleDeclaration::ref()
373 m_parentElement
->ref();
376 void InlineCSSStyleDeclaration::deref()
378 m_parentElement
->deref();
382 DEFINE_TRACE(InlineCSSStyleDeclaration
)
384 visitor
->trace(m_parentElement
);
385 AbstractPropertySetCSSStyleDeclaration::trace(visitor
);