/src/mozilla-central/dom/base/NodeInfo.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 | | * Class that represents a prefix/namespace/localName triple; a single |
9 | | * nodeinfo is shared by all elements in a document that have that |
10 | | * prefix, namespace, and localName. |
11 | | */ |
12 | | |
13 | | #include "mozilla/dom/NodeInfo.h" |
14 | | #include "mozilla/dom/NodeInfoInlines.h" |
15 | | |
16 | | #include "mozilla/ArrayUtils.h" |
17 | | #include "mozilla/Likely.h" |
18 | | |
19 | | #include "nsNodeInfoManager.h" |
20 | | #include "nsCOMPtr.h" |
21 | | #include "nsString.h" |
22 | | #include "nsAtom.h" |
23 | | #include "nsDOMString.h" |
24 | | #include "nsCRT.h" |
25 | | #include "nsINode.h" |
26 | | #include "nsContentUtils.h" |
27 | | #include "nsReadableUtils.h" |
28 | | #include "mozilla/Sprintf.h" |
29 | | #include "nsIDocument.h" |
30 | | #include "nsGkAtoms.h" |
31 | | #include "nsCCUncollectableMarker.h" |
32 | | #include "nsNameSpaceManager.h" |
33 | | |
34 | | using namespace mozilla; |
35 | | using mozilla::dom::NodeInfo; |
36 | | |
37 | | NodeInfo::~NodeInfo() |
38 | 0 | { |
39 | 0 | mOwnerManager->RemoveNodeInfo(this); |
40 | 0 |
|
41 | 0 | // We can't use NS_IF_RELEASE because mName is const. |
42 | 0 | if (mInner.mName) { |
43 | 0 | mInner.mName->Release(); |
44 | 0 | } |
45 | 0 | NS_IF_RELEASE(mInner.mPrefix); |
46 | 0 | NS_IF_RELEASE(mInner.mExtraName); |
47 | 0 | } |
48 | | |
49 | | NodeInfo::NodeInfo(nsAtom *aName, nsAtom *aPrefix, int32_t aNamespaceID, |
50 | | uint16_t aNodeType, nsAtom* aExtraName, |
51 | | nsNodeInfoManager *aOwnerManager) |
52 | | : mDocument(aOwnerManager->GetDocument()), |
53 | | mInner(aName, aPrefix, aNamespaceID, aNodeType, aExtraName), |
54 | | mOwnerManager(aOwnerManager) |
55 | 0 | { |
56 | 0 | CheckValidNodeInfo(aNodeType, aName, aNamespaceID, aExtraName); |
57 | 0 |
|
58 | 0 | NS_IF_ADDREF(mInner.mName); |
59 | 0 | NS_IF_ADDREF(mInner.mPrefix); |
60 | 0 | NS_IF_ADDREF(mInner.mExtraName); |
61 | 0 |
|
62 | 0 | // Now compute our cached members. |
63 | 0 |
|
64 | 0 | // Qualified name. If we have no prefix, use ToString on |
65 | 0 | // mInner.mName so that we get to share its buffer. |
66 | 0 | if (aPrefix) { |
67 | 0 | mQualifiedName = nsDependentAtomString(mInner.mPrefix) + |
68 | 0 | NS_LITERAL_STRING(":") + |
69 | 0 | nsDependentAtomString(mInner.mName); |
70 | 0 | } else { |
71 | 0 | mInner.mName->ToString(mQualifiedName); |
72 | 0 | } |
73 | 0 |
|
74 | 0 | MOZ_ASSERT_IF(aNodeType != nsINode::ELEMENT_NODE && |
75 | 0 | aNodeType != nsINode::ATTRIBUTE_NODE && |
76 | 0 | aNodeType != UINT16_MAX, |
77 | 0 | aNamespaceID == kNameSpaceID_None && !aPrefix); |
78 | 0 |
|
79 | 0 | switch (aNodeType) { |
80 | 0 | case nsINode::ELEMENT_NODE: |
81 | 0 | case nsINode::ATTRIBUTE_NODE: |
82 | 0 | // Correct the case for HTML |
83 | 0 | if (aNodeType == nsINode::ELEMENT_NODE && |
84 | 0 | aNamespaceID == kNameSpaceID_XHTML && GetDocument() && |
85 | 0 | GetDocument()->IsHTMLDocument()) { |
86 | 0 | nsContentUtils::ASCIIToUpper(mQualifiedName, mNodeName); |
87 | 0 | } else { |
88 | 0 | mNodeName = mQualifiedName; |
89 | 0 | } |
90 | 0 | mInner.mName->ToString(mLocalName); |
91 | 0 | break; |
92 | 0 | case nsINode::TEXT_NODE: |
93 | 0 | case nsINode::CDATA_SECTION_NODE: |
94 | 0 | case nsINode::COMMENT_NODE: |
95 | 0 | case nsINode::DOCUMENT_NODE: |
96 | 0 | case nsINode::DOCUMENT_FRAGMENT_NODE: |
97 | 0 | mInner.mName->ToString(mNodeName); |
98 | 0 | SetDOMStringToNull(mLocalName); |
99 | 0 | break; |
100 | 0 | case nsINode::PROCESSING_INSTRUCTION_NODE: |
101 | 0 | case nsINode::DOCUMENT_TYPE_NODE: |
102 | 0 | mInner.mExtraName->ToString(mNodeName); |
103 | 0 | SetDOMStringToNull(mLocalName); |
104 | 0 | break; |
105 | 0 | default: |
106 | 0 | MOZ_ASSERT(aNodeType == UINT16_MAX, "Unknown node type"); |
107 | 0 | } |
108 | 0 | } |
109 | | |
110 | | |
111 | | // nsISupports |
112 | | |
113 | | NS_IMPL_CYCLE_COLLECTION_CLASS(NodeInfo) |
114 | | |
115 | | NS_IMPL_CYCLE_COLLECTION_UNLINK_0(NodeInfo) |
116 | | |
117 | | static const char* kNodeInfoNSURIs[] = { |
118 | | " ([none])", |
119 | | " (xmlns)", |
120 | | " (xml)", |
121 | | " (xhtml)", |
122 | | " (XLink)", |
123 | | " (XSLT)", |
124 | | " (XBL)", |
125 | | " (MathML)", |
126 | | " (RDF)", |
127 | | " (XUL)" |
128 | | }; |
129 | | |
130 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(NodeInfo) |
131 | 0 | if (MOZ_UNLIKELY(cb.WantDebugInfo())) { |
132 | 0 | char name[72]; |
133 | 0 | uint32_t nsid = tmp->NamespaceID(); |
134 | 0 | nsAtomCString localName(tmp->NameAtom()); |
135 | 0 | if (nsid < ArrayLength(kNodeInfoNSURIs)) { |
136 | 0 | SprintfLiteral(name, "NodeInfo%s %s", kNodeInfoNSURIs[nsid], |
137 | 0 | localName.get()); |
138 | 0 | } |
139 | 0 | else { |
140 | 0 | SprintfLiteral(name, "NodeInfo %s", localName.get()); |
141 | 0 | } |
142 | 0 |
|
143 | 0 | cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name); |
144 | 0 | } |
145 | 0 | else { |
146 | 0 | NS_IMPL_CYCLE_COLLECTION_DESCRIBE(NodeInfo, tmp->mRefCnt.get()) |
147 | 0 | } |
148 | 0 |
|
149 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwnerManager) |
150 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
151 | | |
152 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(NodeInfo) |
153 | 0 | return nsCCUncollectableMarker::sGeneration && tmp->CanSkip(); |
154 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END |
155 | | |
156 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(NodeInfo) |
157 | 0 | return nsCCUncollectableMarker::sGeneration && tmp->CanSkip(); |
158 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END |
159 | | |
160 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(NodeInfo) |
161 | 0 | return nsCCUncollectableMarker::sGeneration && tmp->CanSkip(); |
162 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END |
163 | | |
164 | | |
165 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NodeInfo, AddRef) |
166 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NodeInfo, Release) |
167 | | |
168 | | void |
169 | | NodeInfo::GetName(nsAString& aName) const |
170 | 0 | { |
171 | 0 | mInner.mName->ToString(aName); |
172 | 0 | } |
173 | | |
174 | | void |
175 | | NodeInfo::GetPrefix(nsAString& aPrefix) const |
176 | 0 | { |
177 | 0 | if (mInner.mPrefix) { |
178 | 0 | mInner.mPrefix->ToString(aPrefix); |
179 | 0 | } else { |
180 | 0 | SetDOMStringToNull(aPrefix); |
181 | 0 | } |
182 | 0 | } |
183 | | |
184 | | void |
185 | | NodeInfo::GetNamespaceURI(nsAString& aNameSpaceURI) const |
186 | 0 | { |
187 | 0 | if (mInner.mNamespaceID > 0) { |
188 | 0 | nsresult rv = |
189 | 0 | nsContentUtils::NameSpaceManager()->GetNameSpaceURI(mInner.mNamespaceID, |
190 | 0 | aNameSpaceURI); |
191 | 0 | // How can we possibly end up with a bogus namespace ID here? |
192 | 0 | if (NS_FAILED(rv)) { |
193 | 0 | MOZ_CRASH(); |
194 | 0 | } |
195 | 0 | } else { |
196 | 0 | SetDOMStringToNull(aNameSpaceURI); |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | bool |
201 | | NodeInfo::NamespaceEquals(const nsAString& aNamespaceURI) const |
202 | 0 | { |
203 | 0 | int32_t nsid = |
204 | 0 | nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, |
205 | 0 | nsContentUtils::IsChromeDoc(mOwnerManager->GetDocument())); |
206 | 0 |
|
207 | 0 | return mozilla::dom::NodeInfo::NamespaceEquals(nsid); |
208 | 0 | } |
209 | | |
210 | | void |
211 | | NodeInfo::DeleteCycleCollectable() |
212 | 0 | { |
213 | 0 | RefPtr<nsNodeInfoManager> kungFuDeathGrip = mOwnerManager; |
214 | 0 | mozilla::Unused << kungFuDeathGrip; // Just keeping value alive for longer than this |
215 | 0 | delete this; |
216 | 0 | } |
217 | | |
218 | | bool |
219 | | NodeInfo::CanSkip() |
220 | 0 | { |
221 | 0 | return mDocument && |
222 | 0 | nsCCUncollectableMarker::InGeneration(mDocument->GetMarkedCCGeneration()); |
223 | 0 | } |