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