LCOV - code coverage report
Current view: directory - content/base/src - nsNodeInfoManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 159 149 93.7 %
Date: 2012-06-02 Functions: 22 20 90.9 %

       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                 :  * A class for handing out nodeinfos and ensuring sharing of them as needed.
      40                 :  */
      41                 : 
      42                 : #include "nsNodeInfoManager.h"
      43                 : #include "nsNodeInfo.h"
      44                 : #include "nsCOMPtr.h"
      45                 : #include "nsString.h"
      46                 : #include "nsIAtom.h"
      47                 : #include "nsIDocument.h"
      48                 : #include "nsIPrincipal.h"
      49                 : #include "nsIURI.h"
      50                 : #include "nsContentUtils.h"
      51                 : #include "nsReadableUtils.h"
      52                 : #include "nsGkAtoms.h"
      53                 : #include "nsComponentManagerUtils.h"
      54                 : #include "nsLayoutStatics.h"
      55                 : #include "nsBindingManager.h"
      56                 : #include "nsHashKeys.h"
      57                 : #include "nsCCUncollectableMarker.h"
      58                 : 
      59                 : using namespace mozilla;
      60                 : 
      61                 : #ifdef MOZ_LOGGING
      62                 : // so we can get logging even in release builds
      63                 : #define FORCE_PR_LOG 1
      64                 : #endif
      65                 : #include "prlog.h"
      66                 : 
      67                 : #ifdef PR_LOGGING
      68                 : static PRLogModuleInfo* gNodeInfoManagerLeakPRLog;
      69                 : #endif
      70                 : 
      71                 : PLHashNumber
      72           67156 : nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key)
      73                 : {
      74           67156 :   NS_ASSERTION(key, "Null key passed to nsNodeInfo::GetHashValue!");
      75                 : 
      76                 :   const nsINodeInfo::nsNodeInfoInner *node =
      77           67156 :     reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key);
      78                 : 
      79           67156 :   if (node->mName) {
      80                 :     // Ideally, we'd return node->mName->hash() here.  But that doesn't work at
      81                 :     // the moment because node->mName->hash() is not the same as
      82                 :     // HashString(*(node->mNameString)).  See bug 732815.
      83           66949 :     return HashString(nsDependentAtomString(node->mName));
      84                 :   }
      85             207 :   return HashString(*(node->mNameString));
      86                 : }
      87                 : 
      88                 : 
      89                 : PRIntn
      90           44260 : nsNodeInfoManager::NodeInfoInnerKeyCompare(const void *key1, const void *key2)
      91                 : {
      92           44260 :   NS_ASSERTION(key1 && key2, "Null key passed to NodeInfoInnerKeyCompare!");
      93                 : 
      94                 :   const nsINodeInfo::nsNodeInfoInner *node1 =
      95           44260 :     reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key1);
      96                 :   const nsINodeInfo::nsNodeInfoInner *node2 =
      97           44260 :     reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key2);
      98                 : 
      99           44260 :   if (node1->mPrefix != node2->mPrefix ||
     100                 :       node1->mNamespaceID != node2->mNamespaceID ||
     101                 :       node1->mNodeType != node2->mNodeType ||
     102                 :       node1->mExtraName != node2->mExtraName) {
     103            1090 :     return 0;
     104                 :   }
     105                 : 
     106           43170 :   if (node1->mName) {
     107           43143 :     if (node2->mName) {
     108           43143 :       return (node1->mName == node2->mName);
     109                 :     }
     110               0 :     return (node1->mName->Equals(*(node2->mNameString)));
     111                 :   }
     112              27 :   if (node2->mName) {
     113              27 :     return (node2->mName->Equals(*(node1->mNameString)));
     114                 :   }
     115               0 :   return (node1->mNameString->Equals(*(node2->mNameString)));
     116                 : }
     117                 : 
     118                 : 
     119            1273 : nsNodeInfoManager::nsNodeInfoManager()
     120                 :   : mDocument(nsnull),
     121                 :     mNonDocumentNodeInfos(0),
     122                 :     mPrincipal(nsnull),
     123                 :     mTextNodeInfo(nsnull),
     124                 :     mCommentNodeInfo(nsnull),
     125                 :     mDocumentNodeInfo(nsnull),
     126            1273 :     mBindingManager(nsnull)
     127                 : {
     128            1273 :   nsLayoutStatics::AddRef();
     129                 : 
     130                 : #ifdef PR_LOGGING
     131            1273 :   if (!gNodeInfoManagerLeakPRLog)
     132             249 :     gNodeInfoManagerLeakPRLog = PR_NewLogModule("NodeInfoManagerLeak");
     133                 : 
     134            1273 :   if (gNodeInfoManagerLeakPRLog)
     135            1273 :     PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
     136                 :            ("NODEINFOMANAGER %p created", this));
     137                 : #endif
     138                 : 
     139                 :   mNodeInfoHash = PL_NewHashTable(32, GetNodeInfoInnerHashValue,
     140                 :                                   NodeInfoInnerKeyCompare,
     141            1273 :                                   PL_CompareValues, nsnull, nsnull);
     142            1273 : }
     143                 : 
     144                 : 
     145            2542 : nsNodeInfoManager::~nsNodeInfoManager()
     146                 : {
     147            1271 :   if (mNodeInfoHash)
     148            1271 :     PL_HashTableDestroy(mNodeInfoHash);
     149                 : 
     150                 :   // Note: mPrincipal may be null here if we never got inited correctly
     151            1271 :   NS_IF_RELEASE(mPrincipal);
     152                 : 
     153            1271 :   NS_IF_RELEASE(mBindingManager);
     154                 : 
     155                 : #ifdef PR_LOGGING
     156            1271 :   if (gNodeInfoManagerLeakPRLog)
     157            1271 :     PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
     158                 :            ("NODEINFOMANAGER %p destroyed", this));
     159                 : #endif
     160                 : 
     161            1271 :   nsLayoutStatics::Release();
     162            1271 : }
     163                 : 
     164                 : 
     165            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeInfoManager)
     166            1271 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsNodeInfoManager, AddRef)
     167            1271 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsNodeInfoManager, Release)
     168            1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsNodeInfoManager)
     169            1287 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsNodeInfoManager)
     170            2574 :   if (tmp->mDocument &&
     171                 :       nsCCUncollectableMarker::InGeneration(cb,
     172            1287 :                                             tmp->mDocument->GetMarkedCCGeneration())) {
     173               8 :     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
     174                 :   }
     175            1279 :   if (tmp->mNonDocumentNodeInfos) {
     176            1279 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocument)
     177                 :   }
     178            1279 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mBindingManager)
     179            1279 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     180                 : 
     181                 : nsresult
     182            1273 : nsNodeInfoManager::Init(nsIDocument *aDocument)
     183                 : {
     184            1273 :   NS_ENSURE_TRUE(mNodeInfoHash, NS_ERROR_OUT_OF_MEMORY);
     185                 : 
     186            1273 :   NS_PRECONDITION(!mPrincipal,
     187                 :                   "Being inited when we already have a principal?");
     188                 :   nsresult rv = CallCreateInstance("@mozilla.org/nullprincipal;1",
     189            1273 :                                    &mPrincipal);
     190            1273 :   NS_ENSURE_TRUE(mPrincipal, rv);
     191                 : 
     192            1273 :   if (aDocument) {
     193            1273 :     mBindingManager = new nsBindingManager(aDocument);
     194            1273 :     NS_ENSURE_TRUE(mBindingManager, NS_ERROR_OUT_OF_MEMORY);
     195                 : 
     196            1273 :     NS_ADDREF(mBindingManager);
     197                 :   }
     198                 : 
     199            1273 :   mDefaultPrincipal = mPrincipal;
     200                 : 
     201            1273 :   mDocument = aDocument;
     202                 : 
     203                 : #ifdef PR_LOGGING
     204            1273 :   if (gNodeInfoManagerLeakPRLog)
     205            1273 :     PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
     206                 :            ("NODEINFOMANAGER %p Init document=%p", this, aDocument));
     207                 : #endif
     208                 : 
     209            1273 :   return NS_OK;
     210                 : }
     211                 : 
     212                 : // static
     213                 : PRIntn
     214            2371 : nsNodeInfoManager::DropNodeInfoDocument(PLHashEntry *he, PRIntn hashIndex, void *arg)
     215                 : {
     216            2371 :   static_cast<nsINodeInfo*>(he->value)->mDocument = nsnull;
     217            2371 :   return HT_ENUMERATE_NEXT;
     218                 : }
     219                 : 
     220                 : void
     221            1271 : nsNodeInfoManager::DropDocumentReference()
     222                 : {
     223            1271 :   if (mBindingManager) {
     224            1271 :     mBindingManager->DropDocumentReference();
     225                 :   }
     226                 : 
     227                 :   // This is probably not needed anymore.
     228            1271 :   PL_HashTableEnumerateEntries(mNodeInfoHash, DropNodeInfoDocument, nsnull);
     229                 : 
     230            1271 :   NS_ASSERTION(!mNonDocumentNodeInfos, "Shouldn't have non-document nodeinfos!");
     231            1271 :   mDocument = nsnull;
     232            1271 : }
     233                 : 
     234                 : 
     235                 : already_AddRefed<nsINodeInfo>
     236           42971 : nsNodeInfoManager::GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix,
     237                 :                                PRInt32 aNamespaceID, PRUint16 aNodeType,
     238                 :                                nsIAtom* aExtraName /* = nsnull */)
     239                 : {
     240           42971 :   CHECK_VALID_NODEINFO(aNodeType, aName, aNamespaceID, aExtraName);
     241                 : 
     242                 :   nsINodeInfo::nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType,
     243           42971 :                                       aExtraName);
     244                 : 
     245           42971 :   void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey);
     246                 : 
     247           42971 :   if (node) {
     248           31158 :     nsINodeInfo* nodeInfo = static_cast<nsINodeInfo *>(node);
     249                 : 
     250           31158 :     NS_ADDREF(nodeInfo);
     251                 : 
     252           31158 :     return nodeInfo;
     253                 :   }
     254                 : 
     255                 :   nsRefPtr<nsNodeInfo> newNodeInfo =
     256                 :     nsNodeInfo::Create(aName, aPrefix, aNamespaceID, aNodeType, aExtraName,
     257           23626 :                        this);
     258           11813 :   NS_ENSURE_TRUE(newNodeInfo, nsnull);
     259                 :   
     260                 :   PLHashEntry *he;
     261           11813 :   he = PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo);
     262           11813 :   NS_ENSURE_TRUE(he, nsnull);
     263                 : 
     264                 :   // Have to do the swap thing, because already_AddRefed<nsNodeInfo>
     265                 :   // doesn't cast to already_AddRefed<nsINodeInfo>
     266           11813 :   ++mNonDocumentNodeInfos;
     267           11813 :   if (mNonDocumentNodeInfos == 1) {
     268            2545 :     NS_IF_ADDREF(mDocument);
     269                 :   }
     270                 : 
     271           11813 :   nsNodeInfo *nodeInfo = nsnull;
     272           11813 :   newNodeInfo.swap(nodeInfo);
     273                 : 
     274           11813 :   return nodeInfo;
     275                 : }
     276                 : 
     277                 : 
     278                 : nsresult
     279             207 : nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix,
     280                 :                                PRInt32 aNamespaceID, PRUint16 aNodeType,
     281                 :                                nsINodeInfo** aNodeInfo)
     282                 : {
     283                 : #ifdef DEBUG
     284                 :   {
     285             414 :     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
     286             207 :     CHECK_VALID_NODEINFO(aNodeType, nameAtom, aNamespaceID, nsnull);
     287                 :   }
     288                 : #endif
     289                 : 
     290             207 :   nsINodeInfo::nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType);
     291                 : 
     292             207 :   void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey);
     293                 : 
     294             207 :   if (node) {
     295              27 :     nsINodeInfo* nodeInfo = static_cast<nsINodeInfo *>(node);
     296                 : 
     297              27 :     NS_ADDREF(*aNodeInfo = nodeInfo);
     298                 : 
     299              27 :     return NS_OK;
     300                 :   }
     301                 : 
     302                 :   
     303             360 :   nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
     304             180 :   NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
     305                 : 
     306                 :   nsRefPtr<nsNodeInfo> newNodeInfo =
     307                 :       nsNodeInfo::Create(nameAtom, aPrefix, aNamespaceID, aNodeType, nsnull,
     308             360 :                          this);
     309             180 :   NS_ENSURE_TRUE(newNodeInfo, NS_ERROR_OUT_OF_MEMORY);
     310                 : 
     311                 :   PLHashEntry *he;
     312             180 :   he = PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo);
     313             180 :   NS_ENSURE_TRUE(he, NS_ERROR_FAILURE);
     314                 : 
     315             180 :   ++mNonDocumentNodeInfos;
     316             180 :   if (mNonDocumentNodeInfos == 1) {
     317               1 :     NS_IF_ADDREF(mDocument);
     318                 :   }
     319                 : 
     320             180 :   newNodeInfo.forget(aNodeInfo);
     321                 : 
     322             180 :   return NS_OK;
     323                 : }
     324                 : 
     325                 : 
     326                 : nsresult
     327               0 : nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix,
     328                 :                                const nsAString& aNamespaceURI,
     329                 :                                PRUint16 aNodeType,
     330                 :                                nsINodeInfo** aNodeInfo)
     331                 : {
     332               0 :   PRInt32 nsid = kNameSpaceID_None;
     333                 : 
     334               0 :   if (!aNamespaceURI.IsEmpty()) {
     335               0 :     nsresult rv = nsContentUtils::NameSpaceManager()->
     336               0 :       RegisterNameSpace(aNamespaceURI, nsid);
     337               0 :     NS_ENSURE_SUCCESS(rv, rv);
     338                 :   }
     339                 : 
     340               0 :   return GetNodeInfo(aName, aPrefix, nsid, aNodeType, aNodeInfo);
     341                 : }
     342                 : 
     343                 : already_AddRefed<nsINodeInfo>
     344           72639 : nsNodeInfoManager::GetTextNodeInfo()
     345                 : {
     346           72639 :   if (!mTextNodeInfo) {
     347                 :     mTextNodeInfo = GetNodeInfo(nsGkAtoms::textTagName, nsnull,
     348                 :                                 kNameSpaceID_None,
     349            1064 :                                 nsIDOMNode::TEXT_NODE, nsnull).get();
     350                 :   }
     351                 :   else {
     352           71575 :     NS_ADDREF(mTextNodeInfo);
     353                 :   }
     354                 : 
     355           72639 :   return mTextNodeInfo;
     356                 : }
     357                 : 
     358                 : already_AddRefed<nsINodeInfo>
     359            1638 : nsNodeInfoManager::GetCommentNodeInfo()
     360                 : {
     361            1638 :   if (!mCommentNodeInfo) {
     362                 :     mCommentNodeInfo = GetNodeInfo(nsGkAtoms::commentTagName, nsnull,
     363                 :                                    kNameSpaceID_None,
     364             186 :                                    nsIDOMNode::COMMENT_NODE, nsnull).get();
     365                 :   }
     366                 :   else {
     367            1452 :     NS_ADDREF(mCommentNodeInfo);
     368                 :   }
     369                 : 
     370            1638 :   return mCommentNodeInfo;
     371                 : }
     372                 : 
     373                 : already_AddRefed<nsINodeInfo>
     374            1273 : nsNodeInfoManager::GetDocumentNodeInfo()
     375                 : {
     376            1273 :   if (!mDocumentNodeInfo) {
     377            1273 :     NS_ASSERTION(mDocument, "Should have mDocument!");
     378                 :     mDocumentNodeInfo = GetNodeInfo(nsGkAtoms::documentNodeName, nsnull,
     379                 :                                     kNameSpaceID_None,
     380            1273 :                                     nsIDOMNode::DOCUMENT_NODE, nsnull).get();
     381            1273 :     --mNonDocumentNodeInfos;
     382            1273 :     if (!mNonDocumentNodeInfos) {
     383            1273 :       mDocument->Release(); // Don't set mDocument to null!
     384                 :     }
     385                 :   }
     386                 :   else {
     387               0 :     NS_ADDREF(mDocumentNodeInfo);
     388                 :   }
     389                 : 
     390            1273 :   return mDocumentNodeInfo;
     391                 : }
     392                 : 
     393                 : void
     394            3249 : nsNodeInfoManager::SetDocumentPrincipal(nsIPrincipal *aPrincipal)
     395                 : {
     396            3249 :   NS_RELEASE(mPrincipal);
     397            3249 :   if (!aPrincipal) {
     398             469 :     aPrincipal = mDefaultPrincipal;
     399                 :   }
     400                 : 
     401            3249 :   NS_ASSERTION(aPrincipal, "Must have principal by this point!");
     402                 :   
     403            3249 :   NS_ADDREF(mPrincipal = aPrincipal);
     404            3249 : }
     405                 : 
     406                 : void
     407           11985 : nsNodeInfoManager::RemoveNodeInfo(nsNodeInfo *aNodeInfo)
     408                 : {
     409           11985 :   NS_PRECONDITION(aNodeInfo, "Trying to remove null nodeinfo from manager!");
     410                 : 
     411           11985 :   if (aNodeInfo == mDocumentNodeInfo) {
     412            1271 :     mDocumentNodeInfo = nsnull;
     413            1271 :     mDocument = nsnull;
     414                 :   } else {
     415           10714 :     if (--mNonDocumentNodeInfos == 0) {
     416            1271 :       if (mDocument) {
     417                 :         // Note, whoever calls this method should keep NodeInfoManager alive,
     418                 :         // even if mDocument gets deleted.
     419            1271 :         mDocument->Release();
     420                 :       }
     421                 :     }
     422                 :     // Drop weak reference if needed
     423           10714 :     if (aNodeInfo == mTextNodeInfo) {
     424            1062 :       mTextNodeInfo = nsnull;
     425                 :     }
     426            9652 :     else if (aNodeInfo == mCommentNodeInfo) {
     427             186 :       mCommentNodeInfo = nsnull;
     428                 :     }
     429                 :   }
     430                 : 
     431                 : #ifdef DEBUG
     432                 :   bool ret =
     433                 : #endif
     434           11985 :   PL_HashTableRemove(mNodeInfoHash, &aNodeInfo->mInner);
     435                 : 
     436           11985 :   NS_POSTCONDITION(ret, "Can't find nsINodeInfo to remove!!!");
     437           16377 : }

Generated by: LCOV version 1.7