/src/mozilla-central/layout/style/nsDOMCSSAttrDeclaration.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* DOM object for element.style */ |
8 | | |
9 | | #include "nsDOMCSSAttrDeclaration.h" |
10 | | |
11 | | #include "mozilla/DeclarationBlock.h" |
12 | | #include "mozilla/dom/Element.h" |
13 | | #include "mozilla/dom/MutationEventBinding.h" |
14 | | #include "mozilla/InternalMutationEvent.h" |
15 | | #include "mozAutoDocUpdate.h" |
16 | | #include "nsIDocument.h" |
17 | | #include "nsIURI.h" |
18 | | #include "nsNodeUtils.h" |
19 | | #include "nsSMILCSSValueType.h" |
20 | | #include "nsWrapperCacheInlines.h" |
21 | | #include "nsIFrame.h" |
22 | | #include "ActiveLayerTracker.h" |
23 | | |
24 | | using namespace mozilla; |
25 | | |
26 | | nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(dom::Element* aElement, |
27 | | bool aIsSMILOverride) |
28 | | : mElement(aElement) |
29 | | , mIsSMILOverride(aIsSMILOverride) |
30 | 0 | { |
31 | 0 | NS_ASSERTION(aElement, "Inline style for a NULL element?"); |
32 | 0 | } |
33 | | |
34 | | nsDOMCSSAttributeDeclaration::~nsDOMCSSAttributeDeclaration() |
35 | 0 | { |
36 | 0 | } |
37 | | |
38 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSAttributeDeclaration, mElement) |
39 | | |
40 | | // mElement holds a strong ref to us, so if it's going to be |
41 | | // skipped, the attribute declaration can't be part of a garbage |
42 | | // cycle. |
43 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMCSSAttributeDeclaration) |
44 | 0 | if (tmp->mElement && Element::CanSkip(tmp->mElement, true)) { |
45 | 0 | if (tmp->PreservingWrapper()) { |
46 | 0 | tmp->MarkWrapperLive(); |
47 | 0 | } |
48 | 0 | return true; |
49 | 0 | } |
50 | 0 | return tmp->HasKnownLiveWrapper(); |
51 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END |
52 | | |
53 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMCSSAttributeDeclaration) |
54 | 0 | return tmp->HasKnownLiveWrapper() || |
55 | 0 | (tmp->mElement && Element::CanSkipInCC(tmp->mElement)); |
56 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END |
57 | | |
58 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMCSSAttributeDeclaration) |
59 | 0 | return tmp->HasKnownLiveWrapper() || |
60 | 0 | (tmp->mElement && Element::CanSkipThis(tmp->mElement)); |
61 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END |
62 | | |
63 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSAttributeDeclaration) |
64 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
65 | 0 | NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration) |
66 | | |
67 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCSSAttributeDeclaration) |
68 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCSSAttributeDeclaration) |
69 | | |
70 | | nsresult |
71 | | nsDOMCSSAttributeDeclaration::SetCSSDeclaration(DeclarationBlock* aDecl, |
72 | | MutationClosureData* aClosureData) |
73 | 0 | { |
74 | 0 | NS_ASSERTION(mElement, "Must have Element to set the declaration!"); |
75 | 0 |
|
76 | 0 | // Whenever changing element.style values, aClosureData must be non-null. |
77 | 0 | // SMIL doesn't update Element's attribute values, so closure data isn't |
78 | 0 | // needed. |
79 | 0 | MOZ_ASSERT_IF(!mIsSMILOverride, aClosureData); |
80 | 0 |
|
81 | 0 | // If the closure hasn't been called because the declaration wasn't changed, |
82 | 0 | // we need to explicitly call it now to get InlineStyleDeclarationWillChange |
83 | 0 | // notification before SetInlineStyleDeclaration. |
84 | 0 | if (aClosureData && aClosureData->mClosure) { |
85 | 0 | aClosureData->mClosure(aClosureData); |
86 | 0 | } |
87 | 0 |
|
88 | 0 | aDecl->SetDirty(); |
89 | 0 | return mIsSMILOverride |
90 | 0 | ? mElement->SetSMILOverrideStyleDeclaration(aDecl, true) |
91 | 0 | : mElement->SetInlineStyleDeclaration(*aDecl, *aClosureData); |
92 | 0 | } |
93 | | |
94 | | nsIDocument* |
95 | | nsDOMCSSAttributeDeclaration::DocToUpdate() |
96 | 0 | { |
97 | 0 | // We need OwnerDoc() rather than GetUncomposedDoc() because it might |
98 | 0 | // be the BeginUpdate call that inserts mElement into the document. |
99 | 0 | return mElement->OwnerDoc(); |
100 | 0 | } |
101 | | |
102 | | DeclarationBlock* |
103 | | nsDOMCSSAttributeDeclaration::GetOrCreateCSSDeclaration(Operation aOperation, |
104 | | DeclarationBlock** aCreated) |
105 | 0 | { |
106 | 0 | MOZ_ASSERT(aOperation != eOperation_Modify || aCreated); |
107 | 0 |
|
108 | 0 | if (!mElement) |
109 | 0 | return nullptr; |
110 | 0 | |
111 | 0 | DeclarationBlock* declaration; |
112 | 0 | if (mIsSMILOverride) { |
113 | 0 | declaration = mElement->GetSMILOverrideStyleDeclaration(); |
114 | 0 | } else { |
115 | 0 | declaration = mElement->GetInlineStyleDeclaration(); |
116 | 0 | } |
117 | 0 |
|
118 | 0 | if (declaration) { |
119 | 0 | return declaration; |
120 | 0 | } |
121 | 0 | |
122 | 0 | if (aOperation != eOperation_Modify) { |
123 | 0 | return nullptr; |
124 | 0 | } |
125 | 0 | |
126 | 0 | // cannot fail |
127 | 0 | RefPtr<DeclarationBlock> decl = new DeclarationBlock(); |
128 | 0 | // Mark the declaration dirty so that it can be reused by the caller. |
129 | 0 | // Normally SetDirty is called later in SetCSSDeclaration. |
130 | 0 | decl->SetDirty(); |
131 | | #ifdef DEBUG |
132 | | RefPtr<DeclarationBlock> mutableDecl = decl->EnsureMutable(); |
133 | | MOZ_ASSERT(mutableDecl == decl); |
134 | | #endif |
135 | | decl.swap(*aCreated); |
136 | 0 | return *aCreated; |
137 | 0 | } |
138 | | |
139 | | nsDOMCSSDeclaration::ParsingEnvironment |
140 | | nsDOMCSSAttributeDeclaration::GetParsingEnvironment( |
141 | | nsIPrincipal* aSubjectPrincipal) const |
142 | 0 | { |
143 | 0 | return { |
144 | 0 | mElement->GetURLDataForStyleAttr(aSubjectPrincipal), |
145 | 0 | mElement->OwnerDoc()->GetCompatibilityMode(), |
146 | 0 | mElement->OwnerDoc()->CSSLoader(), |
147 | 0 | }; |
148 | 0 | } |
149 | | |
150 | | nsresult |
151 | | nsDOMCSSAttributeDeclaration::SetSMILValue(const nsCSSPropertyID aPropID, |
152 | | const nsSMILValue& aValue) |
153 | 0 | { |
154 | 0 | MOZ_ASSERT(mIsSMILOverride); |
155 | 0 | // No need to do the ActiveLayerTracker / ScrollLinkedEffectDetector bits, |
156 | 0 | // since we're in a SMIL animation anyway, no need to try to detect we're a |
157 | 0 | // scripted animation. |
158 | 0 | RefPtr<DeclarationBlock> created; |
159 | 0 | DeclarationBlock* olddecl = |
160 | 0 | GetOrCreateCSSDeclaration(eOperation_Modify, getter_AddRefs(created)); |
161 | 0 | if (!olddecl) { |
162 | 0 | return NS_ERROR_NOT_AVAILABLE; |
163 | 0 | } |
164 | 0 | mozAutoDocUpdate autoUpdate(DocToUpdate(), true); |
165 | 0 | RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable(); |
166 | 0 | bool changed = nsSMILCSSValueType::SetPropertyValues(aValue, *decl); |
167 | 0 | if (changed) { |
168 | 0 | // We can pass nullptr as the latter param, since this is |
169 | 0 | // mIsSMILOverride == true case. |
170 | 0 | SetCSSDeclaration(decl, nullptr); |
171 | 0 | } |
172 | 0 | return NS_OK; |
173 | 0 | } |
174 | | |
175 | | nsresult |
176 | | nsDOMCSSAttributeDeclaration::SetPropertyValue(const nsCSSPropertyID aPropID, |
177 | | const nsAString& aValue, |
178 | | nsIPrincipal* aSubjectPrincipal) |
179 | 0 | { |
180 | 0 | // Scripted modifications to style.opacity or style.transform |
181 | 0 | // could immediately force us into the animated state if heuristics suggest |
182 | 0 | // this is scripted animation. |
183 | 0 | // FIXME: This is missing the margin shorthand and the logical versions of |
184 | 0 | // the margin properties, see bug 1266287. |
185 | 0 | if (aPropID == eCSSProperty_opacity || aPropID == eCSSProperty_transform || |
186 | 0 | aPropID == eCSSProperty_left || aPropID == eCSSProperty_top || |
187 | 0 | aPropID == eCSSProperty_right || aPropID == eCSSProperty_bottom || |
188 | 0 | aPropID == eCSSProperty_background_position_x || |
189 | 0 | aPropID == eCSSProperty_background_position_y || |
190 | 0 | aPropID == eCSSProperty_background_position) { |
191 | 0 | nsIFrame* frame = mElement->GetPrimaryFrame(); |
192 | 0 | if (frame) { |
193 | 0 | ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropID, aValue, this); |
194 | 0 | } |
195 | 0 | } |
196 | 0 | return nsDOMCSSDeclaration::SetPropertyValue(aPropID, aValue, aSubjectPrincipal); |
197 | 0 | } |
198 | | |
199 | | void |
200 | | nsDOMCSSAttributeDeclaration::MutationClosureFunction(void* aData) |
201 | 0 | { |
202 | 0 | MutationClosureData* data = static_cast<MutationClosureData*>(aData); |
203 | 0 | // Clear mClosure pointer so that it doesn't get called again. |
204 | 0 | data->mClosure = nullptr; |
205 | 0 | data->mElement->InlineStyleDeclarationWillChange(*data); |
206 | 0 | } |