content/base/src/nsNodeInfoManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsNodeInfoManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,429 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * A class for handing out nodeinfos and ensuring sharing of them as needed.
    1.12 + */
    1.13 +
    1.14 +#include "nsNodeInfoManager.h"
    1.15 +
    1.16 +#include "mozilla/DebugOnly.h"
    1.17 +#include "nsNodeInfo.h"
    1.18 +#include "nsCOMPtr.h"
    1.19 +#include "nsString.h"
    1.20 +#include "nsIAtom.h"
    1.21 +#include "nsIDocument.h"
    1.22 +#include "nsIPrincipal.h"
    1.23 +#include "nsIURI.h"
    1.24 +#include "nsContentUtils.h"
    1.25 +#include "nsReadableUtils.h"
    1.26 +#include "nsGkAtoms.h"
    1.27 +#include "nsComponentManagerUtils.h"
    1.28 +#include "nsLayoutStatics.h"
    1.29 +#include "nsBindingManager.h"
    1.30 +#include "nsHashKeys.h"
    1.31 +#include "nsCCUncollectableMarker.h"
    1.32 +
    1.33 +using namespace mozilla;
    1.34 +
    1.35 +#ifdef MOZ_LOGGING
    1.36 +// so we can get logging even in release builds
    1.37 +#define FORCE_PR_LOG 1
    1.38 +#endif
    1.39 +#include "prlog.h"
    1.40 +
    1.41 +#ifdef PR_LOGGING
    1.42 +static PRLogModuleInfo* gNodeInfoManagerLeakPRLog;
    1.43 +#endif
    1.44 +
    1.45 +PLHashNumber
    1.46 +nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key)
    1.47 +{
    1.48 +  NS_ASSERTION(key, "Null key passed to nsNodeInfo::GetHashValue!");
    1.49 +
    1.50 +  const nsINodeInfo::nsNodeInfoInner *node =
    1.51 +    reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key);
    1.52 +
    1.53 +  return node->mName ? node->mName->hash() : HashString(*(node->mNameString));
    1.54 +}
    1.55 +
    1.56 +
    1.57 +int
    1.58 +nsNodeInfoManager::NodeInfoInnerKeyCompare(const void *key1, const void *key2)
    1.59 +{
    1.60 +  NS_ASSERTION(key1 && key2, "Null key passed to NodeInfoInnerKeyCompare!");
    1.61 +
    1.62 +  const nsINodeInfo::nsNodeInfoInner *node1 =
    1.63 +    reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key1);
    1.64 +  const nsINodeInfo::nsNodeInfoInner *node2 =
    1.65 +    reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key2);
    1.66 +
    1.67 +  if (node1->mPrefix != node2->mPrefix ||
    1.68 +      node1->mNamespaceID != node2->mNamespaceID ||
    1.69 +      node1->mNodeType != node2->mNodeType ||
    1.70 +      node1->mExtraName != node2->mExtraName) {
    1.71 +    return 0;
    1.72 +  }
    1.73 +
    1.74 +  if (node1->mName) {
    1.75 +    if (node2->mName) {
    1.76 +      return (node1->mName == node2->mName);
    1.77 +    }
    1.78 +    return (node1->mName->Equals(*(node2->mNameString)));
    1.79 +  }
    1.80 +  if (node2->mName) {
    1.81 +    return (node2->mName->Equals(*(node1->mNameString)));
    1.82 +  }
    1.83 +  return (node1->mNameString->Equals(*(node2->mNameString)));
    1.84 +}
    1.85 +
    1.86 +
    1.87 +static void* PR_CALLBACK
    1.88 +AllocTable(void* pool, size_t size)
    1.89 +{
    1.90 +  return malloc(size);
    1.91 +}
    1.92 +
    1.93 +static void PR_CALLBACK
    1.94 +FreeTable(void* pool, void* item)
    1.95 +{
    1.96 +  free(item);
    1.97 +}
    1.98 +
    1.99 +static PLHashEntry* PR_CALLBACK
   1.100 +AllocEntry(void* pool, const void* key)
   1.101 +{
   1.102 +  return (PLHashEntry*)malloc(sizeof(PLHashEntry));
   1.103 +}
   1.104 +
   1.105 +static void PR_CALLBACK
   1.106 +FreeEntry(void* pool, PLHashEntry* he, unsigned flag)
   1.107 +{
   1.108 +  if (flag == HT_FREE_ENTRY) {
   1.109 +    free(he);
   1.110 +  }
   1.111 +}
   1.112 +
   1.113 +static PLHashAllocOps allocOps =
   1.114 +  { AllocTable, FreeTable, AllocEntry, FreeEntry };
   1.115 +
   1.116 +nsNodeInfoManager::nsNodeInfoManager()
   1.117 +  : mDocument(nullptr),
   1.118 +    mNonDocumentNodeInfos(0),
   1.119 +    mTextNodeInfo(nullptr),
   1.120 +    mCommentNodeInfo(nullptr),
   1.121 +    mDocumentNodeInfo(nullptr)
   1.122 +{
   1.123 +  nsLayoutStatics::AddRef();
   1.124 +
   1.125 +#ifdef PR_LOGGING
   1.126 +  if (!gNodeInfoManagerLeakPRLog)
   1.127 +    gNodeInfoManagerLeakPRLog = PR_NewLogModule("NodeInfoManagerLeak");
   1.128 +
   1.129 +  if (gNodeInfoManagerLeakPRLog)
   1.130 +    PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
   1.131 +           ("NODEINFOMANAGER %p created", this));
   1.132 +#endif
   1.133 +
   1.134 +  mNodeInfoHash = PL_NewHashTable(32, GetNodeInfoInnerHashValue,
   1.135 +                                  NodeInfoInnerKeyCompare,
   1.136 +                                  PL_CompareValues, &allocOps, nullptr);
   1.137 +}
   1.138 +
   1.139 +
   1.140 +nsNodeInfoManager::~nsNodeInfoManager()
   1.141 +{
   1.142 +  if (mNodeInfoHash)
   1.143 +    PL_HashTableDestroy(mNodeInfoHash);
   1.144 +
   1.145 +  // Note: mPrincipal may be null here if we never got inited correctly
   1.146 +  mPrincipal = nullptr;
   1.147 +
   1.148 +  mBindingManager = nullptr;
   1.149 +
   1.150 +#ifdef PR_LOGGING
   1.151 +  if (gNodeInfoManagerLeakPRLog)
   1.152 +    PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
   1.153 +           ("NODEINFOMANAGER %p destroyed", this));
   1.154 +#endif
   1.155 +
   1.156 +  nsLayoutStatics::Release();
   1.157 +}
   1.158 +
   1.159 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeInfoManager)
   1.160 +
   1.161 +NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsNodeInfoManager)
   1.162 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNodeInfoManager)
   1.163 +  if (tmp->mDocument &&
   1.164 +      nsCCUncollectableMarker::InGeneration(cb,
   1.165 +                                            tmp->mDocument->GetMarkedCCGeneration())) {
   1.166 +    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   1.167 +  }
   1.168 +  if (tmp->mNonDocumentNodeInfos) {
   1.169 +    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocument)
   1.170 +  }
   1.171 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBindingManager)
   1.172 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.173 +
   1.174 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsNodeInfoManager, AddRef)
   1.175 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsNodeInfoManager, Release)
   1.176 +
   1.177 +nsresult
   1.178 +nsNodeInfoManager::Init(nsIDocument *aDocument)
   1.179 +{
   1.180 +  NS_ENSURE_TRUE(mNodeInfoHash, NS_ERROR_OUT_OF_MEMORY);
   1.181 +
   1.182 +  NS_PRECONDITION(!mPrincipal,
   1.183 +                  "Being inited when we already have a principal?");
   1.184 +  nsresult rv;
   1.185 +  mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
   1.186 +  NS_ENSURE_TRUE(mPrincipal, rv);
   1.187 +
   1.188 +  if (aDocument) {
   1.189 +    mBindingManager = new nsBindingManager(aDocument);
   1.190 +  }
   1.191 +
   1.192 +  mDefaultPrincipal = mPrincipal;
   1.193 +
   1.194 +  mDocument = aDocument;
   1.195 +
   1.196 +#ifdef PR_LOGGING
   1.197 +  if (gNodeInfoManagerLeakPRLog)
   1.198 +    PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
   1.199 +           ("NODEINFOMANAGER %p Init document=%p", this, aDocument));
   1.200 +#endif
   1.201 +
   1.202 +  return NS_OK;
   1.203 +}
   1.204 +
   1.205 +// static
   1.206 +int
   1.207 +nsNodeInfoManager::DropNodeInfoDocument(PLHashEntry *he, int hashIndex, void *arg)
   1.208 +{
   1.209 +  static_cast<nsINodeInfo*>(he->value)->mDocument = nullptr;
   1.210 +  return HT_ENUMERATE_NEXT;
   1.211 +}
   1.212 +
   1.213 +void
   1.214 +nsNodeInfoManager::DropDocumentReference()
   1.215 +{
   1.216 +  if (mBindingManager) {
   1.217 +    mBindingManager->DropDocumentReference();
   1.218 +  }
   1.219 +
   1.220 +  // This is probably not needed anymore.
   1.221 +  PL_HashTableEnumerateEntries(mNodeInfoHash, DropNodeInfoDocument, nullptr);
   1.222 +
   1.223 +  NS_ASSERTION(!mNonDocumentNodeInfos, "Shouldn't have non-document nodeinfos!");
   1.224 +  mDocument = nullptr;
   1.225 +}
   1.226 +
   1.227 +
   1.228 +already_AddRefed<nsINodeInfo>
   1.229 +nsNodeInfoManager::GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix,
   1.230 +                               int32_t aNamespaceID, uint16_t aNodeType,
   1.231 +                               nsIAtom* aExtraName /* = nullptr */)
   1.232 +{
   1.233 +  CheckValidNodeInfo(aNodeType, aName, aNamespaceID, aExtraName);
   1.234 +
   1.235 +  nsINodeInfo::nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType,
   1.236 +                                      aExtraName);
   1.237 +
   1.238 +  void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey);
   1.239 +
   1.240 +  if (node) {
   1.241 +    nsCOMPtr<nsINodeInfo> nodeInfo = static_cast<nsINodeInfo*>(node);
   1.242 +
   1.243 +    return nodeInfo.forget();
   1.244 +  }
   1.245 +
   1.246 +  nsRefPtr<nsNodeInfo> newNodeInfo =
   1.247 +    new nsNodeInfo(aName, aPrefix, aNamespaceID, aNodeType, aExtraName, this);
   1.248 +
   1.249 +  DebugOnly<PLHashEntry*> he =
   1.250 +    PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo);
   1.251 +  MOZ_ASSERT(he, "PL_HashTableAdd() failed");
   1.252 +
   1.253 +  // Have to do the swap thing, because already_AddRefed<nsNodeInfo>
   1.254 +  // doesn't cast to already_AddRefed<nsINodeInfo>
   1.255 +  ++mNonDocumentNodeInfos;
   1.256 +  if (mNonDocumentNodeInfos == 1) {
   1.257 +    NS_IF_ADDREF(mDocument);
   1.258 +  }
   1.259 +
   1.260 +  return newNodeInfo.forget();
   1.261 +}
   1.262 +
   1.263 +
   1.264 +nsresult
   1.265 +nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix,
   1.266 +                               int32_t aNamespaceID, uint16_t aNodeType,
   1.267 +                               nsINodeInfo** aNodeInfo)
   1.268 +{
   1.269 +#ifdef DEBUG
   1.270 +  {
   1.271 +    nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
   1.272 +    CheckValidNodeInfo(aNodeType, nameAtom, aNamespaceID, nullptr);
   1.273 +  }
   1.274 +#endif
   1.275 +
   1.276 +  nsINodeInfo::nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType);
   1.277 +
   1.278 +  void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey);
   1.279 +
   1.280 +  if (node) {
   1.281 +    nsINodeInfo* nodeInfo = static_cast<nsINodeInfo *>(node);
   1.282 +
   1.283 +    NS_ADDREF(*aNodeInfo = nodeInfo);
   1.284 +
   1.285 +    return NS_OK;
   1.286 +  }
   1.287 +
   1.288 +  nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
   1.289 +  NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
   1.290 +
   1.291 +  nsRefPtr<nsNodeInfo> newNodeInfo =
   1.292 +    new nsNodeInfo(nameAtom, aPrefix, aNamespaceID, aNodeType, nullptr, this);
   1.293 +  NS_ENSURE_TRUE(newNodeInfo, NS_ERROR_OUT_OF_MEMORY);
   1.294 +
   1.295 +  PLHashEntry *he;
   1.296 +  he = PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo);
   1.297 +  NS_ENSURE_TRUE(he, NS_ERROR_FAILURE);
   1.298 +
   1.299 +  ++mNonDocumentNodeInfos;
   1.300 +  if (mNonDocumentNodeInfos == 1) {
   1.301 +    NS_IF_ADDREF(mDocument);
   1.302 +  }
   1.303 +
   1.304 +  newNodeInfo.forget(aNodeInfo);
   1.305 +
   1.306 +  return NS_OK;
   1.307 +}
   1.308 +
   1.309 +
   1.310 +nsresult
   1.311 +nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix,
   1.312 +                               const nsAString& aNamespaceURI,
   1.313 +                               uint16_t aNodeType,
   1.314 +                               nsINodeInfo** aNodeInfo)
   1.315 +{
   1.316 +  int32_t nsid = kNameSpaceID_None;
   1.317 +
   1.318 +  if (!aNamespaceURI.IsEmpty()) {
   1.319 +    nsresult rv = nsContentUtils::NameSpaceManager()->
   1.320 +      RegisterNameSpace(aNamespaceURI, nsid);
   1.321 +    NS_ENSURE_SUCCESS(rv, rv);
   1.322 +  }
   1.323 +
   1.324 +  return GetNodeInfo(aName, aPrefix, nsid, aNodeType, aNodeInfo);
   1.325 +}
   1.326 +
   1.327 +already_AddRefed<nsINodeInfo>
   1.328 +nsNodeInfoManager::GetTextNodeInfo()
   1.329 +{
   1.330 +  nsCOMPtr<nsINodeInfo> nodeInfo;
   1.331 +
   1.332 +  if (!mTextNodeInfo) {
   1.333 +    nodeInfo = GetNodeInfo(nsGkAtoms::textTagName, nullptr, kNameSpaceID_None,
   1.334 +                           nsIDOMNode::TEXT_NODE, nullptr);
   1.335 +    // Hold a weak ref; the nodeinfo will let us know when it goes away
   1.336 +    mTextNodeInfo = nodeInfo;
   1.337 +  } else {
   1.338 +    nodeInfo = mTextNodeInfo;
   1.339 +  }
   1.340 +
   1.341 +  return nodeInfo.forget();
   1.342 +}
   1.343 +
   1.344 +already_AddRefed<nsINodeInfo>
   1.345 +nsNodeInfoManager::GetCommentNodeInfo()
   1.346 +{
   1.347 +  nsCOMPtr<nsINodeInfo> nodeInfo;
   1.348 +
   1.349 +  if (!mCommentNodeInfo) {
   1.350 +    nodeInfo = GetNodeInfo(nsGkAtoms::commentTagName, nullptr,
   1.351 +                           kNameSpaceID_None, nsIDOMNode::COMMENT_NODE,
   1.352 +                           nullptr);
   1.353 +    // Hold a weak ref; the nodeinfo will let us know when it goes away
   1.354 +    mCommentNodeInfo = nodeInfo;
   1.355 +  }
   1.356 +  else {
   1.357 +    nodeInfo = mCommentNodeInfo;
   1.358 +  }
   1.359 +
   1.360 +  return nodeInfo.forget();
   1.361 +}
   1.362 +
   1.363 +already_AddRefed<nsINodeInfo>
   1.364 +nsNodeInfoManager::GetDocumentNodeInfo()
   1.365 +{
   1.366 +  nsCOMPtr<nsINodeInfo> nodeInfo;
   1.367 +
   1.368 +  if (!mDocumentNodeInfo) {
   1.369 +    NS_ASSERTION(mDocument, "Should have mDocument!");
   1.370 +    nodeInfo = GetNodeInfo(nsGkAtoms::documentNodeName, nullptr,
   1.371 +                           kNameSpaceID_None, nsIDOMNode::DOCUMENT_NODE,
   1.372 +                           nullptr);
   1.373 +    // Hold a weak ref; the nodeinfo will let us know when it goes away
   1.374 +    mDocumentNodeInfo = nodeInfo;
   1.375 +
   1.376 +    --mNonDocumentNodeInfos;
   1.377 +    if (!mNonDocumentNodeInfos) {
   1.378 +      mDocument->Release(); // Don't set mDocument to null!
   1.379 +    }
   1.380 +  }
   1.381 +  else {
   1.382 +    nodeInfo = mDocumentNodeInfo;
   1.383 +  }
   1.384 +
   1.385 +  return nodeInfo.forget();
   1.386 +}
   1.387 +
   1.388 +void
   1.389 +nsNodeInfoManager::SetDocumentPrincipal(nsIPrincipal *aPrincipal)
   1.390 +{
   1.391 +  mPrincipal = nullptr;
   1.392 +  if (!aPrincipal) {
   1.393 +    aPrincipal = mDefaultPrincipal;
   1.394 +  }
   1.395 +
   1.396 +  NS_ASSERTION(aPrincipal, "Must have principal by this point!");
   1.397 +
   1.398 +  mPrincipal = aPrincipal;
   1.399 +}
   1.400 +
   1.401 +void
   1.402 +nsNodeInfoManager::RemoveNodeInfo(nsNodeInfo *aNodeInfo)
   1.403 +{
   1.404 +  NS_PRECONDITION(aNodeInfo, "Trying to remove null nodeinfo from manager!");
   1.405 +
   1.406 +  if (aNodeInfo == mDocumentNodeInfo) {
   1.407 +    mDocumentNodeInfo = nullptr;
   1.408 +    mDocument = nullptr;
   1.409 +  } else {
   1.410 +    if (--mNonDocumentNodeInfos == 0) {
   1.411 +      if (mDocument) {
   1.412 +        // Note, whoever calls this method should keep NodeInfoManager alive,
   1.413 +        // even if mDocument gets deleted.
   1.414 +        mDocument->Release();
   1.415 +      }
   1.416 +    }
   1.417 +    // Drop weak reference if needed
   1.418 +    if (aNodeInfo == mTextNodeInfo) {
   1.419 +      mTextNodeInfo = nullptr;
   1.420 +    }
   1.421 +    else if (aNodeInfo == mCommentNodeInfo) {
   1.422 +      mCommentNodeInfo = nullptr;
   1.423 +    }
   1.424 +  }
   1.425 +
   1.426 +#ifdef DEBUG
   1.427 +  bool ret =
   1.428 +#endif
   1.429 +  PL_HashTableRemove(mNodeInfoHash, &aNodeInfo->mInner);
   1.430 +
   1.431 +  NS_POSTCONDITION(ret, "Can't find nsINodeInfo to remove!!!");
   1.432 +}

mercurial