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