/src/mozilla-central/dom/base/Attr.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 | | /* |
8 | | * Implementation of DOM Core's Attr node. |
9 | | */ |
10 | | |
11 | | #include "mozilla/dom/Attr.h" |
12 | | #include "mozilla/dom/AttrBinding.h" |
13 | | #include "mozilla/dom/Element.h" |
14 | | #include "mozilla/EventDispatcher.h" |
15 | | #include "mozilla/InternalMutationEvent.h" |
16 | | #include "nsContentCreatorFunctions.h" |
17 | | #include "nsError.h" |
18 | | #include "nsUnicharUtils.h" |
19 | | #include "nsDOMString.h" |
20 | | #include "nsIContentInlines.h" |
21 | | #include "nsIDocument.h" |
22 | | #include "nsGkAtoms.h" |
23 | | #include "nsCOMArray.h" |
24 | | #include "nsNameSpaceManager.h" |
25 | | #include "nsNodeUtils.h" |
26 | | #include "nsTextNode.h" |
27 | | #include "mozAutoDocUpdate.h" |
28 | | #include "nsWrapperCacheInlines.h" |
29 | | #include "NodeUbiReporting.h" |
30 | | |
31 | | namespace mozilla { |
32 | | namespace dom { |
33 | | |
34 | | //---------------------------------------------------------------------- |
35 | | bool Attr::sInitialized; |
36 | | |
37 | | Attr::Attr(nsDOMAttributeMap *aAttrMap, |
38 | | already_AddRefed<dom::NodeInfo>&& aNodeInfo, |
39 | | const nsAString& aValue) |
40 | | : nsINode(std::move(aNodeInfo)), mAttrMap(aAttrMap), mValue(aValue) |
41 | 0 | { |
42 | 0 | MOZ_ASSERT(mNodeInfo, "We must get a nodeinfo here!"); |
43 | 0 | MOZ_ASSERT(mNodeInfo->NodeType() == ATTRIBUTE_NODE, |
44 | 0 | "Wrong nodeType"); |
45 | 0 |
|
46 | 0 | // We don't add a reference to our content. It will tell us |
47 | 0 | // to drop our reference when it goes away. |
48 | 0 | } |
49 | | |
50 | | NS_IMPL_CYCLE_COLLECTION_CLASS(Attr) |
51 | | |
52 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Attr) |
53 | 0 | if (!nsINode::Traverse(tmp, cb)) { |
54 | 0 | return NS_SUCCESS_INTERRUPTED_TRAVERSE; |
55 | 0 | } |
56 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttrMap) |
57 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
58 | | |
59 | | NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Attr) |
60 | | |
61 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Attr) |
62 | 0 | nsINode::Unlink(tmp); |
63 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttrMap) |
64 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
65 | | |
66 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Attr) |
67 | 0 | Element* ownerElement = tmp->GetElement(); |
68 | 0 | if (tmp->HasKnownLiveWrapper()) { |
69 | 0 | if (ownerElement) { |
70 | 0 | // The attribute owns the element via attribute map so we can |
71 | 0 | // mark it when the attribute is certainly alive. |
72 | 0 | mozilla::dom::FragmentOrElement::MarkNodeChildren(ownerElement); |
73 | 0 | } |
74 | 0 | return true; |
75 | 0 | } |
76 | 0 | if (ownerElement && |
77 | 0 | mozilla::dom::FragmentOrElement::CanSkip(ownerElement, true)) { |
78 | 0 | return true; |
79 | 0 | } |
80 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END |
81 | 0 |
|
82 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Attr) |
83 | 0 | return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp); |
84 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END |
85 | | |
86 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Attr) |
87 | 0 | return tmp->HasKnownLiveWrapper(); |
88 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END |
89 | | |
90 | | // QueryInterface implementation for Attr |
91 | 0 | NS_INTERFACE_TABLE_HEAD(Attr) |
92 | 0 | NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY |
93 | 0 | NS_INTERFACE_TABLE(Attr, nsINode, EventTarget) |
94 | 0 | NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(Attr) |
95 | 0 | NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference, |
96 | 0 | new nsNodeSupportsWeakRefTearoff(this)) |
97 | 0 | NS_INTERFACE_MAP_END |
98 | | |
99 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(Attr) |
100 | | NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(Attr, |
101 | | nsNodeUtils::LastRelease(this)) |
102 | | |
103 | | void |
104 | | Attr::SetMap(nsDOMAttributeMap *aMap) |
105 | 0 | { |
106 | 0 | if (mAttrMap && !aMap && sInitialized) { |
107 | 0 | // We're breaking a relationship with content and not getting a new one, |
108 | 0 | // need to locally cache value. GetValue() does that. |
109 | 0 | GetValue(mValue); |
110 | 0 | } |
111 | 0 |
|
112 | 0 | mAttrMap = aMap; |
113 | 0 | } |
114 | | |
115 | | Element* |
116 | | Attr::GetElement() const |
117 | 0 | { |
118 | 0 | if (!mAttrMap) { |
119 | 0 | return nullptr; |
120 | 0 | } |
121 | 0 | nsIContent* content = mAttrMap->GetContent(); |
122 | 0 | return content ? content->AsElement() : nullptr; |
123 | 0 | } |
124 | | |
125 | | nsresult |
126 | | Attr::SetOwnerDocument(nsIDocument* aDocument) |
127 | 0 | { |
128 | 0 | NS_ASSERTION(aDocument, "Missing document"); |
129 | 0 |
|
130 | 0 | nsIDocument *doc = OwnerDoc(); |
131 | 0 | NS_ASSERTION(doc != aDocument, "bad call to Attr::SetOwnerDocument"); |
132 | 0 | doc->DeleteAllPropertiesFor(this); |
133 | 0 |
|
134 | 0 | RefPtr<dom::NodeInfo> newNodeInfo = |
135 | 0 | aDocument->NodeInfoManager()-> |
136 | 0 | GetNodeInfo(mNodeInfo->NameAtom(), mNodeInfo->GetPrefixAtom(), |
137 | 0 | mNodeInfo->NamespaceID(), ATTRIBUTE_NODE); |
138 | 0 | NS_ASSERTION(newNodeInfo, "GetNodeInfo lies"); |
139 | 0 | mNodeInfo.swap(newNodeInfo); |
140 | 0 |
|
141 | 0 | return NS_OK; |
142 | 0 | } |
143 | | |
144 | | void |
145 | | Attr::GetName(nsAString& aName) |
146 | 0 | { |
147 | 0 | aName = NodeName(); |
148 | 0 | } |
149 | | |
150 | | void |
151 | | Attr::GetValue(nsAString& aValue) |
152 | 0 | { |
153 | 0 | Element* element = GetElement(); |
154 | 0 | if (element) { |
155 | 0 | RefPtr<nsAtom> nameAtom = mNodeInfo->NameAtom(); |
156 | 0 | element->GetAttr(mNodeInfo->NamespaceID(), nameAtom, aValue); |
157 | 0 | } |
158 | 0 | else { |
159 | 0 | aValue = mValue; |
160 | 0 | } |
161 | 0 | } |
162 | | |
163 | | void |
164 | | Attr::SetValue(const nsAString& aValue, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aRv) |
165 | 0 | { |
166 | 0 | Element* element = GetElement(); |
167 | 0 | if (!element) { |
168 | 0 | mValue = aValue; |
169 | 0 | return; |
170 | 0 | } |
171 | 0 | |
172 | 0 | RefPtr<nsAtom> nameAtom = mNodeInfo->NameAtom(); |
173 | 0 | aRv = element->SetAttr(mNodeInfo->NamespaceID(), |
174 | 0 | nameAtom, |
175 | 0 | mNodeInfo->GetPrefixAtom(), |
176 | 0 | aValue, |
177 | 0 | aTriggeringPrincipal, |
178 | 0 | true); |
179 | 0 | } |
180 | | |
181 | | void |
182 | | Attr::SetValue(const nsAString& aValue, ErrorResult& aRv) |
183 | 0 | { |
184 | 0 | SetValue(aValue, nullptr, aRv); |
185 | 0 | } |
186 | | |
187 | | bool |
188 | | Attr::Specified() const |
189 | 0 | { |
190 | 0 | return true; |
191 | 0 | } |
192 | | |
193 | | Element* |
194 | | Attr::GetOwnerElement(ErrorResult& aRv) |
195 | 0 | { |
196 | 0 | return GetElement(); |
197 | 0 | } |
198 | | |
199 | | void |
200 | | Attr::GetNodeValueInternal(nsAString& aNodeValue) |
201 | 0 | { |
202 | 0 | GetValue(aNodeValue); |
203 | 0 | } |
204 | | |
205 | | void |
206 | | Attr::SetNodeValueInternal(const nsAString& aNodeValue, ErrorResult& aError) |
207 | 0 | { |
208 | 0 | SetValue(aNodeValue, nullptr, aError); |
209 | 0 | } |
210 | | |
211 | | nsresult |
212 | | Attr::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const |
213 | 0 | { |
214 | 0 | nsAutoString value; |
215 | 0 | const_cast<Attr*>(this)->GetValue(value); |
216 | 0 |
|
217 | 0 | *aResult = new Attr(nullptr, do_AddRef(aNodeInfo), value); |
218 | 0 | if (!*aResult) { |
219 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
220 | 0 | } |
221 | 0 | |
222 | 0 | NS_ADDREF(*aResult); |
223 | 0 |
|
224 | 0 | return NS_OK; |
225 | 0 | } |
226 | | |
227 | | already_AddRefed<nsIURI> |
228 | | Attr::GetBaseURI(bool aTryUseXHRDocBaseURI) const |
229 | 0 | { |
230 | 0 | Element* parent = GetElement(); |
231 | 0 |
|
232 | 0 | return parent ? parent->GetBaseURI(aTryUseXHRDocBaseURI) : nullptr; |
233 | 0 | } |
234 | | |
235 | | void |
236 | | Attr::GetTextContentInternal(nsAString& aTextContent, |
237 | | OOMReporter& aError) |
238 | 0 | { |
239 | 0 | GetValue(aTextContent); |
240 | 0 | } |
241 | | |
242 | | void |
243 | | Attr::SetTextContentInternal(const nsAString& aTextContent, |
244 | | nsIPrincipal* aSubjectPrincipal, |
245 | | ErrorResult& aError) |
246 | 0 | { |
247 | 0 | SetNodeValueInternal(aTextContent, aError); |
248 | 0 | } |
249 | | |
250 | | bool |
251 | | Attr::IsNodeOfType(uint32_t aFlags) const |
252 | 0 | { |
253 | 0 | return false; |
254 | 0 | } |
255 | | |
256 | | void |
257 | | Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor) |
258 | 0 | { |
259 | 0 | aVisitor.mCanHandle = true; |
260 | 0 | } |
261 | | |
262 | | void |
263 | | Attr::Initialize() |
264 | 3 | { |
265 | 3 | sInitialized = true; |
266 | 3 | } |
267 | | |
268 | | void |
269 | | Attr::Shutdown() |
270 | 0 | { |
271 | 0 | sInitialized = false; |
272 | 0 | } |
273 | | |
274 | | JSObject* |
275 | | Attr::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
276 | 0 | { |
277 | 0 | return Attr_Binding::Wrap(aCx, this, aGivenProto); |
278 | 0 | } |
279 | | |
280 | | void |
281 | | Attr::ConstructUbiNode(void* storage) |
282 | 0 | { |
283 | 0 | JS::ubi::Concrete<Attr>::construct(storage, this); |
284 | 0 | } |
285 | | |
286 | | } // namespace dom |
287 | | } // namespace mozilla |