1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * Class that represents a prefix/namespace/localName triple; a single
40 : * nodeinfo is shared by all elements in a document that have that
41 : * prefix, namespace, and localName.
42 : */
43 :
44 : #include "mozilla/Util.h"
45 :
46 : #include "nscore.h"
47 : #include "nsNodeInfo.h"
48 : #include "nsNodeInfoManager.h"
49 : #include "nsCOMPtr.h"
50 : #include "nsString.h"
51 : #include "nsIAtom.h"
52 : #include "nsDOMString.h"
53 : #include "nsCRT.h"
54 : #include "nsContentUtils.h"
55 : #include "nsReadableUtils.h"
56 : #include "nsAutoPtr.h"
57 : #include NEW_H
58 : #include "nsFixedSizeAllocator.h"
59 : #include "prprf.h"
60 : #include "nsIDocument.h"
61 : #include "nsGkAtoms.h"
62 :
63 : using namespace mozilla;
64 :
65 : static const size_t kNodeInfoPoolSizes[] = {
66 : sizeof(nsNodeInfo)
67 : };
68 :
69 : static const PRInt32 kNodeInfoPoolInitialSize =
70 : (NS_SIZE_IN_HEAP(sizeof(nsNodeInfo))) * 64;
71 :
72 : // static
73 : nsFixedSizeAllocator* nsNodeInfo::sNodeInfoPool = nsnull;
74 :
75 : // static
76 : nsNodeInfo*
77 11993 : nsNodeInfo::Create(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID,
78 : PRUint16 aNodeType, nsIAtom *aExtraName,
79 : nsNodeInfoManager *aOwnerManager)
80 : {
81 11993 : if (!sNodeInfoPool) {
82 249 : sNodeInfoPool = new nsFixedSizeAllocator();
83 249 : if (!sNodeInfoPool)
84 0 : return nsnull;
85 :
86 : nsresult rv = sNodeInfoPool->Init("NodeInfo Pool", kNodeInfoPoolSizes,
87 249 : 1, kNodeInfoPoolInitialSize);
88 249 : if (NS_FAILED(rv)) {
89 0 : delete sNodeInfoPool;
90 0 : sNodeInfoPool = nsnull;
91 0 : return nsnull;
92 : }
93 : }
94 :
95 : // Create a new one
96 11993 : void* place = sNodeInfoPool->Alloc(sizeof(nsNodeInfo));
97 : return place ?
98 : new (place) nsNodeInfo(aName, aPrefix, aNamespaceID, aNodeType, aExtraName,
99 11993 : aOwnerManager) :
100 23986 : nsnull;
101 : }
102 :
103 23970 : nsNodeInfo::~nsNodeInfo()
104 : {
105 11985 : mOwnerManager->RemoveNodeInfo(this);
106 :
107 11985 : NS_RELEASE(mInner.mName);
108 11985 : NS_IF_RELEASE(mInner.mPrefix);
109 11985 : NS_IF_RELEASE(mInner.mExtraName);
110 11985 : NS_RELEASE(mOwnerManager);
111 23970 : }
112 :
113 :
114 11993 : nsNodeInfo::nsNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID,
115 : PRUint16 aNodeType, nsIAtom* aExtraName,
116 11993 : nsNodeInfoManager *aOwnerManager)
117 : {
118 11993 : CHECK_VALID_NODEINFO(aNodeType, aName, aNamespaceID, aExtraName);
119 11993 : NS_ABORT_IF_FALSE(aOwnerManager, "Invalid aOwnerManager");
120 :
121 : // Initialize mInner
122 11993 : NS_ADDREF(mInner.mName = aName);
123 11993 : NS_IF_ADDREF(mInner.mPrefix = aPrefix);
124 11993 : mInner.mNamespaceID = aNamespaceID;
125 11993 : mInner.mNodeType = aNodeType;
126 11993 : NS_ADDREF(mOwnerManager = aOwnerManager);
127 11993 : NS_IF_ADDREF(mInner.mExtraName = aExtraName);
128 :
129 11993 : mDocument = aOwnerManager->GetDocument();
130 :
131 : // Now compute our cached members.
132 :
133 : // Qualified name. If we have no prefix, use ToString on
134 : // mInner.mName so that we get to share its buffer.
135 11993 : if (aPrefix) {
136 2812 : mQualifiedName = nsDependentAtomString(mInner.mPrefix) +
137 5624 : NS_LITERAL_STRING(":") +
138 8436 : nsDependentAtomString(mInner.mName);
139 : } else {
140 9181 : mInner.mName->ToString(mQualifiedName);
141 : }
142 :
143 11993 : switch (aNodeType) {
144 : case nsIDOMNode::ELEMENT_NODE:
145 : case nsIDOMNode::ATTRIBUTE_NODE:
146 : // Correct the case for HTML
147 10922 : if (aNodeType == nsIDOMNode::ELEMENT_NODE &&
148 786 : aNamespaceID == kNameSpaceID_XHTML && GetDocument() &&
149 786 : GetDocument()->IsHTML()) {
150 775 : nsContentUtils::ASCIIToUpper(mQualifiedName, mNodeName);
151 : } else {
152 8575 : mNodeName = mQualifiedName;
153 : }
154 9350 : mInner.mName->ToString(mLocalName);
155 9350 : break;
156 : case nsIDOMNode::TEXT_NODE:
157 : case nsIDOMNode::CDATA_SECTION_NODE:
158 : case nsIDOMNode::COMMENT_NODE:
159 : case nsIDOMNode::DOCUMENT_NODE:
160 : case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
161 2533 : mInner.mName->ToString(mNodeName);
162 2533 : SetDOMStringToNull(mLocalName);
163 2533 : break;
164 : case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
165 : case nsIDOMNode::DOCUMENT_TYPE_NODE:
166 110 : mInner.mExtraName->ToString(mNodeName);
167 110 : SetDOMStringToNull(mLocalName);
168 110 : break;
169 : default:
170 0 : NS_ABORT_IF_FALSE(aNodeType == PR_UINT16_MAX,
171 : "Unknown node type");
172 : }
173 11993 : }
174 :
175 :
176 : // nsISupports
177 :
178 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeInfo)
179 11972 : NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsNodeInfo)
180 :
181 : static const char* kNSURIs[] = {
182 : " ([none])",
183 : " (xmlns)",
184 : " (xml)",
185 : " (xhtml)",
186 : " (XLink)",
187 : " (XSLT)",
188 : " (XBL)",
189 : " (MathML)",
190 : " (RDF)",
191 : " (XUL)"
192 : };
193 :
194 14219 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsNodeInfo)
195 14219 : if (NS_UNLIKELY(cb.WantDebugInfo())) {
196 : char name[72];
197 0 : PRUint32 nsid = tmp->NamespaceID();
198 0 : nsAtomCString localName(tmp->NameAtom());
199 0 : if (nsid < ArrayLength(kNSURIs)) {
200 : PR_snprintf(name, sizeof(name), "nsNodeInfo%s %s", kNSURIs[nsid],
201 0 : localName.get());
202 : }
203 : else {
204 0 : PR_snprintf(name, sizeof(name), "nsNodeInfo %s", localName.get());
205 : }
206 :
207 0 : cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsNodeInfo), name);
208 : }
209 : else {
210 14219 : NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsNodeInfo, tmp->mRefCnt.get())
211 : }
212 :
213 14219 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mOwnerManager,
214 : nsNodeInfoManager)
215 14219 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
216 :
217 437916 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeInfo)
218 437908 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsNodeInfo, LastRelease())
219 933568 : NS_INTERFACE_TABLE_HEAD(nsNodeInfo)
220 933568 : NS_INTERFACE_TABLE1(nsNodeInfo, nsINodeInfo)
221 933568 : NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsNodeInfo)
222 0 : NS_INTERFACE_MAP_END
223 :
224 : // nsINodeInfo
225 :
226 : nsresult
227 21464 : nsNodeInfo::GetNamespaceURI(nsAString& aNameSpaceURI) const
228 : {
229 21464 : nsresult rv = NS_OK;
230 :
231 21464 : if (mInner.mNamespaceID > 0) {
232 21325 : rv = nsContentUtils::NameSpaceManager()->GetNameSpaceURI(mInner.mNamespaceID,
233 21325 : aNameSpaceURI);
234 : } else {
235 139 : SetDOMStringToNull(aNameSpaceURI);
236 : }
237 :
238 21464 : return rv;
239 : }
240 :
241 :
242 : bool
243 0 : nsNodeInfo::NamespaceEquals(const nsAString& aNamespaceURI) const
244 : {
245 : PRInt32 nsid =
246 0 : nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
247 :
248 0 : return nsINodeInfo::NamespaceEquals(nsid);
249 : }
250 :
251 : // static
252 : void
253 1403 : nsNodeInfo::ClearCache()
254 : {
255 : // Clear our cache.
256 1403 : delete sNodeInfoPool;
257 1403 : sNodeInfoPool = nsnull;
258 1403 : }
259 :
260 : void
261 11985 : nsNodeInfo::LastRelease()
262 : {
263 23970 : nsRefPtr<nsNodeInfoManager> kungFuDeathGrip = mOwnerManager;
264 11985 : this->~nsNodeInfo();
265 :
266 : // The refcount balancing and destructor re-entrancy protection
267 : // code in Release() sets mRefCnt to 1 so we have to set it to 0
268 : // here to prevent leaks
269 11985 : mRefCnt = 0;
270 :
271 11985 : NS_ASSERTION(sNodeInfoPool, "No NodeInfoPool when deleting NodeInfo!!!");
272 11985 : sNodeInfoPool->Free(this, sizeof(nsNodeInfo));
273 16377 : }
|