NodeInfo.cpp (5801B)
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 15 #include "mozilla/Likely.h" 16 #include "mozilla/Sprintf.h" 17 #include "mozilla/dom/Document.h" 18 #include "mozilla/dom/NodeInfoInlines.h" 19 #include "nsAtom.h" 20 #include "nsCCUncollectableMarker.h" 21 #include "nsCOMPtr.h" 22 #include "nsCRT.h" 23 #include "nsContentUtils.h" 24 #include "nsDOMString.h" 25 #include "nsGkAtoms.h" 26 #include "nsINode.h" 27 #include "nsNameSpaceManager.h" 28 #include "nsNodeInfoManager.h" 29 #include "nsReadableUtils.h" 30 #include "nsString.h" 31 32 using namespace mozilla; 33 using mozilla::dom::NodeInfo; 34 35 NodeInfo::~NodeInfo() { 36 mOwnerManager->RemoveNodeInfo(this); 37 38 // We can't use NS_IF_RELEASE because mName is const. 39 if (mInner.mName) { 40 mInner.mName->Release(); 41 } 42 NS_IF_RELEASE(mInner.mPrefix); 43 NS_IF_RELEASE(mInner.mExtraName); 44 } 45 46 NodeInfo::NodeInfo(nsAtom* aName, nsAtom* aPrefix, int32_t aNamespaceID, 47 uint16_t aNodeType, nsAtom* aExtraName, 48 nsNodeInfoManager* aOwnerManager) 49 : mDocument(aOwnerManager->GetDocument()), 50 mInner(aName, aPrefix, aNamespaceID, aNodeType, aExtraName), 51 mOwnerManager(aOwnerManager) { 52 CheckValidNodeInfo(aNodeType, aName, aNamespaceID, aExtraName); 53 54 NS_IF_ADDREF(mInner.mName); 55 NS_IF_ADDREF(mInner.mPrefix); 56 NS_IF_ADDREF(mInner.mExtraName); 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 if (aPrefix) { 63 mQualifiedName = nsDependentAtomString(mInner.mPrefix) + u":"_ns + 64 nsDependentAtomString(mInner.mName); 65 } else { 66 mInner.mName->ToString(mQualifiedName); 67 } 68 69 MOZ_ASSERT_IF(aNodeType != nsINode::ELEMENT_NODE && 70 aNodeType != nsINode::ATTRIBUTE_NODE && 71 aNodeType != UINT16_MAX, 72 aNamespaceID == kNameSpaceID_None && !aPrefix); 73 74 switch (aNodeType) { 75 case nsINode::ELEMENT_NODE: 76 case nsINode::ATTRIBUTE_NODE: 77 // Correct the case for HTML 78 if (aNodeType == nsINode::ELEMENT_NODE && 79 aNamespaceID == kNameSpaceID_XHTML && GetDocument() && 80 GetDocument()->IsHTMLDocument()) { 81 nsContentUtils::ASCIIToUpper(mQualifiedName, mNodeName); 82 } else { 83 mNodeName = mQualifiedName; 84 } 85 mInner.mName->ToString(mLocalName); 86 break; 87 case nsINode::TEXT_NODE: 88 case nsINode::CDATA_SECTION_NODE: 89 case nsINode::COMMENT_NODE: 90 case nsINode::DOCUMENT_NODE: 91 case nsINode::DOCUMENT_FRAGMENT_NODE: 92 mInner.mName->ToString(mNodeName); 93 SetDOMStringToNull(mLocalName); 94 break; 95 case nsINode::PROCESSING_INSTRUCTION_NODE: 96 case nsINode::DOCUMENT_TYPE_NODE: 97 mInner.mExtraName->ToString(mNodeName); 98 SetDOMStringToNull(mLocalName); 99 break; 100 default: 101 MOZ_ASSERT(aNodeType == UINT16_MAX, "Unknown node type"); 102 } 103 } 104 105 // nsISupports 106 107 NS_IMPL_CYCLE_COLLECTION_CLASS(NodeInfo) 108 109 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(NodeInfo) 110 111 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(NodeInfo) 112 if (MOZ_UNLIKELY(cb.WantDebugInfo())) { 113 char name[72]; 114 uint32_t nsid = tmp->NamespaceID(); 115 nsAtomCString localName(tmp->NameAtom()); 116 const char* nsuri = nsNameSpaceManager::GetNameSpaceDisplayName(nsid); 117 SprintfLiteral(name, "NodeInfo %s %s", nsuri, localName.get()); 118 119 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name); 120 } else { 121 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(NodeInfo, tmp->mRefCnt.get()) 122 } 123 124 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwnerManager) 125 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 126 127 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(NodeInfo) 128 return nsCCUncollectableMarker::sGeneration && tmp->CanSkip(); 129 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END 130 131 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(NodeInfo) 132 return nsCCUncollectableMarker::sGeneration && tmp->CanSkip(); 133 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END 134 135 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(NodeInfo) 136 return nsCCUncollectableMarker::sGeneration && tmp->CanSkip(); 137 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 138 139 void NodeInfo::GetName(nsAString& aName) const { 140 mInner.mName->ToString(aName); 141 } 142 143 void NodeInfo::GetPrefix(nsAString& aPrefix) const { 144 if (mInner.mPrefix) { 145 mInner.mPrefix->ToString(aPrefix); 146 } else { 147 SetDOMStringToNull(aPrefix); 148 } 149 } 150 151 void NodeInfo::GetNamespaceURI(nsAString& aNameSpaceURI) const { 152 if (mInner.mNamespaceID > 0) { 153 nsresult rv = nsNameSpaceManager::GetInstance()->GetNameSpaceURI( 154 mInner.mNamespaceID, aNameSpaceURI); 155 // How can we possibly end up with a bogus namespace ID here? 156 if (NS_FAILED(rv)) { 157 MOZ_CRASH(); 158 } 159 } else { 160 SetDOMStringToNull(aNameSpaceURI); 161 } 162 } 163 164 bool NodeInfo::NamespaceEquals(const nsAString& aNamespaceURI) const { 165 int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID( 166 aNamespaceURI, nsContentUtils::IsChromeDoc(mOwnerManager->GetDocument())); 167 168 return mozilla::dom::NodeInfo::NamespaceEquals(nsid); 169 } 170 171 void NodeInfo::DeleteCycleCollectable() { 172 RefPtr<nsNodeInfoManager> kungFuDeathGrip = mOwnerManager; 173 (void)kungFuDeathGrip; // Just keeping value alive for longer than this 174 delete this; 175 } 176 177 bool NodeInfo::CanSkip() { 178 return mDocument && nsCCUncollectableMarker::InGeneration( 179 mDocument->GetMarkedCCGeneration()); 180 }