content/base/src/nsNodeInfoManager.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*
michael@0 8 * A class for handing out nodeinfos and ensuring sharing of them as needed.
michael@0 9 */
michael@0 10
michael@0 11 #include "nsNodeInfoManager.h"
michael@0 12
michael@0 13 #include "mozilla/DebugOnly.h"
michael@0 14 #include "nsNodeInfo.h"
michael@0 15 #include "nsCOMPtr.h"
michael@0 16 #include "nsString.h"
michael@0 17 #include "nsIAtom.h"
michael@0 18 #include "nsIDocument.h"
michael@0 19 #include "nsIPrincipal.h"
michael@0 20 #include "nsIURI.h"
michael@0 21 #include "nsContentUtils.h"
michael@0 22 #include "nsReadableUtils.h"
michael@0 23 #include "nsGkAtoms.h"
michael@0 24 #include "nsComponentManagerUtils.h"
michael@0 25 #include "nsLayoutStatics.h"
michael@0 26 #include "nsBindingManager.h"
michael@0 27 #include "nsHashKeys.h"
michael@0 28 #include "nsCCUncollectableMarker.h"
michael@0 29
michael@0 30 using namespace mozilla;
michael@0 31
michael@0 32 #ifdef MOZ_LOGGING
michael@0 33 // so we can get logging even in release builds
michael@0 34 #define FORCE_PR_LOG 1
michael@0 35 #endif
michael@0 36 #include "prlog.h"
michael@0 37
michael@0 38 #ifdef PR_LOGGING
michael@0 39 static PRLogModuleInfo* gNodeInfoManagerLeakPRLog;
michael@0 40 #endif
michael@0 41
michael@0 42 PLHashNumber
michael@0 43 nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key)
michael@0 44 {
michael@0 45 NS_ASSERTION(key, "Null key passed to nsNodeInfo::GetHashValue!");
michael@0 46
michael@0 47 const nsINodeInfo::nsNodeInfoInner *node =
michael@0 48 reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key);
michael@0 49
michael@0 50 return node->mName ? node->mName->hash() : HashString(*(node->mNameString));
michael@0 51 }
michael@0 52
michael@0 53
michael@0 54 int
michael@0 55 nsNodeInfoManager::NodeInfoInnerKeyCompare(const void *key1, const void *key2)
michael@0 56 {
michael@0 57 NS_ASSERTION(key1 && key2, "Null key passed to NodeInfoInnerKeyCompare!");
michael@0 58
michael@0 59 const nsINodeInfo::nsNodeInfoInner *node1 =
michael@0 60 reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key1);
michael@0 61 const nsINodeInfo::nsNodeInfoInner *node2 =
michael@0 62 reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key2);
michael@0 63
michael@0 64 if (node1->mPrefix != node2->mPrefix ||
michael@0 65 node1->mNamespaceID != node2->mNamespaceID ||
michael@0 66 node1->mNodeType != node2->mNodeType ||
michael@0 67 node1->mExtraName != node2->mExtraName) {
michael@0 68 return 0;
michael@0 69 }
michael@0 70
michael@0 71 if (node1->mName) {
michael@0 72 if (node2->mName) {
michael@0 73 return (node1->mName == node2->mName);
michael@0 74 }
michael@0 75 return (node1->mName->Equals(*(node2->mNameString)));
michael@0 76 }
michael@0 77 if (node2->mName) {
michael@0 78 return (node2->mName->Equals(*(node1->mNameString)));
michael@0 79 }
michael@0 80 return (node1->mNameString->Equals(*(node2->mNameString)));
michael@0 81 }
michael@0 82
michael@0 83
michael@0 84 static void* PR_CALLBACK
michael@0 85 AllocTable(void* pool, size_t size)
michael@0 86 {
michael@0 87 return malloc(size);
michael@0 88 }
michael@0 89
michael@0 90 static void PR_CALLBACK
michael@0 91 FreeTable(void* pool, void* item)
michael@0 92 {
michael@0 93 free(item);
michael@0 94 }
michael@0 95
michael@0 96 static PLHashEntry* PR_CALLBACK
michael@0 97 AllocEntry(void* pool, const void* key)
michael@0 98 {
michael@0 99 return (PLHashEntry*)malloc(sizeof(PLHashEntry));
michael@0 100 }
michael@0 101
michael@0 102 static void PR_CALLBACK
michael@0 103 FreeEntry(void* pool, PLHashEntry* he, unsigned flag)
michael@0 104 {
michael@0 105 if (flag == HT_FREE_ENTRY) {
michael@0 106 free(he);
michael@0 107 }
michael@0 108 }
michael@0 109
michael@0 110 static PLHashAllocOps allocOps =
michael@0 111 { AllocTable, FreeTable, AllocEntry, FreeEntry };
michael@0 112
michael@0 113 nsNodeInfoManager::nsNodeInfoManager()
michael@0 114 : mDocument(nullptr),
michael@0 115 mNonDocumentNodeInfos(0),
michael@0 116 mTextNodeInfo(nullptr),
michael@0 117 mCommentNodeInfo(nullptr),
michael@0 118 mDocumentNodeInfo(nullptr)
michael@0 119 {
michael@0 120 nsLayoutStatics::AddRef();
michael@0 121
michael@0 122 #ifdef PR_LOGGING
michael@0 123 if (!gNodeInfoManagerLeakPRLog)
michael@0 124 gNodeInfoManagerLeakPRLog = PR_NewLogModule("NodeInfoManagerLeak");
michael@0 125
michael@0 126 if (gNodeInfoManagerLeakPRLog)
michael@0 127 PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
michael@0 128 ("NODEINFOMANAGER %p created", this));
michael@0 129 #endif
michael@0 130
michael@0 131 mNodeInfoHash = PL_NewHashTable(32, GetNodeInfoInnerHashValue,
michael@0 132 NodeInfoInnerKeyCompare,
michael@0 133 PL_CompareValues, &allocOps, nullptr);
michael@0 134 }
michael@0 135
michael@0 136
michael@0 137 nsNodeInfoManager::~nsNodeInfoManager()
michael@0 138 {
michael@0 139 if (mNodeInfoHash)
michael@0 140 PL_HashTableDestroy(mNodeInfoHash);
michael@0 141
michael@0 142 // Note: mPrincipal may be null here if we never got inited correctly
michael@0 143 mPrincipal = nullptr;
michael@0 144
michael@0 145 mBindingManager = nullptr;
michael@0 146
michael@0 147 #ifdef PR_LOGGING
michael@0 148 if (gNodeInfoManagerLeakPRLog)
michael@0 149 PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
michael@0 150 ("NODEINFOMANAGER %p destroyed", this));
michael@0 151 #endif
michael@0 152
michael@0 153 nsLayoutStatics::Release();
michael@0 154 }
michael@0 155
michael@0 156 NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeInfoManager)
michael@0 157
michael@0 158 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsNodeInfoManager)
michael@0 159 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNodeInfoManager)
michael@0 160 if (tmp->mDocument &&
michael@0 161 nsCCUncollectableMarker::InGeneration(cb,
michael@0 162 tmp->mDocument->GetMarkedCCGeneration())) {
michael@0 163 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
michael@0 164 }
michael@0 165 if (tmp->mNonDocumentNodeInfos) {
michael@0 166 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocument)
michael@0 167 }
michael@0 168 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBindingManager)
michael@0 169 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 170
michael@0 171 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsNodeInfoManager, AddRef)
michael@0 172 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsNodeInfoManager, Release)
michael@0 173
michael@0 174 nsresult
michael@0 175 nsNodeInfoManager::Init(nsIDocument *aDocument)
michael@0 176 {
michael@0 177 NS_ENSURE_TRUE(mNodeInfoHash, NS_ERROR_OUT_OF_MEMORY);
michael@0 178
michael@0 179 NS_PRECONDITION(!mPrincipal,
michael@0 180 "Being inited when we already have a principal?");
michael@0 181 nsresult rv;
michael@0 182 mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
michael@0 183 NS_ENSURE_TRUE(mPrincipal, rv);
michael@0 184
michael@0 185 if (aDocument) {
michael@0 186 mBindingManager = new nsBindingManager(aDocument);
michael@0 187 }
michael@0 188
michael@0 189 mDefaultPrincipal = mPrincipal;
michael@0 190
michael@0 191 mDocument = aDocument;
michael@0 192
michael@0 193 #ifdef PR_LOGGING
michael@0 194 if (gNodeInfoManagerLeakPRLog)
michael@0 195 PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
michael@0 196 ("NODEINFOMANAGER %p Init document=%p", this, aDocument));
michael@0 197 #endif
michael@0 198
michael@0 199 return NS_OK;
michael@0 200 }
michael@0 201
michael@0 202 // static
michael@0 203 int
michael@0 204 nsNodeInfoManager::DropNodeInfoDocument(PLHashEntry *he, int hashIndex, void *arg)
michael@0 205 {
michael@0 206 static_cast<nsINodeInfo*>(he->value)->mDocument = nullptr;
michael@0 207 return HT_ENUMERATE_NEXT;
michael@0 208 }
michael@0 209
michael@0 210 void
michael@0 211 nsNodeInfoManager::DropDocumentReference()
michael@0 212 {
michael@0 213 if (mBindingManager) {
michael@0 214 mBindingManager->DropDocumentReference();
michael@0 215 }
michael@0 216
michael@0 217 // This is probably not needed anymore.
michael@0 218 PL_HashTableEnumerateEntries(mNodeInfoHash, DropNodeInfoDocument, nullptr);
michael@0 219
michael@0 220 NS_ASSERTION(!mNonDocumentNodeInfos, "Shouldn't have non-document nodeinfos!");
michael@0 221 mDocument = nullptr;
michael@0 222 }
michael@0 223
michael@0 224
michael@0 225 already_AddRefed<nsINodeInfo>
michael@0 226 nsNodeInfoManager::GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix,
michael@0 227 int32_t aNamespaceID, uint16_t aNodeType,
michael@0 228 nsIAtom* aExtraName /* = nullptr */)
michael@0 229 {
michael@0 230 CheckValidNodeInfo(aNodeType, aName, aNamespaceID, aExtraName);
michael@0 231
michael@0 232 nsINodeInfo::nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType,
michael@0 233 aExtraName);
michael@0 234
michael@0 235 void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey);
michael@0 236
michael@0 237 if (node) {
michael@0 238 nsCOMPtr<nsINodeInfo> nodeInfo = static_cast<nsINodeInfo*>(node);
michael@0 239
michael@0 240 return nodeInfo.forget();
michael@0 241 }
michael@0 242
michael@0 243 nsRefPtr<nsNodeInfo> newNodeInfo =
michael@0 244 new nsNodeInfo(aName, aPrefix, aNamespaceID, aNodeType, aExtraName, this);
michael@0 245
michael@0 246 DebugOnly<PLHashEntry*> he =
michael@0 247 PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo);
michael@0 248 MOZ_ASSERT(he, "PL_HashTableAdd() failed");
michael@0 249
michael@0 250 // Have to do the swap thing, because already_AddRefed<nsNodeInfo>
michael@0 251 // doesn't cast to already_AddRefed<nsINodeInfo>
michael@0 252 ++mNonDocumentNodeInfos;
michael@0 253 if (mNonDocumentNodeInfos == 1) {
michael@0 254 NS_IF_ADDREF(mDocument);
michael@0 255 }
michael@0 256
michael@0 257 return newNodeInfo.forget();
michael@0 258 }
michael@0 259
michael@0 260
michael@0 261 nsresult
michael@0 262 nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix,
michael@0 263 int32_t aNamespaceID, uint16_t aNodeType,
michael@0 264 nsINodeInfo** aNodeInfo)
michael@0 265 {
michael@0 266 #ifdef DEBUG
michael@0 267 {
michael@0 268 nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
michael@0 269 CheckValidNodeInfo(aNodeType, nameAtom, aNamespaceID, nullptr);
michael@0 270 }
michael@0 271 #endif
michael@0 272
michael@0 273 nsINodeInfo::nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType);
michael@0 274
michael@0 275 void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey);
michael@0 276
michael@0 277 if (node) {
michael@0 278 nsINodeInfo* nodeInfo = static_cast<nsINodeInfo *>(node);
michael@0 279
michael@0 280 NS_ADDREF(*aNodeInfo = nodeInfo);
michael@0 281
michael@0 282 return NS_OK;
michael@0 283 }
michael@0 284
michael@0 285 nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
michael@0 286 NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
michael@0 287
michael@0 288 nsRefPtr<nsNodeInfo> newNodeInfo =
michael@0 289 new nsNodeInfo(nameAtom, aPrefix, aNamespaceID, aNodeType, nullptr, this);
michael@0 290 NS_ENSURE_TRUE(newNodeInfo, NS_ERROR_OUT_OF_MEMORY);
michael@0 291
michael@0 292 PLHashEntry *he;
michael@0 293 he = PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo);
michael@0 294 NS_ENSURE_TRUE(he, NS_ERROR_FAILURE);
michael@0 295
michael@0 296 ++mNonDocumentNodeInfos;
michael@0 297 if (mNonDocumentNodeInfos == 1) {
michael@0 298 NS_IF_ADDREF(mDocument);
michael@0 299 }
michael@0 300
michael@0 301 newNodeInfo.forget(aNodeInfo);
michael@0 302
michael@0 303 return NS_OK;
michael@0 304 }
michael@0 305
michael@0 306
michael@0 307 nsresult
michael@0 308 nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix,
michael@0 309 const nsAString& aNamespaceURI,
michael@0 310 uint16_t aNodeType,
michael@0 311 nsINodeInfo** aNodeInfo)
michael@0 312 {
michael@0 313 int32_t nsid = kNameSpaceID_None;
michael@0 314
michael@0 315 if (!aNamespaceURI.IsEmpty()) {
michael@0 316 nsresult rv = nsContentUtils::NameSpaceManager()->
michael@0 317 RegisterNameSpace(aNamespaceURI, nsid);
michael@0 318 NS_ENSURE_SUCCESS(rv, rv);
michael@0 319 }
michael@0 320
michael@0 321 return GetNodeInfo(aName, aPrefix, nsid, aNodeType, aNodeInfo);
michael@0 322 }
michael@0 323
michael@0 324 already_AddRefed<nsINodeInfo>
michael@0 325 nsNodeInfoManager::GetTextNodeInfo()
michael@0 326 {
michael@0 327 nsCOMPtr<nsINodeInfo> nodeInfo;
michael@0 328
michael@0 329 if (!mTextNodeInfo) {
michael@0 330 nodeInfo = GetNodeInfo(nsGkAtoms::textTagName, nullptr, kNameSpaceID_None,
michael@0 331 nsIDOMNode::TEXT_NODE, nullptr);
michael@0 332 // Hold a weak ref; the nodeinfo will let us know when it goes away
michael@0 333 mTextNodeInfo = nodeInfo;
michael@0 334 } else {
michael@0 335 nodeInfo = mTextNodeInfo;
michael@0 336 }
michael@0 337
michael@0 338 return nodeInfo.forget();
michael@0 339 }
michael@0 340
michael@0 341 already_AddRefed<nsINodeInfo>
michael@0 342 nsNodeInfoManager::GetCommentNodeInfo()
michael@0 343 {
michael@0 344 nsCOMPtr<nsINodeInfo> nodeInfo;
michael@0 345
michael@0 346 if (!mCommentNodeInfo) {
michael@0 347 nodeInfo = GetNodeInfo(nsGkAtoms::commentTagName, nullptr,
michael@0 348 kNameSpaceID_None, nsIDOMNode::COMMENT_NODE,
michael@0 349 nullptr);
michael@0 350 // Hold a weak ref; the nodeinfo will let us know when it goes away
michael@0 351 mCommentNodeInfo = nodeInfo;
michael@0 352 }
michael@0 353 else {
michael@0 354 nodeInfo = mCommentNodeInfo;
michael@0 355 }
michael@0 356
michael@0 357 return nodeInfo.forget();
michael@0 358 }
michael@0 359
michael@0 360 already_AddRefed<nsINodeInfo>
michael@0 361 nsNodeInfoManager::GetDocumentNodeInfo()
michael@0 362 {
michael@0 363 nsCOMPtr<nsINodeInfo> nodeInfo;
michael@0 364
michael@0 365 if (!mDocumentNodeInfo) {
michael@0 366 NS_ASSERTION(mDocument, "Should have mDocument!");
michael@0 367 nodeInfo = GetNodeInfo(nsGkAtoms::documentNodeName, nullptr,
michael@0 368 kNameSpaceID_None, nsIDOMNode::DOCUMENT_NODE,
michael@0 369 nullptr);
michael@0 370 // Hold a weak ref; the nodeinfo will let us know when it goes away
michael@0 371 mDocumentNodeInfo = nodeInfo;
michael@0 372
michael@0 373 --mNonDocumentNodeInfos;
michael@0 374 if (!mNonDocumentNodeInfos) {
michael@0 375 mDocument->Release(); // Don't set mDocument to null!
michael@0 376 }
michael@0 377 }
michael@0 378 else {
michael@0 379 nodeInfo = mDocumentNodeInfo;
michael@0 380 }
michael@0 381
michael@0 382 return nodeInfo.forget();
michael@0 383 }
michael@0 384
michael@0 385 void
michael@0 386 nsNodeInfoManager::SetDocumentPrincipal(nsIPrincipal *aPrincipal)
michael@0 387 {
michael@0 388 mPrincipal = nullptr;
michael@0 389 if (!aPrincipal) {
michael@0 390 aPrincipal = mDefaultPrincipal;
michael@0 391 }
michael@0 392
michael@0 393 NS_ASSERTION(aPrincipal, "Must have principal by this point!");
michael@0 394
michael@0 395 mPrincipal = aPrincipal;
michael@0 396 }
michael@0 397
michael@0 398 void
michael@0 399 nsNodeInfoManager::RemoveNodeInfo(nsNodeInfo *aNodeInfo)
michael@0 400 {
michael@0 401 NS_PRECONDITION(aNodeInfo, "Trying to remove null nodeinfo from manager!");
michael@0 402
michael@0 403 if (aNodeInfo == mDocumentNodeInfo) {
michael@0 404 mDocumentNodeInfo = nullptr;
michael@0 405 mDocument = nullptr;
michael@0 406 } else {
michael@0 407 if (--mNonDocumentNodeInfos == 0) {
michael@0 408 if (mDocument) {
michael@0 409 // Note, whoever calls this method should keep NodeInfoManager alive,
michael@0 410 // even if mDocument gets deleted.
michael@0 411 mDocument->Release();
michael@0 412 }
michael@0 413 }
michael@0 414 // Drop weak reference if needed
michael@0 415 if (aNodeInfo == mTextNodeInfo) {
michael@0 416 mTextNodeInfo = nullptr;
michael@0 417 }
michael@0 418 else if (aNodeInfo == mCommentNodeInfo) {
michael@0 419 mCommentNodeInfo = nullptr;
michael@0 420 }
michael@0 421 }
michael@0 422
michael@0 423 #ifdef DEBUG
michael@0 424 bool ret =
michael@0 425 #endif
michael@0 426 PL_HashTableRemove(mNodeInfoHash, &aNodeInfo->mInner);
michael@0 427
michael@0 428 NS_POSTCONDITION(ret, "Can't find nsINodeInfo to remove!!!");
michael@0 429 }

mercurial