LCOV - code coverage report
Current view: directory - content/xbl/src - nsBindingManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 763 91 11.9 %
Date: 2012-06-02 Functions: 111 21 18.9 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=79: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Original Author: David W. Hyatt (hyatt@netscape.com)
      25                 :  *   Alec Flett <alecf@netscape.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "nsCOMPtr.h"
      42                 : #include "nsIXBLService.h"
      43                 : #include "nsIInputStream.h"
      44                 : #include "nsIURI.h"
      45                 : #include "nsIURL.h"
      46                 : #include "nsIChannel.h"
      47                 : #include "nsXPIDLString.h"
      48                 : #include "nsIParser.h"
      49                 : #include "nsParserCIID.h"
      50                 : #include "nsNetUtil.h"
      51                 : #include "plstr.h"
      52                 : #include "nsIContent.h"
      53                 : #include "nsIDOMElement.h"
      54                 : #include "nsIDocument.h"
      55                 : #include "mozilla/FunctionTimer.h"
      56                 : #include "nsContentUtils.h"
      57                 : #include "nsIPresShell.h"
      58                 : #include "nsIXMLContentSink.h"
      59                 : #include "nsContentCID.h"
      60                 : #include "nsXMLDocument.h"
      61                 : #include "nsIStreamListener.h"
      62                 : 
      63                 : #include "nsXBLBinding.h"
      64                 : #include "nsXBLPrototypeBinding.h"
      65                 : #include "nsXBLDocumentInfo.h"
      66                 : #include "nsXBLInsertionPoint.h"
      67                 : 
      68                 : #include "nsIStyleRuleProcessor.h"
      69                 : #include "nsRuleProcessorData.h"
      70                 : #include "nsIWeakReference.h"
      71                 : 
      72                 : #include "jsapi.h"
      73                 : #include "nsIXPConnect.h"
      74                 : #include "nsDOMCID.h"
      75                 : #include "nsIDOMScriptObjectFactory.h"
      76                 : #include "nsIScriptGlobalObject.h"
      77                 : #include "nsTHashtable.h"
      78                 : 
      79                 : #include "nsIScriptContext.h"
      80                 : #include "nsBindingManager.h"
      81                 : 
      82                 : #include "nsThreadUtils.h"
      83                 : #include "dombindings.h"
      84                 : 
      85                 : // ==================================================================
      86                 : // = nsAnonymousContentList 
      87                 : // ==================================================================
      88                 : 
      89                 : #define NS_ANONYMOUS_CONTENT_LIST_IID \
      90                 :   { 0xbfb5d8e7, 0xf718, 0x4a46, \
      91                 :     { 0xb2, 0x2b, 0x22, 0x4a, 0x44, 0x4c, 0xb9, 0x77 } }
      92                 : 
      93                 : class nsAnonymousContentList : public nsINodeList
      94                 : {
      95                 : public:
      96                 :   nsAnonymousContentList(nsIContent *aContent, nsInsertionPointList* aElements);
      97                 :   virtual ~nsAnonymousContentList();
      98                 : 
      99               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     100            1464 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsAnonymousContentList)
     101                 :   // nsIDOMNodeList interface
     102                 :   NS_DECL_NSIDOMNODELIST
     103                 : 
     104                 :   // nsINodeList interface
     105                 :   virtual PRInt32 IndexOf(nsIContent* aContent);
     106               0 :   virtual nsINode *GetParentObject()
     107                 :   {
     108               0 :     return mContent;
     109                 :   }
     110                 : 
     111               0 :   PRInt32 GetInsertionPointCount() { return mElements->Length(); }
     112                 : 
     113               0 :   nsXBLInsertionPoint* GetInsertionPointAt(PRInt32 i) { return static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i)); }
     114                 :   void RemoveInsertionPointAt(PRInt32 i) { mElements->RemoveElementAt(i); }
     115                 : 
     116               0 :   virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
     117                 :                                bool *triedToWrap)
     118                 :   {
     119                 :     return mozilla::dom::binding::NodeList::create(cx, scope, this,
     120               0 :                                                    triedToWrap);
     121                 :   }
     122                 : 
     123                 :   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ANONYMOUS_CONTENT_LIST_IID)
     124                 : private:
     125                 :   nsCOMPtr<nsIContent> mContent;
     126                 :   nsInsertionPointList* mElements;
     127                 : };
     128                 : 
     129                 : NS_DEFINE_STATIC_IID_ACCESSOR(nsAnonymousContentList,
     130                 :                               NS_ANONYMOUS_CONTENT_LIST_IID)
     131                 : 
     132               0 : nsAnonymousContentList::nsAnonymousContentList(nsIContent *aContent,
     133                 :                                                nsInsertionPointList* aElements)
     134                 :   : mContent(aContent),
     135               0 :     mElements(aElements)
     136                 : {
     137               0 :   MOZ_COUNT_CTOR(nsAnonymousContentList);
     138                 : 
     139                 :   // We don't reference count our Anonymous reference (to avoid circular
     140                 :   // references). We'll be told when the Anonymous goes away.
     141               0 :   SetIsProxy();
     142               0 : }
     143                 : 
     144               0 : nsAnonymousContentList::~nsAnonymousContentList()
     145                 : {
     146               0 :   MOZ_COUNT_DTOR(nsAnonymousContentList);
     147               0 :   delete mElements;
     148               0 : }
     149                 : 
     150            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsAnonymousContentList)
     151                 : 
     152               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList)
     153               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList)
     154                 : 
     155               0 : NS_INTERFACE_TABLE_HEAD(nsAnonymousContentList)
     156               0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     157                 :   NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsAnonymousContentList)
     158                 :     NS_INTERFACE_TABLE_ENTRY(nsAnonymousContentList, nsINodeList)
     159                 :     NS_INTERFACE_TABLE_ENTRY(nsAnonymousContentList, nsIDOMNodeList)
     160                 :     NS_INTERFACE_TABLE_ENTRY(nsAnonymousContentList, nsAnonymousContentList)
     161               0 :   NS_OFFSET_AND_INTERFACE_TABLE_END
     162               0 :   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
     163               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList)
     164               0 :   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsAnonymousContentList)
     165               0 : NS_INTERFACE_MAP_END
     166                 : 
     167               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAnonymousContentList)
     168               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContent)
     169               0 :   tmp->mElements->Clear();
     170               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     171               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     172                 : 
     173               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAnonymousContentList)
     174               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContent)
     175                 :   {
     176               0 :     PRInt32 i, count = tmp->mElements->Length();
     177               0 :     for (i = 0; i < count; ++i) {
     178               0 :       NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mElements->ElementAt(i),
     179                 :                                                       nsXBLInsertionPoint);
     180                 :     }
     181                 :   }
     182               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
     183               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     184               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsAnonymousContentList)
     185               0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     186               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     187                 : 
     188                 : NS_IMETHODIMP
     189               0 : nsAnonymousContentList::GetLength(PRUint32* aLength)
     190                 : {
     191               0 :   NS_ASSERTION(aLength != nsnull, "null ptr");
     192               0 :   if (! aLength)
     193               0 :       return NS_ERROR_NULL_POINTER;
     194                 : 
     195               0 :   PRInt32 cnt = mElements->Length();
     196                 : 
     197               0 :   *aLength = 0;
     198               0 :   for (PRInt32 i = 0; i < cnt; i++)
     199               0 :     *aLength += static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i))->ChildCount();
     200                 : 
     201               0 :   return NS_OK;
     202                 : }
     203                 : 
     204                 : NS_IMETHODIMP    
     205               0 : nsAnonymousContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
     206                 : {
     207               0 :   nsINode* item = GetNodeAt(aIndex);
     208               0 :   if (!item)
     209               0 :     return NS_ERROR_FAILURE;
     210                 : 
     211               0 :   return CallQueryInterface(item, aReturn);    
     212                 : }
     213                 : 
     214                 : nsIContent*
     215               0 : nsAnonymousContentList::GetNodeAt(PRUint32 aIndex)
     216                 : {
     217               0 :   PRInt32 cnt = mElements->Length();
     218               0 :   PRUint32 pointCount = 0;
     219                 : 
     220               0 :   for (PRInt32 i = 0; i < cnt; i++) {
     221               0 :     aIndex -= pointCount;
     222                 :     
     223               0 :     nsXBLInsertionPoint* point = static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i));
     224               0 :     pointCount = point->ChildCount();
     225                 : 
     226               0 :     if (aIndex < pointCount) {
     227               0 :       return point->ChildAt(aIndex);
     228                 :     }
     229                 :   }
     230                 : 
     231               0 :   return nsnull;
     232                 : }
     233                 : 
     234                 : PRInt32
     235               0 : nsAnonymousContentList::IndexOf(nsIContent* aContent)
     236                 : {
     237               0 :   PRInt32 cnt = mElements->Length();
     238               0 :   PRInt32 lengthSoFar = 0;
     239                 : 
     240               0 :   for (PRInt32 i = 0; i < cnt; ++i) {
     241                 :     nsXBLInsertionPoint* point =
     242               0 :       static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i));
     243               0 :     PRInt32 idx = point->IndexOf(aContent);
     244               0 :     if (idx != -1) {
     245               0 :       return idx + lengthSoFar;
     246                 :     }
     247                 : 
     248               0 :     lengthSoFar += point->ChildCount();
     249                 :   }
     250                 : 
     251                 :   // Didn't find it anywhere
     252               0 :   return -1;
     253                 : }
     254                 : 
     255                 : //
     256                 : // Generic pldhash table stuff for mapping one nsISupports to another
     257                 : //
     258                 : // These values are never null - a null value implies that this
     259                 : // whole key should be removed (See SetOrRemoveObject)
     260                 : class ObjectEntry : public PLDHashEntryHdr
     261                 : {
     262                 : public:
     263                 : 
     264                 :   // note that these are allocated within the PLDHashTable, but we
     265                 :   // want to keep track of them anyway
     266               0 :   ObjectEntry() { MOZ_COUNT_CTOR(ObjectEntry); }
     267               0 :   ~ObjectEntry() { MOZ_COUNT_DTOR(ObjectEntry); }
     268                 :   
     269               0 :   nsISupports* GetValue() { return mValue; }
     270               0 :   nsISupports* GetKey() { return mKey; }
     271               0 :   void SetValue(nsISupports* aValue) { mValue = aValue; }
     272               0 :   void SetKey(nsISupports* aKey) { mKey = aKey; }
     273                 :   
     274                 : private:
     275                 :   nsCOMPtr<nsISupports> mKey;
     276                 :   nsCOMPtr<nsISupports> mValue;
     277                 : };
     278                 : 
     279                 : static void
     280               0 : ClearObjectEntry(PLDHashTable* table, PLDHashEntryHdr *entry)
     281                 : {
     282               0 :   ObjectEntry* objEntry = static_cast<ObjectEntry*>(entry);
     283               0 :   objEntry->~ObjectEntry();
     284               0 : }
     285                 : 
     286                 : static bool
     287               0 : InitObjectEntry(PLDHashTable* table, PLDHashEntryHdr* entry, const void* key)
     288                 : {
     289               0 :   new (entry) ObjectEntry;
     290               0 :   return true;
     291                 : }
     292                 :   
     293                 : 
     294                 : 
     295                 : static PLDHashTableOps ObjectTableOps = {
     296                 :   PL_DHashAllocTable,
     297                 :   PL_DHashFreeTable,
     298                 :   PL_DHashVoidPtrKeyStub,
     299                 :   PL_DHashMatchEntryStub,
     300                 :   PL_DHashMoveEntryStub,
     301                 :   ClearObjectEntry,
     302                 :   PL_DHashFinalizeStub,
     303                 :   InitObjectEntry
     304                 : };
     305                 : 
     306                 : // helper routine for adding a new entry
     307                 : static nsresult
     308               0 : AddObjectEntry(PLDHashTable& table, nsISupports* aKey, nsISupports* aValue)
     309                 : {
     310               0 :   NS_ASSERTION(aKey, "key must be non-null");
     311               0 :   if (!aKey) return NS_ERROR_INVALID_ARG;
     312                 :   
     313                 :   ObjectEntry *entry =
     314                 :     static_cast<ObjectEntry*>
     315               0 :                (PL_DHashTableOperate(&table, aKey, PL_DHASH_ADD));
     316                 : 
     317               0 :   if (!entry)
     318               0 :     return NS_ERROR_OUT_OF_MEMORY;
     319                 : 
     320                 :   // only add the key if the entry is new
     321               0 :   if (!entry->GetKey())
     322               0 :     entry->SetKey(aKey);
     323                 : 
     324                 :   // now attach the new entry - note that entry->mValue could possibly
     325                 :   // have a value already, this will release that.
     326               0 :   entry->SetValue(aValue);
     327                 :   
     328               0 :   return NS_OK;
     329                 : }
     330                 : 
     331                 : // helper routine for looking up an existing entry. Note that the
     332                 : // return result is NOT addreffed
     333                 : static nsISupports*
     334               0 : LookupObject(PLDHashTable& table, nsIContent* aKey)
     335                 : {
     336               0 :   if (aKey && aKey->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
     337                 :     ObjectEntry *entry =
     338                 :       static_cast<ObjectEntry*>
     339               0 :                  (PL_DHashTableOperate(&table, aKey, PL_DHASH_LOOKUP));
     340                 : 
     341               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry))
     342               0 :       return entry->GetValue();
     343                 :   }
     344                 : 
     345               0 :   return nsnull;
     346                 : }
     347                 : 
     348                 : inline void
     349               0 : RemoveObjectEntry(PLDHashTable& table, nsISupports* aKey)
     350                 : {
     351               0 :   PL_DHashTableOperate(&table, aKey, PL_DHASH_REMOVE);
     352               0 : }
     353                 : 
     354                 : static nsresult
     355               0 : SetOrRemoveObject(PLDHashTable& table, nsIContent* aKey, nsISupports* aValue)
     356                 : {
     357               0 :   if (aValue) {
     358                 :     // lazily create the table, but only when adding elements
     359               0 :     if (!table.ops &&
     360                 :         !PL_DHashTableInit(&table, &ObjectTableOps, nsnull,
     361               0 :                            sizeof(ObjectEntry), 16)) {
     362               0 :       table.ops = nsnull;
     363               0 :       return NS_ERROR_OUT_OF_MEMORY;
     364                 :     }
     365               0 :     aKey->SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
     366               0 :     return AddObjectEntry(table, aKey, aValue);
     367                 :   }
     368                 : 
     369                 :   // no value, so remove the key from the table
     370               0 :   if (table.ops) {
     371                 :     ObjectEntry* entry =
     372                 :       static_cast<ObjectEntry*>
     373               0 :         (PL_DHashTableOperate(&table, aKey, PL_DHASH_LOOKUP));
     374               0 :     if (entry && PL_DHASH_ENTRY_IS_BUSY(entry)) {
     375                 :       // Keep key and value alive while removing the entry.
     376               0 :       nsCOMPtr<nsISupports> key = entry->GetKey();
     377               0 :       nsCOMPtr<nsISupports> value = entry->GetValue();
     378               0 :       RemoveObjectEntry(table, aKey);
     379                 :     }
     380                 :   }
     381               0 :   return NS_OK;
     382                 : }
     383                 : 
     384                 : // Implementation /////////////////////////////////////////////////////////////////
     385                 : 
     386                 : // Static member variable initialization
     387                 : 
     388                 : // Implement our nsISupports methods
     389                 : 
     390            1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager)
     391            1271 :   tmp->mDestroyed = true;
     392                 : 
     393            1271 :   if (tmp->mBindingTable.IsInitialized())
     394               0 :     tmp->mBindingTable.Clear();
     395                 : 
     396            1271 :   if (tmp->mDocumentTable.IsInitialized())
     397               0 :     tmp->mDocumentTable.Clear();
     398                 : 
     399            1271 :   if (tmp->mLoadingDocTable.IsInitialized())
     400               0 :     tmp->mLoadingDocTable.Clear();
     401                 : 
     402            1271 :   if (tmp->mContentListTable.ops)
     403               0 :     PL_DHashTableFinish(&(tmp->mContentListTable));
     404            1271 :   tmp->mContentListTable.ops = nsnull;
     405                 : 
     406            1271 :   if (tmp->mAnonymousNodesTable.ops)
     407               0 :     PL_DHashTableFinish(&(tmp->mAnonymousNodesTable));
     408            1271 :   tmp->mAnonymousNodesTable.ops = nsnull;
     409                 : 
     410            1271 :   if (tmp->mInsertionParentTable.ops)
     411               0 :     PL_DHashTableFinish(&(tmp->mInsertionParentTable));
     412            1271 :   tmp->mInsertionParentTable.ops = nsnull;
     413                 : 
     414            1271 :   if (tmp->mWrapperTable.ops)
     415               0 :     PL_DHashTableFinish(&(tmp->mWrapperTable));
     416            1271 :   tmp->mWrapperTable.ops = nsnull;
     417                 : 
     418            1271 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mAttachedStack)
     419                 : 
     420            1271 :   if (tmp->mProcessAttachedQueueEvent) {
     421               0 :     tmp->mProcessAttachedQueueEvent->Revoke();
     422                 :   }
     423            1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     424                 : 
     425                 : 
     426                 : static PLDHashOperator
     427               0 : DocumentInfoHashtableTraverser(nsIURI* key,
     428                 :                                nsXBLDocumentInfo* di,
     429                 :                                void* userArg)
     430                 : {
     431                 :   nsCycleCollectionTraversalCallback *cb = 
     432               0 :     static_cast<nsCycleCollectionTraversalCallback*>(userArg);
     433               0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mDocumentTable value");
     434               0 :   cb->NoteXPCOMChild(static_cast<nsIScriptGlobalObjectOwner*>(di));
     435               0 :   return PL_DHASH_NEXT;
     436                 : }
     437                 : 
     438                 : static PLDHashOperator
     439               0 : LoadingDocHashtableTraverser(nsIURI* key,
     440                 :                              nsIStreamListener* sl,
     441                 :                              void* userArg)
     442                 : {
     443                 :   nsCycleCollectionTraversalCallback *cb = 
     444               0 :     static_cast<nsCycleCollectionTraversalCallback*>(userArg);
     445               0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mLoadingDocTable value");
     446               0 :   cb->NoteXPCOMChild(sl);
     447               0 :   return PL_DHASH_NEXT;
     448                 : }
     449                 : 
     450            1279 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager)
     451                 :   // The hashes keyed on nsIContent are traversed from the nsIContent itself.
     452            1279 :   if (tmp->mDocumentTable.IsInitialized())
     453               0 :       tmp->mDocumentTable.EnumerateRead(&DocumentInfoHashtableTraverser, &cb);
     454            1279 :   if (tmp->mLoadingDocTable.IsInitialized())
     455               0 :       tmp->mLoadingDocTable.EnumerateRead(&LoadingDocHashtableTraverser, &cb);
     456            1279 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mAttachedStack,
     457                 :                                                     nsXBLBinding)
     458                 :   // No need to traverse mProcessAttachedQueueEvent, since it'll just
     459                 :   // fire at some point or become revoke and drop its ref to us.
     460            1279 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     461                 : 
     462            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager)
     463                 : 
     464            6379 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsBindingManager)
     465               0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     466               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     467               0 : NS_INTERFACE_MAP_END
     468                 : 
     469            2544 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBindingManager)
     470            3813 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBindingManager)
     471                 : 
     472                 : // Constructors/Destructors
     473            1273 : nsBindingManager::nsBindingManager(nsIDocument* aDocument)
     474                 :   : mProcessingAttachedStack(false),
     475                 :     mDestroyed(false),
     476                 :     mAttachedStackSizeOnOutermost(0),
     477            1273 :     mDocument(aDocument)
     478                 : {
     479            1273 :   mContentListTable.ops = nsnull;
     480            1273 :   mAnonymousNodesTable.ops = nsnull;
     481            1273 :   mInsertionParentTable.ops = nsnull;
     482            1273 :   mWrapperTable.ops = nsnull;
     483            1273 : }
     484                 : 
     485            2542 : nsBindingManager::~nsBindingManager(void)
     486                 : {
     487            1271 :   mDestroyed = true;
     488                 : 
     489            1271 :   if (mContentListTable.ops)
     490               0 :     PL_DHashTableFinish(&mContentListTable);
     491            1271 :   if (mAnonymousNodesTable.ops)
     492               0 :     PL_DHashTableFinish(&mAnonymousNodesTable);
     493            1271 :   NS_ASSERTION(!mInsertionParentTable.ops || !mInsertionParentTable.entryCount,
     494                 :                "Insertion parent table isn't empty!");
     495            1271 :   if (mInsertionParentTable.ops)
     496               0 :     PL_DHashTableFinish(&mInsertionParentTable);
     497            1271 :   if (mWrapperTable.ops)
     498               0 :     PL_DHashTableFinish(&mWrapperTable);
     499            1271 : }
     500                 : 
     501                 : PLDHashOperator
     502               0 : RemoveInsertionParentCB(PLDHashTable* aTable, PLDHashEntryHdr* aEntry,
     503                 :                         PRUint32 aNumber, void* aArg)
     504                 : {
     505               0 :   return (static_cast<ObjectEntry*>(aEntry)->GetValue() ==
     506               0 :           static_cast<nsISupports*>(aArg)) ? PL_DHASH_REMOVE : PL_DHASH_NEXT;
     507                 : }
     508                 : 
     509                 : static void
     510               0 : RemoveInsertionParentForNodeList(nsIDOMNodeList* aList, nsIContent* aParent)
     511                 : {
     512               0 :   nsAnonymousContentList* list = nsnull;
     513               0 :   if (aList) {
     514               0 :     CallQueryInterface(aList, &list);
     515                 :   }
     516               0 :   if (list) {
     517               0 :     PRInt32 count = list->GetInsertionPointCount();
     518               0 :     for (PRInt32 i = 0; i < count; ++i) {
     519               0 :       nsRefPtr<nsXBLInsertionPoint> currPoint = list->GetInsertionPointAt(i);
     520               0 :       currPoint->UnbindDefaultContent();
     521                 : #ifdef DEBUG
     522               0 :       nsCOMPtr<nsIContent> parent = currPoint->GetInsertionParent();
     523               0 :       NS_ASSERTION(!parent || parent == aParent, "Wrong insertion parent!");
     524                 : #endif
     525               0 :       currPoint->ClearInsertionParent();
     526                 :     }
     527               0 :     NS_RELEASE(list);
     528                 :   }
     529               0 : }
     530                 : 
     531                 : void
     532               0 : nsBindingManager::RemoveInsertionParent(nsIContent* aParent)
     533                 : {
     534               0 :   RemoveInsertionParentForNodeList(GetContentListFor(aParent), aParent);
     535                 : 
     536               0 :   RemoveInsertionParentForNodeList(GetAnonymousNodesFor(aParent), aParent);
     537                 : 
     538               0 :   if (mInsertionParentTable.ops) {
     539                 :     PL_DHashTableEnumerate(&mInsertionParentTable, RemoveInsertionParentCB,
     540               0 :                            static_cast<nsISupports*>(aParent));
     541                 :   }
     542               0 : }
     543                 : 
     544                 : nsXBLBinding*
     545           39024 : nsBindingManager::GetBinding(nsIContent* aContent)
     546                 : {
     547           39024 :   if (aContent && aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) &&
     548               0 :       mBindingTable.IsInitialized()) {
     549               0 :     return mBindingTable.GetWeak(aContent);
     550                 :   }
     551                 : 
     552           39024 :   return nsnull;
     553                 : }
     554                 : 
     555                 : nsresult
     556               0 : nsBindingManager::SetBinding(nsIContent* aContent, nsXBLBinding* aBinding)
     557                 : {
     558               0 :   if (!mBindingTable.IsInitialized()) {
     559               0 :     if (!mBindingTable.Init())
     560               0 :       return NS_ERROR_OUT_OF_MEMORY;
     561                 :   }
     562                 : 
     563                 :   // After this point, aBinding will be the most-derived binding for aContent.
     564                 :   // If we already have a binding for aContent in our table, make sure to
     565                 :   // remove it from the attached stack.  Otherwise we might end up firing its
     566                 :   // constructor twice (if aBinding inherits from it) or firing its constructor
     567                 :   // after aContent has been deleted (if aBinding is null and the content node
     568                 :   // dies before we process mAttachedStack).
     569               0 :   nsRefPtr<nsXBLBinding> oldBinding = GetBinding(aContent);
     570               0 :   if (oldBinding) {
     571               0 :     if (aContent->HasFlag(NODE_IS_INSERTION_PARENT)) {
     572                 :       nsRefPtr<nsXBLBinding> parentBinding =
     573               0 :         GetBinding(aContent->GetBindingParent());
     574                 :       // Clear insertion parent only if we don't have a parent binding which
     575                 :       // marked content to be an insertion parent. See also ChangeDocumentFor().
     576               0 :       if (!parentBinding || !parentBinding->HasInsertionParent(aContent)) {
     577               0 :         RemoveInsertionParent(aContent);
     578               0 :         aContent->UnsetFlags(NODE_IS_INSERTION_PARENT);
     579                 :       }
     580                 :     }
     581                 :     // Don't remove items here as that could mess up an executing
     582                 :     // ProcessAttachedQueue
     583               0 :     PRUint32 index = mAttachedStack.IndexOf(oldBinding);
     584               0 :     if (index != mAttachedStack.NoIndex) {
     585               0 :       mAttachedStack[index] = nsnull;
     586                 :     }
     587                 :   }
     588                 :   
     589               0 :   bool result = true;
     590                 : 
     591               0 :   if (aBinding) {
     592               0 :     aContent->SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
     593               0 :     result = mBindingTable.Put(aContent, aBinding);
     594                 :   } else {
     595               0 :     mBindingTable.Remove(aContent);
     596                 : 
     597                 :     // The death of the bindings means the death of the JS wrapper,
     598                 :     // and the flushing of our explicit and anonymous insertion point
     599                 :     // lists.
     600               0 :     SetWrappedJS(aContent, nsnull);
     601               0 :     SetContentListFor(aContent, nsnull);
     602               0 :     SetAnonymousNodesFor(aContent, nsnull);
     603               0 :     if (oldBinding) {
     604               0 :       oldBinding->SetBoundElement(nsnull);
     605                 :     }
     606                 :   }
     607                 : 
     608               0 :   return result ? NS_OK : NS_ERROR_FAILURE;
     609                 : }
     610                 : 
     611                 : nsIContent*
     612            4605 : nsBindingManager::GetInsertionParent(nsIContent* aContent)
     613                 : { 
     614            4605 :   if (mInsertionParentTable.ops) {
     615                 :     return static_cast<nsIContent*>
     616               0 :                       (LookupObject(mInsertionParentTable, aContent));
     617                 :   }
     618                 : 
     619            4605 :   return nsnull;
     620                 : }
     621                 : 
     622                 : nsresult
     623               0 : nsBindingManager::SetInsertionParent(nsIContent* aContent, nsIContent* aParent)
     624                 : {
     625               0 :   NS_ASSERTION(!aParent || aParent->HasFlag(NODE_IS_INSERTION_PARENT),
     626                 :                "Insertion parent should have NODE_IS_INSERTION_PARENT flag!");
     627                 : 
     628               0 :   if (mDestroyed) {
     629               0 :     return NS_OK;
     630                 :   }
     631                 : 
     632               0 :   return SetOrRemoveObject(mInsertionParentTable, aContent, aParent);
     633                 : }
     634                 : 
     635                 : nsIXPConnectWrappedJS*
     636               0 : nsBindingManager::GetWrappedJS(nsIContent* aContent)
     637                 : { 
     638               0 :   if (mWrapperTable.ops) {
     639               0 :     return static_cast<nsIXPConnectWrappedJS*>(LookupObject(mWrapperTable, aContent));
     640                 :   }
     641                 : 
     642               0 :   return nsnull;
     643                 : }
     644                 : 
     645                 : nsresult
     646               0 : nsBindingManager::SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aWrappedJS)
     647                 : {
     648               0 :   if (mDestroyed) {
     649               0 :     return NS_OK;
     650                 :   }
     651                 : 
     652               0 :   return SetOrRemoveObject(mWrapperTable, aContent, aWrappedJS);
     653                 : }
     654                 : 
     655                 : void
     656               0 : nsBindingManager::RemovedFromDocumentInternal(nsIContent* aContent,
     657                 :                                               nsIDocument* aOldDocument)
     658                 : {
     659               0 :   NS_PRECONDITION(aOldDocument != nsnull, "no old document");
     660                 : 
     661               0 :   if (mDestroyed)
     662               0 :     return;
     663                 : 
     664                 :   // Hold a ref to the binding so it won't die when we remove it from our
     665                 :   // table.
     666               0 :   nsRefPtr<nsXBLBinding> binding = GetBinding(aContent);
     667               0 :   if (aContent->HasFlag(NODE_IS_INSERTION_PARENT)) {
     668               0 :     nsRefPtr<nsXBLBinding> parentBinding = GetBinding(aContent->GetBindingParent());
     669               0 :     if (parentBinding) {
     670               0 :       parentBinding->RemoveInsertionParent(aContent);
     671                 :       // Clear insertion parent only if we don't have a binding which
     672                 :       // marked content to be an insertion parent. See also SetBinding().
     673               0 :       if (!binding || !binding->HasInsertionParent(aContent)) {
     674               0 :         RemoveInsertionParent(aContent);
     675               0 :         aContent->UnsetFlags(NODE_IS_INSERTION_PARENT);
     676                 :       }
     677                 :     }
     678                 :   }
     679                 : 
     680               0 :   if (binding) {
     681               0 :     binding->PrototypeBinding()->BindingDetached(binding->GetBoundElement());
     682               0 :     binding->ChangeDocument(aOldDocument, nsnull);
     683               0 :     SetBinding(aContent, nsnull);
     684                 :   }
     685                 : 
     686                 :   // Clear out insertion parents and content lists.
     687               0 :   SetInsertionParent(aContent, nsnull);
     688               0 :   SetContentListFor(aContent, nsnull);
     689               0 :   SetAnonymousNodesFor(aContent, nsnull);
     690                 : }
     691                 : 
     692                 : nsIAtom*
     693               0 : nsBindingManager::ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID)
     694                 : {
     695               0 :   nsXBLBinding *binding = GetBinding(aContent);
     696                 :   
     697               0 :   if (binding) {
     698               0 :     nsIAtom* base = binding->GetBaseTag(aNameSpaceID);
     699                 : 
     700               0 :     if (base) {
     701               0 :       return base;
     702                 :     }
     703                 :   }
     704                 : 
     705               0 :   *aNameSpaceID = aContent->GetNameSpaceID();
     706               0 :   return aContent->Tag();
     707                 : }
     708                 : 
     709                 : nsresult
     710               0 : nsBindingManager::GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult)
     711                 : {
     712               0 :   NS_IF_ADDREF(*aResult = GetContentListFor(aContent));
     713               0 :   return NS_OK;
     714                 : }
     715                 : 
     716                 : nsINodeList*
     717               0 : nsBindingManager::GetContentListFor(nsIContent* aContent)
     718                 : { 
     719               0 :   nsINodeList* result = nsnull;
     720                 : 
     721               0 :   if (mContentListTable.ops) {
     722                 :     result = static_cast<nsAnonymousContentList*>
     723               0 :       (LookupObject(mContentListTable, aContent));
     724                 :   }
     725                 : 
     726               0 :   if (!result) {
     727               0 :     result = aContent->GetChildNodesList();
     728                 :   }
     729                 : 
     730               0 :   return result;
     731                 : }
     732                 : 
     733                 : nsresult
     734               0 : nsBindingManager::SetContentListFor(nsIContent* aContent,
     735                 :                                     nsInsertionPointList* aList)
     736                 : {
     737               0 :   if (mDestroyed) {
     738               0 :     return NS_OK;
     739                 :   }
     740                 : 
     741               0 :   nsAnonymousContentList* contentList = nsnull;
     742               0 :   if (aList) {
     743               0 :     contentList = new nsAnonymousContentList(aContent, aList);
     744               0 :     if (!contentList) {
     745               0 :       delete aList;
     746               0 :       return NS_ERROR_OUT_OF_MEMORY;
     747                 :     }
     748                 :   }
     749                 : 
     750               0 :   return SetOrRemoveObject(mContentListTable, aContent, contentList);
     751                 : }
     752                 : 
     753                 : bool
     754               0 : nsBindingManager::HasContentListFor(nsIContent* aContent)
     755                 : {
     756               0 :   return mContentListTable.ops && LookupObject(mContentListTable, aContent);
     757                 : }
     758                 : 
     759                 : nsINodeList*
     760               0 : nsBindingManager::GetAnonymousNodesInternal(nsIContent* aContent,
     761                 :                                             bool* aIsAnonymousContentList)
     762                 : { 
     763               0 :   nsINodeList* result = nsnull;
     764               0 :   if (mAnonymousNodesTable.ops) {
     765                 :     result = static_cast<nsAnonymousContentList*>
     766               0 :                         (LookupObject(mAnonymousNodesTable, aContent));
     767                 :   }
     768                 : 
     769               0 :   if (!result) {
     770               0 :     *aIsAnonymousContentList = false;
     771               0 :     nsXBLBinding *binding = GetBinding(aContent);
     772               0 :     if (binding) {
     773               0 :       result = binding->GetAnonymousNodes();
     774                 :     }
     775                 :   } else
     776               0 :     *aIsAnonymousContentList = true;
     777                 : 
     778               0 :   return result;
     779                 : }
     780                 : 
     781                 : nsresult
     782               0 : nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent,
     783                 :                                        nsIDOMNodeList** aResult)
     784                 : {
     785                 :   bool dummy;
     786               0 :   NS_IF_ADDREF(*aResult = GetAnonymousNodesInternal(aContent, &dummy));
     787               0 :   return NS_OK;
     788                 : }
     789                 : 
     790                 : nsINodeList*
     791               0 : nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent)
     792                 : {
     793                 :   bool dummy;
     794               0 :   return GetAnonymousNodesInternal(aContent, &dummy);
     795                 : }
     796                 : 
     797                 : nsresult
     798               0 : nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent,
     799                 :                                        nsInsertionPointList* aList)
     800                 : {
     801               0 :   if (mDestroyed) {
     802               0 :     return NS_OK;
     803                 :   }
     804                 : 
     805               0 :   nsAnonymousContentList* contentList = nsnull;
     806               0 :   if (aList) {
     807               0 :     contentList = new nsAnonymousContentList(aContent, aList);
     808               0 :     if (!contentList) {
     809               0 :       delete aList;
     810               0 :       return NS_ERROR_OUT_OF_MEMORY;
     811                 :     }
     812                 :   }
     813                 : 
     814               0 :   return SetOrRemoveObject(mAnonymousNodesTable, aContent, contentList);
     815                 : }
     816                 : 
     817                 : nsINodeList*
     818               0 : nsBindingManager::GetXBLChildNodesInternal(nsIContent* aContent,
     819                 :                                            bool* aIsAnonymousContentList)
     820                 : {
     821                 :   PRUint32 length;
     822                 : 
     823                 :   // Retrieve the anonymous content that we should build.
     824                 :   nsINodeList* result = GetAnonymousNodesInternal(aContent,
     825               0 :                                                   aIsAnonymousContentList);
     826               0 :   if (result) {
     827               0 :     result->GetLength(&length);
     828               0 :     if (length == 0)
     829               0 :       result = nsnull;
     830                 :   }
     831                 :     
     832                 :   // We may have an altered list of children from XBL insertion points.
     833                 :   // If we don't have any anonymous kids, we next check to see if we have 
     834                 :   // insertion points.
     835               0 :   if (!result) {
     836               0 :     if (mContentListTable.ops) {
     837                 :       result = static_cast<nsAnonymousContentList*>
     838               0 :                           (LookupObject(mContentListTable, aContent));
     839               0 :       *aIsAnonymousContentList = true;
     840                 :     }
     841                 :   }
     842                 : 
     843               0 :   return result;
     844                 : }
     845                 : 
     846                 : nsresult
     847               0 : nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
     848                 : {
     849               0 :   NS_IF_ADDREF(*aResult = GetXBLChildNodesFor(aContent));
     850               0 :   return NS_OK;
     851                 : }
     852                 : 
     853                 : nsINodeList*
     854               0 : nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent)
     855                 : {
     856                 :   bool dummy;
     857               0 :   return GetXBLChildNodesInternal(aContent, &dummy);
     858                 : }
     859                 : 
     860                 : nsIContent*
     861               0 : nsBindingManager::GetInsertionPoint(nsIContent* aParent,
     862                 :                                     const nsIContent* aChild,
     863                 :                                     PRUint32* aIndex)
     864                 : {
     865               0 :   nsXBLBinding *binding = GetBinding(aParent);
     866               0 :   return binding ? binding->GetInsertionPoint(aChild, aIndex) : nsnull;
     867                 : }
     868                 : 
     869                 : nsIContent*
     870               0 : nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent,
     871                 :                                           PRUint32* aIndex,
     872                 :                                           bool* aMultipleInsertionPoints)
     873                 : {
     874               0 :   nsXBLBinding *binding = GetBinding(aParent);
     875               0 :   if (binding)
     876               0 :     return binding->GetSingleInsertionPoint(aIndex, aMultipleInsertionPoints);
     877                 : 
     878               0 :   *aMultipleInsertionPoints = false;
     879               0 :   return nsnull;
     880                 : }
     881                 : 
     882                 : nsresult
     883               0 : nsBindingManager::AddLayeredBinding(nsIContent* aContent, nsIURI* aURL,
     884                 :                                     nsIPrincipal* aOriginPrincipal)
     885                 : {
     886                 :   // First we need to load our binding.
     887                 :   nsresult rv;
     888                 :   nsCOMPtr<nsIXBLService> xblService = 
     889               0 :            do_GetService("@mozilla.org/xbl;1", &rv);
     890               0 :   if (!xblService)
     891               0 :     return rv;
     892                 : 
     893                 :   // Load the bindings.
     894               0 :   nsRefPtr<nsXBLBinding> binding;
     895                 :   bool dummy;
     896               0 :   xblService->LoadBindings(aContent, aURL, aOriginPrincipal, true,
     897               0 :                            getter_AddRefs(binding), &dummy);
     898               0 :   if (binding) {
     899               0 :     AddToAttachedQueue(binding);
     900               0 :     ProcessAttachedQueue();
     901                 :   }
     902                 : 
     903               0 :   return NS_OK;
     904                 : }
     905                 : 
     906                 : nsresult
     907               0 : nsBindingManager::RemoveLayeredBinding(nsIContent* aContent, nsIURI* aURL)
     908                 : {
     909                 :   // Hold a ref to the binding so it won't die when we remove it from our table
     910               0 :   nsRefPtr<nsXBLBinding> binding = GetBinding(aContent);
     911                 :   
     912               0 :   if (!binding) {
     913               0 :     return NS_OK;
     914                 :   }
     915                 : 
     916                 :   // For now we can only handle removing a binding if it's the only one
     917               0 :   NS_ENSURE_FALSE(binding->GetBaseBinding(), NS_ERROR_FAILURE);
     918                 : 
     919                 :   // Make sure that the binding has the URI that is requested to be removed
     920               0 :   if (!binding->PrototypeBinding()->CompareBindingURI(aURL)) {
     921               0 :     return NS_OK;
     922                 :   }
     923                 : 
     924                 :   // Make sure it isn't a style binding
     925               0 :   if (binding->IsStyleBinding()) {
     926               0 :     return NS_OK;
     927                 :   }
     928                 : 
     929                 :   // Hold strong ref in case removing the binding tries to close the
     930                 :   // window or something.
     931                 :   // XXXbz should that be ownerdoc?  Wouldn't we need a ref to the
     932                 :   // currentdoc too?  What's the one that should be passed to
     933                 :   // ChangeDocument?
     934               0 :   nsCOMPtr<nsIDocument> doc = aContent->OwnerDoc();
     935                 :   
     936                 :   // Finally remove the binding...
     937                 :   // XXXbz this doesn't remove the implementation!  Should fix!  Until
     938                 :   // then we need the explicit UnhookEventHandlers here.
     939               0 :   binding->UnhookEventHandlers();
     940               0 :   binding->ChangeDocument(doc, nsnull);
     941               0 :   SetBinding(aContent, nsnull);
     942               0 :   binding->MarkForDeath();
     943                 :   
     944                 :   // ...and recreate its frames. We need to do this since the frames may have
     945                 :   // been removed and style may have changed due to the removal of the
     946                 :   // anonymous children.
     947                 :   // XXXbz this should be using the current doc (if any), not the owner doc.
     948               0 :   nsIPresShell *presShell = doc->GetShell();
     949               0 :   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
     950                 : 
     951               0 :   return presShell->RecreateFramesFor(aContent);;
     952                 : }
     953                 : 
     954                 : nsresult
     955               0 : nsBindingManager::LoadBindingDocument(nsIDocument* aBoundDoc,
     956                 :                                       nsIURI* aURL,
     957                 :                                       nsIPrincipal* aOriginPrincipal)
     958                 : {
     959               0 :   NS_PRECONDITION(aURL, "Must have a URI to load!");
     960                 :   
     961                 :   // First we need to load our binding.
     962                 :   nsresult rv;
     963                 :   nsCOMPtr<nsIXBLService> xblService = 
     964               0 :            do_GetService("@mozilla.org/xbl;1", &rv);
     965               0 :   if (!xblService)
     966               0 :     return rv;
     967                 : 
     968                 :   // Load the binding doc.
     969               0 :   nsRefPtr<nsXBLDocumentInfo> info;
     970               0 :   xblService->LoadBindingDocumentInfo(nsnull, aBoundDoc, aURL,
     971                 :                                       aOriginPrincipal, true,
     972               0 :                                       getter_AddRefs(info));
     973               0 :   if (!info)
     974               0 :     return NS_ERROR_FAILURE;
     975                 : 
     976               0 :   return NS_OK;
     977                 : }
     978                 : 
     979                 : nsresult
     980               0 : nsBindingManager::AddToAttachedQueue(nsXBLBinding* aBinding)
     981                 : {
     982               0 :   if (!mAttachedStack.AppendElement(aBinding))
     983               0 :     return NS_ERROR_OUT_OF_MEMORY;
     984                 : 
     985                 :   // If we're in the middle of processing our queue already, don't
     986                 :   // bother posting the event.
     987               0 :   if (!mProcessingAttachedStack && !mProcessAttachedQueueEvent) {
     988               0 :     PostProcessAttachedQueueEvent();
     989                 :   }
     990                 : 
     991                 :   // Make sure that flushes will flush out the new items as needed.
     992               0 :   mDocument->SetNeedStyleFlush();
     993                 : 
     994               0 :   return NS_OK;
     995                 : 
     996                 : }
     997                 : 
     998                 : void
     999               0 : nsBindingManager::PostProcessAttachedQueueEvent()
    1000                 : {
    1001                 :   mProcessAttachedQueueEvent =
    1002               0 :     NS_NewRunnableMethod(this, &nsBindingManager::DoProcessAttachedQueue);
    1003               0 :   nsresult rv = NS_DispatchToCurrentThread(mProcessAttachedQueueEvent);
    1004               0 :   if (NS_SUCCEEDED(rv) && mDocument) {
    1005               0 :     mDocument->BlockOnload();
    1006                 :   }
    1007               0 : }
    1008                 : 
    1009                 : void
    1010               0 : nsBindingManager::DoProcessAttachedQueue()
    1011                 : {
    1012               0 :   if (!mProcessingAttachedStack) {
    1013               0 :     ProcessAttachedQueue();
    1014                 : 
    1015               0 :     NS_ASSERTION(mAttachedStack.Length() == 0,
    1016                 :                "Shouldn't have pending bindings!");
    1017                 :   
    1018               0 :     mProcessAttachedQueueEvent = nsnull;
    1019                 :   } else {
    1020                 :     // Someone's doing event processing from inside a constructor.
    1021                 :     // They're evil, but we'll fight back!  Just poll on them being
    1022                 :     // done and repost the attached queue event.
    1023               0 :     PostProcessAttachedQueueEvent();
    1024                 :   }
    1025                 : 
    1026                 :   // No matter what, unblock onload for the event that's fired.
    1027               0 :   if (mDocument) {
    1028                 :     // Hold a strong reference while calling UnblockOnload since that might
    1029                 :     // run script.
    1030               0 :     nsCOMPtr<nsIDocument> doc = mDocument;
    1031               0 :     doc->UnblockOnload(true);
    1032                 :   }
    1033               0 : }
    1034                 : 
    1035                 : void
    1036            4890 : nsBindingManager::ProcessAttachedQueue(PRUint32 aSkipSize)
    1037                 : {
    1038            4890 :   if (mProcessingAttachedStack || mAttachedStack.Length() <= aSkipSize)
    1039            4890 :     return;
    1040                 : 
    1041                 :   NS_TIME_FUNCTION;
    1042                 : 
    1043               0 :   mProcessingAttachedStack = true;
    1044                 : 
    1045                 :   // Excute constructors. Do this from high index to low
    1046               0 :   while (mAttachedStack.Length() > aSkipSize) {
    1047               0 :     PRUint32 lastItem = mAttachedStack.Length() - 1;
    1048               0 :     nsRefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(lastItem);
    1049               0 :     mAttachedStack.RemoveElementAt(lastItem);
    1050               0 :     if (binding) {
    1051               0 :       binding->ExecuteAttachedHandler();
    1052                 :     }
    1053                 :   }
    1054                 : 
    1055                 :   // If NodeWillBeDestroyed has run we don't want to clobber
    1056                 :   // mProcessingAttachedStack set there.
    1057               0 :   if (mDocument) {
    1058               0 :     mProcessingAttachedStack = false;
    1059                 :   }
    1060                 : 
    1061               0 :   NS_ASSERTION(mAttachedStack.Length() == aSkipSize, "How did we get here?");
    1062                 :   
    1063               0 :   mAttachedStack.Compact();
    1064                 : }
    1065                 : 
    1066                 : // Keep bindings and bound elements alive while executing detached handlers.
    1067                 : struct BindingTableReadClosure
    1068               0 : {
    1069                 :   nsCOMArray<nsIContent> mBoundElements;
    1070                 :   nsBindingList          mBindings;
    1071                 : };
    1072                 : 
    1073                 : static PLDHashOperator
    1074               0 : AccumulateBindingsToDetach(nsISupports *aKey, nsXBLBinding *aBinding,
    1075                 :                            void* aClosure)
    1076                 :  {
    1077                 :   BindingTableReadClosure* closure =
    1078               0 :     static_cast<BindingTableReadClosure*>(aClosure);
    1079               0 :   if (aBinding && closure->mBindings.AppendElement(aBinding)) {
    1080               0 :     if (!closure->mBoundElements.AppendObject(aBinding->GetBoundElement())) {
    1081               0 :       closure->mBindings.RemoveElementAt(closure->mBindings.Length() - 1);
    1082                 :     }
    1083                 :   }
    1084               0 :   return PL_DHASH_NEXT;
    1085                 : }
    1086                 : 
    1087                 : void
    1088               0 : nsBindingManager::ExecuteDetachedHandlers()
    1089                 : {
    1090                 :   // Walk our hashtable of bindings.
    1091               0 :   if (mBindingTable.IsInitialized()) {
    1092               0 :     BindingTableReadClosure closure;
    1093               0 :     mBindingTable.EnumerateRead(AccumulateBindingsToDetach, &closure);
    1094               0 :     PRUint32 i, count = closure.mBindings.Length();
    1095               0 :     for (i = 0; i < count; ++i) {
    1096               0 :       closure.mBindings[i]->ExecuteDetachedHandler();
    1097                 :     }
    1098                 :   }
    1099               0 : }
    1100                 : 
    1101                 : nsresult
    1102               0 : nsBindingManager::PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo)
    1103                 : {
    1104               0 :   NS_PRECONDITION(aDocumentInfo, "Must have a non-null documentinfo!");
    1105                 :   
    1106               0 :   NS_ENSURE_TRUE(mDocumentTable.IsInitialized() || mDocumentTable.Init(16),
    1107                 :                  NS_ERROR_OUT_OF_MEMORY);
    1108                 : 
    1109               0 :   NS_ENSURE_TRUE(mDocumentTable.Put(aDocumentInfo->DocumentURI(),
    1110                 :                                     aDocumentInfo),
    1111                 :                  NS_ERROR_OUT_OF_MEMORY);
    1112                 : 
    1113               0 :   return NS_OK;
    1114                 : }
    1115                 : 
    1116                 : void
    1117               0 : nsBindingManager::RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo)
    1118                 : {
    1119               0 :   if (mDocumentTable.IsInitialized()) {
    1120               0 :     mDocumentTable.Remove(aDocumentInfo->DocumentURI());
    1121                 :   }
    1122               0 : }
    1123                 : 
    1124                 : nsXBLDocumentInfo*
    1125               0 : nsBindingManager::GetXBLDocumentInfo(nsIURI* aURL)
    1126                 : {
    1127               0 :   if (!mDocumentTable.IsInitialized())
    1128               0 :     return nsnull;
    1129                 : 
    1130               0 :   return mDocumentTable.GetWeak(aURL);
    1131                 : }
    1132                 : 
    1133                 : nsresult
    1134               0 : nsBindingManager::PutLoadingDocListener(nsIURI* aURL, nsIStreamListener* aListener)
    1135                 : {
    1136               0 :   NS_PRECONDITION(aListener, "Must have a non-null listener!");
    1137                 :   
    1138               0 :   NS_ENSURE_TRUE(mLoadingDocTable.IsInitialized() || mLoadingDocTable.Init(16),
    1139                 :                  NS_ERROR_OUT_OF_MEMORY);
    1140                 :   
    1141               0 :   NS_ENSURE_TRUE(mLoadingDocTable.Put(aURL, aListener),
    1142                 :                  NS_ERROR_OUT_OF_MEMORY);
    1143                 : 
    1144               0 :   return NS_OK;
    1145                 : }
    1146                 : 
    1147                 : nsIStreamListener*
    1148               0 : nsBindingManager::GetLoadingDocListener(nsIURI* aURL)
    1149                 : {
    1150               0 :   if (!mLoadingDocTable.IsInitialized())
    1151               0 :     return nsnull;
    1152                 : 
    1153               0 :   return mLoadingDocTable.GetWeak(aURL);
    1154                 : }
    1155                 : 
    1156                 : void
    1157               0 : nsBindingManager::RemoveLoadingDocListener(nsIURI* aURL)
    1158                 : {
    1159               0 :   if (mLoadingDocTable.IsInitialized()) {
    1160               0 :     mLoadingDocTable.Remove(aURL);
    1161                 :   }
    1162               0 : }
    1163                 : 
    1164                 : static PLDHashOperator
    1165               0 : MarkForDeath(nsISupports *aKey, nsXBLBinding *aBinding, void* aClosure)
    1166                 : {
    1167               0 :   if (aBinding->MarkedForDeath())
    1168               0 :     return PL_DHASH_NEXT; // Already marked for death.
    1169                 : 
    1170               0 :   nsCAutoString path;
    1171               0 :   aBinding->PrototypeBinding()->DocURI()->GetPath(path);
    1172                 : 
    1173               0 :   if (!strncmp(path.get(), "/skin", 5))
    1174               0 :     aBinding->MarkForDeath();
    1175                 :   
    1176               0 :   return PL_DHASH_NEXT;
    1177                 : }
    1178                 : 
    1179                 : void
    1180               0 : nsBindingManager::FlushSkinBindings()
    1181                 : {
    1182               0 :   if (mBindingTable.IsInitialized())
    1183               0 :     mBindingTable.EnumerateRead(MarkForDeath, nsnull);
    1184               0 : }
    1185                 : 
    1186                 : // Used below to protect from recurring in QI calls through XPConnect.
    1187                 : struct AntiRecursionData {
    1188                 :   nsIContent* element; 
    1189                 :   REFNSIID iid; 
    1190                 :   AntiRecursionData* next;
    1191                 : 
    1192               0 :   AntiRecursionData(nsIContent* aElement, 
    1193                 :                     REFNSIID aIID, 
    1194                 :                     AntiRecursionData* aNext)
    1195               0 :     : element(aElement), iid(aIID), next(aNext) {}
    1196                 : };
    1197                 : 
    1198                 : nsresult
    1199             993 : nsBindingManager::GetBindingImplementation(nsIContent* aContent, REFNSIID aIID,
    1200                 :                                            void** aResult)
    1201                 : {
    1202             993 :   *aResult = nsnull;
    1203             993 :   nsXBLBinding *binding = GetBinding(aContent);
    1204             993 :   if (binding) {
    1205                 :     // The binding should not be asked for nsISupports
    1206               0 :     NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)), "Asking a binding for nsISupports");
    1207               0 :     if (binding->ImplementsInterface(aIID)) {
    1208               0 :       nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = GetWrappedJS(aContent);
    1209                 : 
    1210               0 :       if (wrappedJS) {
    1211                 :         // Protect from recurring in QI calls through XPConnect. 
    1212                 :         // This can happen when a second binding is being resolved.
    1213                 :         // At that point a wrappedJS exists, but it doesn't yet know about
    1214                 :         // the iid we are asking for. So, without this protection, 
    1215                 :         // AggregatedQueryInterface would end up recurring back into itself
    1216                 :         // through this code. 
    1217                 :         //
    1218                 :         // With this protection, when we detect the recursion we return 
    1219                 :         // NS_NOINTERFACE in the inner call. The outer call will then fall 
    1220                 :         // through (see below) and build a new chained wrappedJS for the iid.
    1221                 :         //
    1222                 :         // We're careful to not assume that only one direct nesting can occur
    1223                 :         // because there is a call into JS in the middle and we can't assume 
    1224                 :         // that this code won't be reached by some more complex nesting path.
    1225                 :         //
    1226                 :         // NOTE: We *assume* this is single threaded, so we can use a
    1227                 :         // static linked list to do the check.
    1228                 : 
    1229                 :         static AntiRecursionData* list = nsnull;
    1230                 : 
    1231               0 :         for (AntiRecursionData* p = list; p; p = p->next) {
    1232               0 :           if (p->element == aContent && p->iid.Equals(aIID)) {
    1233               0 :             *aResult = nsnull;
    1234               0 :             return NS_NOINTERFACE;
    1235                 :           }
    1236                 :         }
    1237                 : 
    1238               0 :         AntiRecursionData item(aContent, aIID, list);
    1239               0 :         list = &item;
    1240                 : 
    1241               0 :         nsresult rv = wrappedJS->AggregatedQueryInterface(aIID, aResult);
    1242                 :         
    1243               0 :         list = item.next;
    1244                 :         
    1245               0 :         if (*aResult)
    1246               0 :           return rv;
    1247                 :         
    1248                 :         // No result was found, so this must be another XBL interface.
    1249                 :         // Fall through to create a new wrapper.
    1250                 :       }
    1251                 : 
    1252                 :       // We have never made a wrapper for this implementation.
    1253                 :       // Create an XPC wrapper for the script object and hand it back.
    1254                 : 
    1255               0 :       nsIDocument* doc = aContent->OwnerDoc();
    1256                 : 
    1257               0 :       nsIScriptGlobalObject *global = doc->GetScriptGlobalObject();
    1258               0 :       if (!global)
    1259               0 :         return NS_NOINTERFACE;
    1260                 : 
    1261               0 :       nsIScriptContext *context = global->GetContext();
    1262               0 :       if (!context)
    1263               0 :         return NS_NOINTERFACE;
    1264                 : 
    1265               0 :       JSContext* jscontext = context->GetNativeContext();
    1266               0 :       if (!jscontext)
    1267               0 :         return NS_NOINTERFACE;
    1268                 : 
    1269               0 :       nsIXPConnect *xpConnect = nsContentUtils::XPConnect();
    1270                 : 
    1271               0 :       nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
    1272                 :       xpConnect->GetWrappedNativeOfNativeObject(jscontext,
    1273               0 :                                                 global->GetGlobalJSObject(),
    1274                 :                                                 aContent,
    1275                 :                                                 NS_GET_IID(nsISupports),
    1276               0 :                                                 getter_AddRefs(wrapper));
    1277               0 :       NS_ENSURE_TRUE(wrapper, NS_NOINTERFACE);
    1278                 : 
    1279               0 :       JSObject* jsobj = nsnull;
    1280                 : 
    1281               0 :       wrapper->GetJSObject(&jsobj);
    1282               0 :       NS_ENSURE_TRUE(jsobj, NS_NOINTERFACE);
    1283                 : 
    1284                 :       nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, jscontext,
    1285               0 :                                                         jsobj, aIID, aResult);
    1286               0 :       if (NS_FAILED(rv))
    1287               0 :         return rv;
    1288                 : 
    1289                 :       // We successfully created a wrapper.  We will own this wrapper for as long as the binding remains
    1290                 :       // alive.  At the time the binding is cleared out of the bindingManager, we will remove the wrapper
    1291                 :       // from the bindingManager as well.
    1292               0 :       nsISupports* supp = static_cast<nsISupports*>(*aResult);
    1293               0 :       wrappedJS = do_QueryInterface(supp);
    1294               0 :       SetWrappedJS(aContent, wrappedJS);
    1295                 : 
    1296               0 :       return rv;
    1297                 :     }
    1298                 :   }
    1299                 :   
    1300             993 :   *aResult = nsnull;
    1301             993 :   return NS_NOINTERFACE;
    1302                 : }
    1303                 : 
    1304                 : nsresult
    1305               0 : nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
    1306                 :                             RuleProcessorData* aData,
    1307                 :                             bool* aCutOffInheritance)
    1308                 : {
    1309               0 :   *aCutOffInheritance = false;
    1310                 :   
    1311               0 :   NS_ASSERTION(aData->mElement, "How did that happen?");
    1312                 : 
    1313                 :   // Walk the binding scope chain, starting with the binding attached to our
    1314                 :   // content, up till we run out of scopes or we get cut off.
    1315               0 :   nsIContent *content = aData->mElement;
    1316                 :   
    1317               0 :   do {
    1318               0 :     nsXBLBinding *binding = GetBinding(content);
    1319               0 :     if (binding) {
    1320               0 :       aData->mTreeMatchContext.mScopedRoot = content;
    1321               0 :       binding->WalkRules(aFunc, aData);
    1322                 :       // If we're not looking at our original content, allow the binding to cut
    1323                 :       // off style inheritance
    1324               0 :       if (content != aData->mElement) {
    1325               0 :         if (!binding->InheritsStyle()) {
    1326                 :           // Go no further; we're not inheriting style from anything above here
    1327               0 :           break;
    1328                 :         }
    1329                 :       }
    1330                 :     }
    1331                 : 
    1332               0 :     if (content->IsRootOfNativeAnonymousSubtree()) {
    1333               0 :       break; // Deliberately cut off style inheritance here.
    1334                 :     }
    1335                 : 
    1336               0 :     content = content->GetBindingParent();
    1337                 :   } while (content);
    1338                 : 
    1339                 :   // If "content" is non-null that means we cut off inheritance at some point
    1340                 :   // in the loop.
    1341               0 :   *aCutOffInheritance = (content != nsnull);
    1342                 : 
    1343                 :   // Null out the scoped root that we set repeatedly
    1344               0 :   aData->mTreeMatchContext.mScopedRoot = nsnull;
    1345                 : 
    1346               0 :   return NS_OK;
    1347                 : }
    1348                 : 
    1349                 : typedef nsTHashtable<nsVoidPtrHashKey> RuleProcessorSet;
    1350                 : 
    1351                 : static PLDHashOperator
    1352               0 : EnumRuleProcessors(nsISupports *aKey, nsXBLBinding *aBinding, void* aClosure)
    1353                 : {
    1354               0 :   RuleProcessorSet *set = static_cast<RuleProcessorSet*>(aClosure);
    1355               0 :   for (nsXBLBinding *binding = aBinding; binding;
    1356                 :        binding = binding->GetBaseBinding()) {
    1357                 :     nsIStyleRuleProcessor *ruleProc =
    1358               0 :       binding->PrototypeBinding()->GetRuleProcessor();
    1359               0 :     if (ruleProc) {
    1360               0 :       if (!set->IsInitialized() && !set->Init(16))
    1361               0 :         return PL_DHASH_STOP;
    1362               0 :       set->PutEntry(ruleProc);
    1363                 :     }
    1364                 :   }
    1365               0 :   return PL_DHASH_NEXT;
    1366                 : }
    1367                 : 
    1368                 : struct WalkAllRulesData {
    1369                 :   nsIStyleRuleProcessor::EnumFunc mFunc;
    1370                 :   RuleProcessorData* mData;
    1371                 : };
    1372                 : 
    1373                 : static PLDHashOperator
    1374               0 : EnumWalkAllRules(nsVoidPtrHashKey *aKey, void* aClosure)
    1375                 : {
    1376                 :   nsIStyleRuleProcessor *ruleProcessor =
    1377               0 :     static_cast<nsIStyleRuleProcessor*>(const_cast<void*>(aKey->GetKey()));
    1378               0 :   WalkAllRulesData *data = static_cast<WalkAllRulesData*>(aClosure);
    1379                 : 
    1380               0 :   (*(data->mFunc))(ruleProcessor, data->mData);
    1381                 : 
    1382               0 :   return PL_DHASH_NEXT;
    1383                 : }
    1384                 : 
    1385                 : void
    1386               0 : nsBindingManager::WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc,
    1387                 :                                RuleProcessorData* aData)
    1388                 : {
    1389               0 :   if (!mBindingTable.IsInitialized())
    1390               0 :     return;
    1391                 : 
    1392               0 :   RuleProcessorSet set;
    1393               0 :   mBindingTable.EnumerateRead(EnumRuleProcessors, &set);
    1394               0 :   if (!set.IsInitialized())
    1395                 :     return;
    1396                 : 
    1397               0 :   WalkAllRulesData data = { aFunc, aData };
    1398               0 :   set.EnumerateEntries(EnumWalkAllRules, &data);
    1399                 : }
    1400                 : 
    1401                 : struct MediumFeaturesChangedData {
    1402                 :   nsPresContext *mPresContext;
    1403                 :   bool *mRulesChanged;
    1404                 : };
    1405                 : 
    1406                 : static PLDHashOperator
    1407               0 : EnumMediumFeaturesChanged(nsVoidPtrHashKey *aKey, void* aClosure)
    1408                 : {
    1409                 :   nsIStyleRuleProcessor *ruleProcessor =
    1410               0 :     static_cast<nsIStyleRuleProcessor*>(const_cast<void*>(aKey->GetKey()));
    1411                 :   MediumFeaturesChangedData *data =
    1412               0 :     static_cast<MediumFeaturesChangedData*>(aClosure);
    1413                 : 
    1414               0 :   bool thisChanged = ruleProcessor->MediumFeaturesChanged(data->mPresContext);
    1415               0 :   *data->mRulesChanged = *data->mRulesChanged || thisChanged;
    1416                 : 
    1417               0 :   return PL_DHASH_NEXT;
    1418                 : }
    1419                 : 
    1420                 : nsresult
    1421               0 : nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext,
    1422                 :                                         bool* aRulesChanged)
    1423                 : {
    1424               0 :   *aRulesChanged = false;
    1425               0 :   if (!mBindingTable.IsInitialized())
    1426               0 :     return NS_OK;
    1427                 : 
    1428               0 :   RuleProcessorSet set;
    1429               0 :   mBindingTable.EnumerateRead(EnumRuleProcessors, &set);
    1430               0 :   if (!set.IsInitialized())
    1431               0 :     return NS_OK;
    1432                 : 
    1433               0 :   MediumFeaturesChangedData data = { aPresContext, aRulesChanged };
    1434               0 :   set.EnumerateEntries(EnumMediumFeaturesChanged, &data);
    1435               0 :   return NS_OK;
    1436                 : }
    1437                 : 
    1438                 : static PLDHashOperator
    1439               0 : EnumAppendAllSheets(nsISupports *aKey, nsXBLBinding *aBinding, void* aClosure)
    1440                 : {
    1441                 :   nsTArray<nsCSSStyleSheet*>* array =
    1442               0 :     static_cast<nsTArray<nsCSSStyleSheet*>*>(aClosure);
    1443               0 :   for (nsXBLBinding *binding = aBinding; binding;
    1444                 :        binding = binding->GetBaseBinding()) {
    1445                 :     nsXBLPrototypeResources::sheet_array_type* sheets =
    1446               0 :       binding->PrototypeBinding()->GetStyleSheets();
    1447               0 :     if (sheets) {
    1448                 :       // Copy from nsTArray<nsRefPtr<nsCSSStyleSheet> > to
    1449                 :       // nsTArray<nsCSSStyleSheet*>.
    1450               0 :       array->AppendElements(*sheets);
    1451                 :     }
    1452                 :   }
    1453               0 :   return PL_DHASH_NEXT;
    1454                 : }
    1455                 : 
    1456                 : void
    1457               0 : nsBindingManager::AppendAllSheets(nsTArray<nsCSSStyleSheet*>& aArray)
    1458                 : {
    1459               0 :   if (!mBindingTable.IsInitialized())
    1460               0 :     return;
    1461                 : 
    1462               0 :   mBindingTable.EnumerateRead(EnumAppendAllSheets, &aArray);
    1463                 : }
    1464                 : 
    1465                 : nsIContent*
    1466               0 : nsBindingManager::GetNestedInsertionPoint(nsIContent* aParent,
    1467                 :                                           const nsIContent* aChild)
    1468                 : {
    1469                 :   // Check to see if the content is anonymous.
    1470               0 :   if (aChild->GetBindingParent() == aParent)
    1471               0 :     return nsnull; // It is anonymous. Don't use the insertion point, since that's only
    1472                 :                    // for the explicit kids.
    1473                 : 
    1474                 :   PRUint32 index;
    1475               0 :   nsIContent *insertionElement = GetInsertionPoint(aParent, aChild, &index);
    1476               0 :   if (insertionElement && insertionElement != aParent) {
    1477                 :     // See if we nest even further in.
    1478               0 :     nsIContent* nestedPoint = GetNestedInsertionPoint(insertionElement, aChild);
    1479               0 :     if (nestedPoint)
    1480               0 :       insertionElement = nestedPoint;
    1481                 :   }
    1482                 : 
    1483               0 :   return insertionElement;
    1484                 : }
    1485                 : 
    1486                 : nsIContent*
    1487               0 : nsBindingManager::GetNestedSingleInsertionPoint(nsIContent* aParent,
    1488                 :                                                 bool* aMultipleInsertionPoints)
    1489                 : {
    1490               0 :   *aMultipleInsertionPoints = false;
    1491                 :   
    1492                 :   PRUint32 index;
    1493                 :   nsIContent *insertionElement =
    1494               0 :     GetSingleInsertionPoint(aParent, &index, aMultipleInsertionPoints);
    1495               0 :   if (*aMultipleInsertionPoints) {
    1496               0 :     return nsnull;
    1497                 :   }
    1498               0 :   if (insertionElement && insertionElement != aParent) {
    1499                 :     // See if we nest even further in.
    1500                 :     nsIContent* nestedPoint =
    1501                 :       GetNestedSingleInsertionPoint(insertionElement,
    1502               0 :                                     aMultipleInsertionPoints);
    1503               0 :     if (nestedPoint)
    1504               0 :       insertionElement = nestedPoint;
    1505                 :   }
    1506                 : 
    1507               0 :   return insertionElement;
    1508                 : }
    1509                 : 
    1510                 : nsXBLInsertionPoint*
    1511               0 : nsBindingManager::FindInsertionPointAndIndex(nsIContent* aContainer,
    1512                 :                                              nsIContent* aInsertionParent,
    1513                 :                                              PRUint32 aIndexInContainer,
    1514                 :                                              PRInt32 aAppend,
    1515                 :                                              PRInt32* aInsertionIndex)
    1516                 : {
    1517                 :   bool isAnonymousContentList;
    1518                 :   nsINodeList* nodeList =
    1519               0 :     GetXBLChildNodesInternal(aInsertionParent, &isAnonymousContentList);
    1520               0 :   if (!nodeList || !isAnonymousContentList) {
    1521               0 :     return nsnull;
    1522                 :   }
    1523                 : 
    1524                 :   // Find a non-pseudo-insertion point and just jam ourselves in.  This is
    1525                 :   // not 100% correct, since there might be multiple insertion points under
    1526                 :   // this insertion parent, and we should really be using the one that
    1527                 :   // matches our content...  Hack city, baby.
    1528                 :   nsAnonymousContentList* contentList =
    1529               0 :     static_cast<nsAnonymousContentList*>(nodeList);
    1530                 : 
    1531               0 :   PRInt32 count = contentList->GetInsertionPointCount();
    1532               0 :   for (PRInt32 i = 0; i < count; i++) {
    1533               0 :     nsXBLInsertionPoint* point = contentList->GetInsertionPointAt(i);
    1534               0 :     if (point->GetInsertionIndex() != -1) {
    1535                 :       // We're real. Jam the kid in.
    1536                 : 
    1537                 :       // Find the right insertion spot.  Can't just insert in the insertion
    1538                 :       // point at aIndexInContainer since the point may contain anonymous
    1539                 :       // content, not all of aContainer's kids, etc.  So find the last
    1540                 :       // child of aContainer that comes before aIndexInContainer and is in
    1541                 :       // the insertion point and insert right after it.
    1542               0 :       PRInt32 pointSize = point->ChildCount();
    1543               0 :       for (PRInt32 parentIndex = aIndexInContainer - 1; parentIndex >= 0;
    1544                 :            --parentIndex) {
    1545               0 :         nsIContent* currentSibling = aContainer->GetChildAt(parentIndex);
    1546               0 :         for (PRInt32 pointIndex = pointSize - 1; pointIndex >= 0;
    1547                 :              --pointIndex) {
    1548               0 :           if (point->ChildAt(pointIndex) == currentSibling) {
    1549               0 :             *aInsertionIndex = pointIndex + 1;
    1550               0 :             return point;
    1551                 :           }
    1552                 :         }
    1553                 :       }
    1554                 : 
    1555                 :       // None of our previous siblings are in here... just stick
    1556                 :       // ourselves in at the end of the insertion point if we're
    1557                 :       // appending, and at the beginning otherwise.            
    1558                 :       // XXXbz if we ever start doing the filter thing right, this may be no
    1559                 :       // good, since we may _still_ have anonymous kids in there and may need
    1560                 :       // to get the ordering with those right.  In fact, this is even wrong
    1561                 :       // without the filter thing for nested insertion points, since they might
    1562                 :       // contain anonymous content that needs to come after all explicit
    1563                 :       // kids... but we have no way to know that here easily.
    1564               0 :       if (aAppend) {
    1565               0 :         *aInsertionIndex = pointSize;
    1566                 :       } else {
    1567               0 :         *aInsertionIndex = 0;
    1568                 :       }
    1569               0 :       return point;
    1570                 :     }
    1571                 :   }
    1572                 : 
    1573               0 :   return nsnull;  
    1574                 : }
    1575                 : 
    1576                 : void
    1577            2366 : nsBindingManager::ContentAppended(nsIDocument* aDocument,
    1578                 :                                   nsIContent* aContainer,
    1579                 :                                   nsIContent* aFirstNewContent,
    1580                 :                                   PRInt32     aNewIndexInContainer)
    1581                 : {
    1582            2366 :   if (aNewIndexInContainer != -1 &&
    1583                 :       (mContentListTable.ops || mAnonymousNodesTable.ops)) {
    1584                 :     // It's not anonymous.
    1585               0 :     NS_ASSERTION(aNewIndexInContainer >= 0, "Bogus index");
    1586                 : 
    1587                 :     bool multiple;
    1588               0 :     nsIContent* ins = GetNestedSingleInsertionPoint(aContainer, &multiple);
    1589                 : 
    1590               0 :     if (multiple) {
    1591                 :       // Do each kid individually
    1592               0 :       PRInt32 childCount = aContainer->GetChildCount();
    1593               0 :       for (PRInt32 idx = aNewIndexInContainer; idx < childCount; ++idx) {
    1594               0 :         HandleChildInsertion(aContainer, aContainer->GetChildAt(idx),
    1595               0 :                              idx, true);
    1596                 :       }
    1597                 :     }
    1598               0 :     else if (ins) {
    1599                 :       PRInt32 insertionIndex;
    1600                 :       nsXBLInsertionPoint* point =
    1601                 :         FindInsertionPointAndIndex(aContainer, ins, aNewIndexInContainer,
    1602               0 :                                    true, &insertionIndex);
    1603               0 :       if (point) {
    1604               0 :         PRInt32 childCount = aContainer->GetChildCount();
    1605               0 :         for (PRInt32 j = aNewIndexInContainer; j < childCount;
    1606                 :              j++, insertionIndex++) {
    1607               0 :           nsIContent* child = aContainer->GetChildAt(j);
    1608               0 :           point->InsertChildAt(insertionIndex, child);
    1609               0 :           SetInsertionParent(child, ins);
    1610                 :         }
    1611                 :       }
    1612                 :     }
    1613                 :   }
    1614            2366 : }
    1615                 : 
    1616                 : void
    1617            1295 : nsBindingManager::ContentInserted(nsIDocument* aDocument,
    1618                 :                                   nsIContent* aContainer,
    1619                 :                                   nsIContent* aChild,
    1620                 :                                   PRInt32 aIndexInContainer)
    1621                 : {
    1622            1295 :   if (aIndexInContainer != -1 &&
    1623                 :       (mContentListTable.ops || mAnonymousNodesTable.ops)) {
    1624                 :     // It's not anonymous.
    1625               0 :     NS_ASSERTION(aIndexInContainer >= 0, "Bogus index");
    1626               0 :     HandleChildInsertion(aContainer, aChild, aIndexInContainer, false);
    1627                 :   }
    1628            1295 : }
    1629                 : 
    1630                 : static void
    1631               0 : RemoveChildFromInsertionPoint(nsAnonymousContentList* aInsertionPointList,
    1632                 :                               nsIContent* aChild,
    1633                 :                               bool aRemoveFromPseudoPoints)
    1634                 : {
    1635                 :   // We need to find the insertion point that contains aChild and remove it
    1636                 :   // from that insertion point.  Sadly, we don't know which point it is, or
    1637                 :   // when we've hit it, but just trying to remove from all the pseudo or
    1638                 :   // non-pseudo insertion points, depending on the value of
    1639                 :   // aRemoveFromPseudoPoints, should work.
    1640                 : 
    1641                 :   // XXXbz nsXBLInsertionPoint::RemoveChild could return whether it
    1642                 :   // removed something.  Wouldn't that let us short-circuit the walk?
    1643                 :   // Or can a child be in multiple insertion points?  I wouldn't think
    1644                 :   // so...
    1645               0 :   PRInt32 count = aInsertionPointList->GetInsertionPointCount();
    1646               0 :   for (PRInt32 i = 0; i < count; i++) {
    1647                 :     nsXBLInsertionPoint* point =
    1648               0 :       aInsertionPointList->GetInsertionPointAt(i);
    1649               0 :     if ((point->GetInsertionIndex() == -1) == aRemoveFromPseudoPoints) {
    1650               0 :       point->RemoveChild(aChild);
    1651                 :     }
    1652                 :   }
    1653               0 : }
    1654                 : 
    1655                 : void
    1656             239 : nsBindingManager::ContentRemoved(nsIDocument* aDocument,
    1657                 :                                  nsIContent* aContainer,
    1658                 :                                  nsIContent* aChild,
    1659                 :                                  PRInt32 aIndexInContainer,
    1660                 :                                  nsIContent* aPreviousSibling)
    1661                 : {
    1662             239 :   if (aContainer && aIndexInContainer != -1 &&
    1663                 :       (mContentListTable.ops || mAnonymousNodesTable.ops)) {
    1664                 :     // It's not anonymous
    1665               0 :     nsCOMPtr<nsIContent> point = GetNestedInsertionPoint(aContainer, aChild);
    1666                 : 
    1667               0 :     if (point) {
    1668                 :       bool isAnonymousContentList;
    1669                 :       nsCOMPtr<nsIDOMNodeList> nodeList =
    1670               0 :         GetXBLChildNodesInternal(point, &isAnonymousContentList);
    1671                 :       
    1672               0 :       if (nodeList && isAnonymousContentList) {
    1673                 :         // Find a non-pseudo-insertion point and remove ourselves.
    1674                 :         RemoveChildFromInsertionPoint(static_cast<nsAnonymousContentList*>
    1675                 :                                         (static_cast<nsIDOMNodeList*>
    1676               0 :                                                     (nodeList)),
    1677                 :                                       aChild,
    1678               0 :                                       false);
    1679               0 :         SetInsertionParent(aChild, nsnull);
    1680                 :       }
    1681                 : 
    1682                 :       // Also remove from the list in mContentListTable, if any.
    1683               0 :       if (mContentListTable.ops) {
    1684                 :         nsCOMPtr<nsIDOMNodeList> otherNodeList =
    1685                 :           static_cast<nsAnonymousContentList*>
    1686               0 :                      (LookupObject(mContentListTable, point));
    1687               0 :         if (otherNodeList && otherNodeList != nodeList) {
    1688                 :           // otherNodeList is always anonymous
    1689                 :           RemoveChildFromInsertionPoint(static_cast<nsAnonymousContentList*>
    1690                 :                                         (static_cast<nsIDOMNodeList*>
    1691               0 :                                                     (otherNodeList)),
    1692                 :                                         aChild,
    1693               0 :                                         false);
    1694                 :         }
    1695                 :       }
    1696                 :     }
    1697                 : 
    1698                 :     // Whether the child has a nested insertion point or not, aContainer might
    1699                 :     // have insertion points under it.  If that's the case, we need to remove
    1700                 :     // aChild from the pseudo insertion point it's in.
    1701               0 :     if (mContentListTable.ops) {
    1702                 :       nsAnonymousContentList* insertionPointList =
    1703                 :         static_cast<nsAnonymousContentList*>(LookupObject(mContentListTable,
    1704               0 :                                                           aContainer));
    1705               0 :       if (insertionPointList) {
    1706               0 :         RemoveChildFromInsertionPoint(insertionPointList, aChild, true);
    1707                 :       }
    1708                 :     }
    1709                 :   }
    1710             239 : }
    1711                 : 
    1712                 : void
    1713            1271 : nsBindingManager::DropDocumentReference()
    1714                 : {
    1715            1271 :   mDestroyed = true;
    1716                 : 
    1717                 :   // Make sure to not run any more XBL constructors
    1718            1271 :   mProcessingAttachedStack = true;
    1719            1271 :   if (mProcessAttachedQueueEvent) {
    1720               0 :     mProcessAttachedQueueEvent->Revoke();
    1721                 :   }
    1722                 : 
    1723            1271 :   if (mContentListTable.ops)
    1724               0 :     PL_DHashTableFinish(&(mContentListTable));
    1725            1271 :   mContentListTable.ops = nsnull;
    1726                 : 
    1727            1271 :   if (mAnonymousNodesTable.ops)
    1728               0 :     PL_DHashTableFinish(&(mAnonymousNodesTable));
    1729            1271 :   mAnonymousNodesTable.ops = nsnull;
    1730                 : 
    1731            1271 :   if (mInsertionParentTable.ops)
    1732               0 :     PL_DHashTableFinish(&(mInsertionParentTable));
    1733            1271 :   mInsertionParentTable.ops = nsnull;
    1734                 : 
    1735            1271 :   if (mBindingTable.IsInitialized())
    1736               0 :     mBindingTable.Clear();
    1737                 : 
    1738            1271 :   mDocument = nsnull;
    1739            1271 : }
    1740                 : 
    1741                 : void
    1742          136368 : nsBindingManager::Traverse(nsIContent *aContent,
    1743                 :                            nsCycleCollectionTraversalCallback &cb)
    1744                 : {
    1745          136368 :   if (!aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
    1746          136368 :     return;
    1747                 :   }
    1748                 : 
    1749                 :   nsISupports *value;
    1750               0 :   if (mInsertionParentTable.ops &&
    1751               0 :       (value = LookupObject(mInsertionParentTable, aContent))) {
    1752               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mInsertionParentTable key");
    1753               0 :     cb.NoteXPCOMChild(aContent);
    1754               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mInsertionParentTable value");
    1755               0 :     cb.NoteXPCOMChild(value);
    1756                 :   }
    1757                 : 
    1758                 :   // XXXbz how exactly would NODE_MAY_BE_IN_BINDING_MNGR end up on non-elements?
    1759               0 :   if (!aContent->IsElement()) {
    1760               0 :     return;
    1761                 :   }
    1762                 : 
    1763               0 :   nsXBLBinding *binding = GetBinding(aContent);
    1764               0 :   if (binding) {
    1765               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mBindingTable key");
    1766               0 :     cb.NoteXPCOMChild(aContent);
    1767               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(binding, nsXBLBinding,
    1768                 :                                   "[via binding manager] mBindingTable value")
    1769                 :   }
    1770               0 :   if (mContentListTable.ops &&
    1771               0 :       (value = LookupObject(mContentListTable, aContent))) {
    1772               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mContentListTable key");
    1773               0 :     cb.NoteXPCOMChild(aContent);
    1774               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mContentListTable value");
    1775               0 :     cb.NoteXPCOMChild(value);
    1776                 :   }
    1777               0 :   if (mAnonymousNodesTable.ops &&
    1778               0 :       (value = LookupObject(mAnonymousNodesTable, aContent))) {
    1779               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mAnonymousNodesTable key");
    1780               0 :     cb.NoteXPCOMChild(aContent);
    1781               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mAnonymousNodesTable value");
    1782               0 :     cb.NoteXPCOMChild(value);
    1783                 :   }
    1784               0 :   if (mWrapperTable.ops &&
    1785               0 :       (value = LookupObject(mWrapperTable, aContent))) {
    1786               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mWrapperTable key");
    1787               0 :     cb.NoteXPCOMChild(aContent);
    1788               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mWrapperTable value");
    1789               0 :     cb.NoteXPCOMChild(value);
    1790                 :   }
    1791                 : }
    1792                 : 
    1793                 : void
    1794            4890 : nsBindingManager::BeginOutermostUpdate()
    1795                 : {
    1796            4890 :   mAttachedStackSizeOnOutermost = mAttachedStack.Length();
    1797            4890 : }
    1798                 : 
    1799                 : void
    1800            4890 : nsBindingManager::EndOutermostUpdate()
    1801                 : {
    1802            4890 :   if (!mProcessingAttachedStack) {
    1803            4890 :     ProcessAttachedQueue(mAttachedStackSizeOnOutermost);
    1804            4890 :     mAttachedStackSizeOnOutermost = 0;
    1805                 :   }
    1806            4890 : }
    1807                 : 
    1808                 : void
    1809               0 : nsBindingManager::HandleChildInsertion(nsIContent* aContainer,
    1810                 :                                        nsIContent* aChild,
    1811                 :                                        PRUint32 aIndexInContainer,
    1812                 :                                        bool aAppend)
    1813                 : {
    1814               0 :   NS_PRECONDITION(aChild, "Must have child");
    1815               0 :   NS_PRECONDITION(!aContainer ||
    1816                 :                   PRUint32(aContainer->IndexOf(aChild)) == aIndexInContainer,
    1817                 :                   "Child not at the right index?");
    1818                 : 
    1819               0 :   nsIContent* ins = GetNestedInsertionPoint(aContainer, aChild);
    1820                 : 
    1821               0 :   if (ins) {
    1822                 :     PRInt32 insertionIndex;
    1823                 :     nsXBLInsertionPoint* point =
    1824                 :       FindInsertionPointAndIndex(aContainer, ins, aIndexInContainer, aAppend,
    1825               0 :                                  &insertionIndex);
    1826               0 :     if (point) {
    1827               0 :       point->InsertChildAt(insertionIndex, aChild);
    1828               0 :       SetInsertionParent(aChild, ins);
    1829                 :     }
    1830                 :   }
    1831            4392 : }

Generated by: LCOV version 1.7