LCOV - code coverage report
Current view: directory - content/xbl/src - nsXBLPrototypeBinding.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1118 3 0.3 %
Date: 2012-06-02 Functions: 108 3 2.8 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Original Author: David W. Hyatt (hyatt@netscape.com)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/Util.h"
      40                 : 
      41                 : #include "nsCOMPtr.h"
      42                 : #include "nsIAtom.h"
      43                 : #include "nsIInputStream.h"
      44                 : #include "nsINameSpaceManager.h"
      45                 : #include "nsIURI.h"
      46                 : #include "nsIURL.h"
      47                 : #include "nsIDOMEventTarget.h"
      48                 : #include "nsIChannel.h"
      49                 : #include "nsXPIDLString.h"
      50                 : #include "nsReadableUtils.h"
      51                 : #include "nsIParser.h"
      52                 : #include "nsParserCIID.h"
      53                 : #include "nsNetUtil.h"
      54                 : #include "plstr.h"
      55                 : #include "nsContentCreatorFunctions.h"
      56                 : #include "nsIDocument.h"
      57                 : #include "nsIXMLContentSink.h"
      58                 : #include "nsContentCID.h"
      59                 : #include "nsXMLDocument.h"
      60                 : #include "nsXBLService.h"
      61                 : #include "nsXBLBinding.h"
      62                 : #include "nsXBLInsertionPoint.h"
      63                 : #include "nsXBLPrototypeBinding.h"
      64                 : #include "nsXBLContentSink.h"
      65                 : #include "nsFixedSizeAllocator.h"
      66                 : #include "xptinfo.h"
      67                 : #include "nsIInterfaceInfoManager.h"
      68                 : #include "nsIDocumentObserver.h"
      69                 : #include "nsGkAtoms.h"
      70                 : #include "nsXBLProtoImpl.h"
      71                 : #include "nsCRT.h"
      72                 : #include "nsContentUtils.h"
      73                 : 
      74                 : #include "nsIScriptContext.h"
      75                 : #include "nsIScriptError.h"
      76                 : 
      77                 : #include "nsIStyleRuleProcessor.h"
      78                 : #include "nsXBLResourceLoader.h"
      79                 : #include "mozilla/dom/Element.h"
      80                 : 
      81                 : #ifdef MOZ_XUL
      82                 : #include "nsXULElement.h"
      83                 : #endif
      84                 : 
      85                 : using namespace mozilla;
      86                 : using namespace mozilla::dom;
      87                 : 
      88                 : // Helper Classes =====================================================================
      89                 : 
      90                 : // Internal helper class for managing our IID table.
      91                 : class nsIIDKey : public nsHashKey {
      92                 :   public:
      93                 :     nsIID mKey;
      94                 : 
      95                 :   public:
      96               0 :     nsIIDKey(REFNSIID key) : mKey(key) {}
      97               0 :     ~nsIIDKey(void) {}
      98                 : 
      99               0 :     PRUint32 HashCode(void) const {
     100                 :       // Just use the 32-bit m0 field.
     101               0 :       return mKey.m0;
     102                 :     }
     103                 : 
     104               0 :     bool Equals(const nsHashKey *aKey) const {
     105               0 :       return mKey.Equals( ((nsIIDKey*) aKey)->mKey);
     106                 :     }
     107                 : 
     108               0 :     nsHashKey *Clone(void) const {
     109               0 :       return new nsIIDKey(mKey);
     110                 :     }
     111                 : };
     112                 : 
     113                 : // nsXBLAttributeEntry and helpers.  This class is used to efficiently handle
     114                 : // attribute changes in anonymous content.
     115                 : 
     116                 : class nsXBLAttributeEntry {
     117                 : public:
     118               0 :   nsIAtom* GetSrcAttribute() { return mSrcAttribute; }
     119               0 :   nsIAtom* GetDstAttribute() { return mDstAttribute; }
     120               0 :   PRInt32 GetDstNameSpace() { return mDstNameSpace; }
     121                 :   
     122               0 :   nsIContent* GetElement() { return mElement; }
     123                 : 
     124               0 :   nsXBLAttributeEntry* GetNext() { return mNext; }
     125               0 :   void SetNext(nsXBLAttributeEntry* aEntry) { mNext = aEntry; }
     126                 : 
     127                 :   static nsXBLAttributeEntry*
     128               0 :   Create(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, PRInt32 aDstNameSpace, nsIContent* aContent) {
     129               0 :     void* place = nsXBLPrototypeBinding::kAttrPool->Alloc(sizeof(nsXBLAttributeEntry));
     130                 :     return place ? ::new (place) nsXBLAttributeEntry(aSrcAtom, aDstAtom, aDstNameSpace, 
     131               0 :                                                      aContent) : nsnull;
     132                 :   }
     133                 : 
     134                 :   static void
     135               0 :   Destroy(nsXBLAttributeEntry* aSelf) {
     136               0 :     aSelf->~nsXBLAttributeEntry();
     137               0 :     nsXBLPrototypeBinding::kAttrPool->Free(aSelf, sizeof(*aSelf));
     138               0 :   }
     139                 : 
     140                 : protected:
     141                 :   nsIContent* mElement;
     142                 : 
     143                 :   nsCOMPtr<nsIAtom> mSrcAttribute;
     144                 :   nsCOMPtr<nsIAtom> mDstAttribute;
     145                 :   PRInt32 mDstNameSpace;
     146                 :   nsXBLAttributeEntry* mNext;
     147                 : 
     148               0 :   nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, PRInt32 aDstNameSpace,
     149                 :                       nsIContent* aContent)
     150                 :     : mElement(aContent),
     151                 :       mSrcAttribute(aSrcAtom),
     152                 :       mDstAttribute(aDstAtom),
     153                 :       mDstNameSpace(aDstNameSpace),
     154               0 :       mNext(nsnull) { }
     155                 : 
     156               0 :   ~nsXBLAttributeEntry() {
     157               0 :     NS_CONTENT_DELETE_LIST_MEMBER(nsXBLAttributeEntry, this, mNext);
     158               0 :   }
     159                 : 
     160                 : private:
     161                 :   // Hide so that only Create() and Destroy() can be used to
     162                 :   // allocate and deallocate from the heap
     163                 :   static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     164               0 :   static void operator delete(void*, size_t) {}
     165                 : };
     166                 : 
     167                 : // nsXBLInsertionPointEntry and helpers.  This class stores all the necessary
     168                 : // info to figure out the position of an insertion point.
     169                 : // The same insertion point may be in the insertion point table for multiple
     170                 : // keys, so we refcount the entries.
     171                 : 
     172                 : class nsXBLInsertionPointEntry {
     173                 : public:
     174               0 :   ~nsXBLInsertionPointEntry() {
     175               0 :     if (mDefaultContent) {
     176               0 :       nsAutoScriptBlocker scriptBlocker;
     177                 :       // mDefaultContent is a sort of anonymous content within the XBL
     178                 :       // document, and we own and manage it.  Unhook it here, since we're going
     179                 :       // away.
     180               0 :       mDefaultContent->UnbindFromTree();
     181                 :     }      
     182               0 :   }
     183                 : 
     184            1464 :   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPointEntry)
     185                 : 
     186               0 :   nsIContent* GetInsertionParent() { return mInsertionParent; }
     187               0 :   PRUint32 GetInsertionIndex() { return mInsertionIndex; }
     188               0 :   void SetInsertionIndex(PRUint32 aIndex) { mInsertionIndex = aIndex; }
     189                 : 
     190               0 :   nsIContent* GetDefaultContent() { return mDefaultContent; }
     191               0 :   void SetDefaultContent(nsIContent* aChildren) { mDefaultContent = aChildren; }
     192                 : 
     193                 : 
     194                 :   // We keep kPool alive as long as there is at least either a
     195                 :   // nsXBLPrototypeBinding or a nsXBLInsertionPointEntry alive.
     196                 :   // nsXBLPrototypeBinding has its own global refcount so it only adds 1 to
     197                 :   // nsXBLInsertionPointEntry::gRefCnt as long as there's at least one
     198                 :   // nsXBLPrototypeBinding alive.
     199                 : 
     200               0 :   static void InitPool(PRInt32 aInitialSize)
     201                 :   {
     202               0 :     if (++gRefCnt == 1) {
     203               0 :       kPool = new nsFixedSizeAllocator();
     204               0 :       if (kPool) {
     205                 :         static const size_t kBucketSizes[] = {
     206                 :           sizeof(nsXBLInsertionPointEntry)
     207                 :         };
     208                 :         kPool->Init("XBL Insertion Point Entries", kBucketSizes,
     209               0 :                     ArrayLength(kBucketSizes), aInitialSize);
     210                 :       }
     211                 :     }
     212               0 :   }
     213               0 :   static bool PoolInited()
     214                 :   {
     215               0 :     return kPool != nsnull;
     216                 :   }
     217               0 :   static void ReleasePool()
     218                 :   {
     219               0 :     if (--gRefCnt == 0) {
     220               0 :       delete kPool;
     221                 :     }
     222               0 :   }
     223                 : 
     224                 :   static nsXBLInsertionPointEntry*
     225               0 :   Create(nsIContent* aParent) {
     226               0 :     void* place = kPool->Alloc(sizeof(nsXBLInsertionPointEntry));
     227               0 :     if (!place) {
     228               0 :       return nsnull;
     229                 :     }
     230               0 :     ++gRefCnt;
     231               0 :     return ::new (place) nsXBLInsertionPointEntry(aParent);
     232                 :   }
     233                 : 
     234                 :   static void
     235                 :   Destroy(nsXBLInsertionPointEntry* aSelf) {
     236                 :     aSelf->~nsXBLInsertionPointEntry();
     237                 :     kPool->Free(aSelf, sizeof(*aSelf));
     238                 :     nsXBLInsertionPointEntry::ReleasePool();
     239                 :   }
     240                 : 
     241               0 :   NS_INLINE_DECL_REFCOUNTING(nsXBLInsertionPointEntry)
     242                 : 
     243                 : protected:
     244                 :   nsCOMPtr<nsIContent> mInsertionParent;
     245                 :   nsCOMPtr<nsIContent> mDefaultContent;
     246                 :   PRUint32 mInsertionIndex;
     247                 : 
     248               0 :   nsXBLInsertionPointEntry(nsIContent* aParent)
     249                 :     : mInsertionParent(aParent),
     250               0 :       mInsertionIndex(0) { }
     251                 : 
     252                 : private:
     253                 :   // Hide so that only Create() and Destroy() can be used to
     254                 :   // allocate and deallocate from the heap
     255                 :   static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     256               0 :   static void operator delete(void*, size_t) {}
     257                 : 
     258                 :   static nsFixedSizeAllocator* kPool;
     259                 :   static PRUint32 gRefCnt;
     260                 : };
     261                 : 
     262                 : PRUint32 nsXBLInsertionPointEntry::gRefCnt = 0;
     263                 : nsFixedSizeAllocator* nsXBLInsertionPointEntry::kPool;
     264                 : 
     265            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLInsertionPointEntry)
     266               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLInsertionPointEntry)
     267               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInsertionParent)
     268               0 :   if (tmp->mDefaultContent) {
     269               0 :     nsAutoScriptBlocker scriptBlocker;
     270                 :     // mDefaultContent is a sort of anonymous content within the XBL
     271                 :     // document, and we own and manage it.  Unhook it here, since we're going
     272                 :     // away.
     273               0 :     tmp->mDefaultContent->UnbindFromTree();
     274               0 :     tmp->mDefaultContent = nsnull;
     275                 :   }      
     276               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     277               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLInsertionPointEntry)
     278               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInsertionParent)
     279               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDefaultContent)
     280               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     281               0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXBLInsertionPointEntry, AddRef)
     282               0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXBLInsertionPointEntry, Release)
     283                 : 
     284                 : // =============================================================================
     285                 : 
     286                 : // Static initialization
     287                 : PRUint32 nsXBLPrototypeBinding::gRefCnt = 0;
     288                 : 
     289                 : nsFixedSizeAllocator* nsXBLPrototypeBinding::kAttrPool;
     290                 : 
     291                 : static const PRInt32 kNumElements = 128;
     292                 : 
     293                 : static const size_t kAttrBucketSizes[] = {
     294                 :   sizeof(nsXBLAttributeEntry)
     295                 : };
     296                 : 
     297                 : static const PRInt32 kAttrNumBuckets = sizeof(kAttrBucketSizes)/sizeof(size_t);
     298                 : static const PRInt32 kAttrInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
     299                 : 
     300                 : static const PRInt32 kInsInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLInsertionPointEntry))) * kNumElements;
     301                 : 
     302                 : // Implementation /////////////////////////////////////////////////////////////////
     303                 : 
     304                 : // Constructors/Destructors
     305               0 : nsXBLPrototypeBinding::nsXBLPrototypeBinding()
     306                 : : mImplementation(nsnull),
     307                 :   mBaseBinding(nsnull),
     308                 :   mInheritStyle(true), 
     309                 :   mCheckedBaseProto(false),
     310                 :   mKeyHandlersRegistered(false),
     311                 :   mResources(nsnull),
     312                 :   mAttributeTable(nsnull),
     313                 :   mInsertionPointTable(nsnull),
     314                 :   mInterfaceTable(nsnull),
     315               0 :   mBaseNameSpaceID(kNameSpaceID_None)
     316                 : {
     317               0 :   MOZ_COUNT_CTOR(nsXBLPrototypeBinding);
     318               0 :   gRefCnt++;
     319                 : 
     320               0 :   if (gRefCnt == 1) {
     321               0 :     kAttrPool = new nsFixedSizeAllocator();
     322               0 :     if (kAttrPool) {
     323               0 :       kAttrPool->Init("XBL Attribute Entries", kAttrBucketSizes, kAttrNumBuckets, kAttrInitialSize);
     324                 :     }
     325               0 :     nsXBLInsertionPointEntry::InitPool(kInsInitialSize);
     326                 :   }
     327               0 : }
     328                 : 
     329                 : nsresult
     330               0 : nsXBLPrototypeBinding::Init(const nsACString& aID,
     331                 :                             nsXBLDocumentInfo* aInfo,
     332                 :                             nsIContent* aElement,
     333                 :                             bool aFirstBinding)
     334                 : {
     335               0 :   if (!kAttrPool || !nsXBLInsertionPointEntry::PoolInited()) {
     336               0 :     return NS_ERROR_OUT_OF_MEMORY;
     337                 :   }
     338                 : 
     339               0 :   nsresult rv = aInfo->DocumentURI()->Clone(getter_AddRefs(mBindingURI));
     340               0 :   NS_ENSURE_SUCCESS(rv, rv);
     341                 : 
     342                 :   // The binding URI might be an immutable URI (e.g. for about: URIs). In that case,
     343                 :   // we'll fail in SetRef below, but that doesn't matter much for now.
     344               0 :   if (aFirstBinding) {
     345               0 :     rv = mBindingURI->Clone(getter_AddRefs(mAlternateBindingURI));
     346               0 :     NS_ENSURE_SUCCESS(rv, rv);
     347                 :   }
     348               0 :   mBindingURI->SetRef(aID);
     349                 : 
     350               0 :   mXBLDocInfoWeak = aInfo;
     351                 : 
     352                 :   // aElement will be null when reading from the cache, but the element will
     353                 :   // still be set later.
     354               0 :   if (aElement) {
     355               0 :     SetBindingElement(aElement);
     356                 :   }
     357               0 :   return NS_OK;
     358                 : }
     359                 : 
     360               0 : bool nsXBLPrototypeBinding::CompareBindingURI(nsIURI* aURI) const
     361                 : {
     362               0 :   bool equal = false;
     363               0 :   mBindingURI->Equals(aURI, &equal);
     364               0 :   if (!equal && mAlternateBindingURI) {
     365               0 :     mAlternateBindingURI->Equals(aURI, &equal);
     366                 :   }
     367               0 :   return equal;
     368                 : }
     369                 : 
     370                 : static bool
     371               0 : TraverseInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
     372                 : {
     373                 :   nsCycleCollectionTraversalCallback &cb = 
     374               0 :     *static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
     375                 :   nsXBLInsertionPointEntry* entry =
     376               0 :     static_cast<nsXBLInsertionPointEntry*>(aData);
     377               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(entry,
     378                 :                                                nsXBLInsertionPointEntry,
     379                 :                                                "[insertion point table] value")
     380               0 :   return kHashEnumerateNext;
     381                 : }
     382                 : 
     383                 : static bool
     384               0 : TraverseBinding(nsHashKey *aKey, void *aData, void* aClosure)
     385                 : {
     386                 :   nsCycleCollectionTraversalCallback *cb = 
     387               0 :     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
     388               0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME((*cb), "proto mInterfaceTable data");
     389               0 :   cb->NoteXPCOMChild(static_cast<nsISupports*>(aData));
     390               0 :   return kHashEnumerateNext;
     391                 : }
     392                 : 
     393                 : void
     394               0 : nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
     395                 : {
     396               0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mBinding");
     397               0 :   cb.NoteXPCOMChild(mBinding);
     398               0 :   if (mResources) {
     399               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mResources mLoader");
     400               0 :     cb.NoteXPCOMChild(mResources->mLoader);
     401                 :   }
     402               0 :   if (mInsertionPointTable)
     403               0 :     mInsertionPointTable->Enumerate(TraverseInsertionPoint, &cb);
     404               0 :   if (mInterfaceTable)
     405               0 :     mInterfaceTable->Enumerate(TraverseBinding, &cb);
     406               0 : }
     407                 : 
     408                 : void
     409               0 : nsXBLPrototypeBinding::UnlinkJSObjects()
     410                 : {
     411               0 :   if (mImplementation)
     412               0 :     mImplementation->UnlinkJSObjects();
     413               0 : }
     414                 : 
     415                 : void
     416               0 : nsXBLPrototypeBinding::Trace(TraceCallback aCallback, void *aClosure) const
     417                 : {
     418               0 :   if (mImplementation)
     419               0 :     mImplementation->Trace(aCallback, aClosure);
     420               0 : }
     421                 : 
     422                 : void
     423               0 : nsXBLPrototypeBinding::Initialize()
     424                 : {
     425               0 :   nsIContent* content = GetImmediateChild(nsGkAtoms::content);
     426               0 :   if (content) {
     427                 :     // Make sure to construct the attribute table first, since constructing the
     428                 :     // insertion point table removes some of the subtrees, which makes them
     429                 :     // unreachable by walking our DOM.
     430               0 :     ConstructAttributeTable(content);
     431               0 :     ConstructInsertionTable(content);
     432                 :   }
     433               0 : }
     434                 : 
     435               0 : nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
     436                 : {
     437               0 :   delete mResources;
     438               0 :   delete mAttributeTable;
     439               0 :   delete mInsertionPointTable;
     440               0 :   delete mInterfaceTable;
     441               0 :   delete mImplementation;
     442               0 :   gRefCnt--;
     443               0 :   if (gRefCnt == 0) {
     444               0 :     delete kAttrPool;
     445               0 :     nsXBLInsertionPointEntry::ReleasePool();
     446                 :   }
     447               0 :   MOZ_COUNT_DTOR(nsXBLPrototypeBinding);
     448               0 : }
     449                 : 
     450                 : void
     451               0 : nsXBLPrototypeBinding::SetBasePrototype(nsXBLPrototypeBinding* aBinding)
     452                 : {
     453               0 :   if (mBaseBinding == aBinding)
     454               0 :     return;
     455                 : 
     456               0 :   if (mBaseBinding) {
     457               0 :     NS_ERROR("Base XBL prototype binding is already defined!");
     458               0 :     return;
     459                 :   }
     460                 : 
     461               0 :   mBaseBinding = aBinding;
     462                 : }
     463                 : 
     464                 : already_AddRefed<nsIContent>
     465               0 : nsXBLPrototypeBinding::GetBindingElement()
     466                 : {
     467               0 :   nsIContent* result = mBinding;
     468               0 :   NS_IF_ADDREF(result);
     469               0 :   return result;
     470                 : }
     471                 : 
     472                 : void
     473               0 : nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
     474                 : {
     475               0 :   mBinding = aElement;
     476               0 :   if (mBinding->AttrValueIs(kNameSpaceID_None, nsGkAtoms::inheritstyle,
     477               0 :                             nsGkAtoms::_false, eCaseMatters))
     478               0 :     mInheritStyle = false;
     479               0 : }
     480                 : 
     481                 : bool
     482               0 : nsXBLPrototypeBinding::GetAllowScripts()
     483                 : {
     484               0 :   return mXBLDocInfoWeak->GetScriptAccess();
     485                 : }
     486                 : 
     487                 : bool
     488               0 : nsXBLPrototypeBinding::LoadResources()
     489                 : {
     490               0 :   if (mResources) {
     491                 :     bool result;
     492               0 :     mResources->LoadResources(&result);
     493               0 :     return result;
     494                 :   }
     495                 : 
     496               0 :   return true;
     497                 : }
     498                 : 
     499                 : nsresult
     500               0 : nsXBLPrototypeBinding::AddResource(nsIAtom* aResourceType, const nsAString& aSrc)
     501                 : {
     502               0 :   if (!mResources) {
     503               0 :     mResources = new nsXBLPrototypeResources(this);
     504               0 :     if (!mResources)
     505               0 :       return NS_ERROR_OUT_OF_MEMORY;
     506                 :   }
     507                 : 
     508               0 :   mResources->AddResource(aResourceType, aSrc);
     509               0 :   return NS_OK;
     510                 : }
     511                 : 
     512                 : nsresult
     513               0 : nsXBLPrototypeBinding::FlushSkinSheets()
     514                 : {
     515               0 :   if (mResources)
     516               0 :     return mResources->FlushSkinSheets();
     517               0 :   return NS_OK;
     518                 : }
     519                 : 
     520                 : nsresult
     521               0 : nsXBLPrototypeBinding::BindingAttached(nsIContent* aBoundElement)
     522                 : {
     523               0 :   if (mImplementation && mImplementation->CompiledMembers() &&
     524                 :       mImplementation->mConstructor)
     525               0 :     return mImplementation->mConstructor->Execute(aBoundElement);
     526               0 :   return NS_OK;
     527                 : }
     528                 : 
     529                 : nsresult
     530               0 : nsXBLPrototypeBinding::BindingDetached(nsIContent* aBoundElement)
     531                 : {
     532               0 :   if (mImplementation && mImplementation->CompiledMembers() &&
     533                 :       mImplementation->mDestructor)
     534               0 :     return mImplementation->mDestructor->Execute(aBoundElement);
     535               0 :   return NS_OK;
     536                 : }
     537                 : 
     538                 : nsXBLProtoImplAnonymousMethod*
     539               0 : nsXBLPrototypeBinding::GetConstructor()
     540                 : {
     541               0 :   if (mImplementation)
     542               0 :     return mImplementation->mConstructor;
     543                 : 
     544               0 :   return nsnull;
     545                 : }
     546                 : 
     547                 : nsXBLProtoImplAnonymousMethod*
     548               0 : nsXBLPrototypeBinding::GetDestructor()
     549                 : {
     550               0 :   if (mImplementation)
     551               0 :     return mImplementation->mDestructor;
     552                 : 
     553               0 :   return nsnull;
     554                 : }
     555                 : 
     556                 : nsresult
     557               0 : nsXBLPrototypeBinding::SetConstructor(nsXBLProtoImplAnonymousMethod* aMethod)
     558                 : {
     559               0 :   if (!mImplementation)
     560               0 :     return NS_ERROR_FAILURE;
     561               0 :   mImplementation->mConstructor = aMethod;
     562               0 :   return NS_OK;
     563                 : }
     564                 : 
     565                 : nsresult
     566               0 : nsXBLPrototypeBinding::SetDestructor(nsXBLProtoImplAnonymousMethod* aMethod)
     567                 : {
     568               0 :   if (!mImplementation)
     569               0 :     return NS_ERROR_FAILURE;
     570               0 :   mImplementation->mDestructor = aMethod;
     571               0 :   return NS_OK;
     572                 : }
     573                 : 
     574                 : nsresult
     575               0 : nsXBLPrototypeBinding::InstallImplementation(nsIContent* aBoundElement)
     576                 : {
     577               0 :   if (mImplementation)
     578               0 :     return mImplementation->InstallImplementation(this, aBoundElement);
     579               0 :   return NS_OK;
     580                 : }
     581                 : 
     582                 : // XXXbz this duplicates lots of SetAttrs
     583                 : void
     584               0 : nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute,
     585                 :                                         PRInt32 aNameSpaceID,
     586                 :                                         bool aRemoveFlag, 
     587                 :                                         nsIContent* aChangedElement,
     588                 :                                         nsIContent* aAnonymousContent,
     589                 :                                         bool aNotify)
     590                 : {
     591               0 :   if (!mAttributeTable)
     592               0 :     return;
     593               0 :   nsPRUint32Key nskey(aNameSpaceID);
     594               0 :   nsObjectHashtable *attributesNS = static_cast<nsObjectHashtable*>(mAttributeTable->Get(&nskey));
     595               0 :   if (!attributesNS)
     596                 :     return;
     597                 : 
     598               0 :   nsISupportsKey key(aAttribute);
     599                 :   nsXBLAttributeEntry* xblAttr = static_cast<nsXBLAttributeEntry*>
     600               0 :                                             (attributesNS->Get(&key));
     601               0 :   if (!xblAttr)
     602                 :     return;
     603                 : 
     604                 :   // Iterate over the elements in the array.
     605               0 :   nsCOMPtr<nsIContent> content = GetImmediateChild(nsGkAtoms::content);
     606               0 :   while (xblAttr) {
     607               0 :     nsIContent* element = xblAttr->GetElement();
     608                 : 
     609                 :     nsCOMPtr<nsIContent> realElement = LocateInstance(aChangedElement, content,
     610                 :                                                       aAnonymousContent,
     611               0 :                                                       element);
     612                 : 
     613               0 :     if (realElement) {
     614                 :       // Hold a strong reference here so that the atom doesn't go away during
     615                 :       // UnsetAttr.
     616               0 :       nsCOMPtr<nsIAtom> dstAttr = xblAttr->GetDstAttribute();
     617               0 :       PRInt32 dstNs = xblAttr->GetDstNameSpace();
     618                 : 
     619               0 :       if (aRemoveFlag)
     620               0 :         realElement->UnsetAttr(dstNs, dstAttr, aNotify);
     621                 :       else {
     622               0 :         bool attrPresent = true;
     623               0 :         nsAutoString value;
     624                 :         // Check to see if the src attribute is xbl:text.  If so, then we need to obtain the 
     625                 :         // children of the real element and get the text nodes' values.
     626               0 :         if (aAttribute == nsGkAtoms::text && aNameSpaceID == kNameSpaceID_XBL) {
     627               0 :           nsContentUtils::GetNodeTextContent(aChangedElement, false, value);
     628               0 :           value.StripChar(PRUnichar('\n'));
     629               0 :           value.StripChar(PRUnichar('\r'));
     630               0 :           nsAutoString stripVal(value);
     631               0 :           stripVal.StripWhitespace();
     632               0 :           if (stripVal.IsEmpty()) 
     633               0 :             attrPresent = false;
     634                 :         }    
     635                 :         else {
     636               0 :           attrPresent = aChangedElement->GetAttr(aNameSpaceID, aAttribute, value);
     637                 :         }
     638                 : 
     639               0 :         if (attrPresent)
     640               0 :           realElement->SetAttr(dstNs, dstAttr, value, aNotify);
     641                 :       }
     642                 : 
     643                 :       // See if we're the <html> tag in XUL, and see if value is being
     644                 :       // set or unset on us.  We may also be a tag that is having
     645                 :       // xbl:text set on us.
     646                 : 
     647               0 :       if ((dstAttr == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
     648                 :           (realElement->NodeInfo()->Equals(nsGkAtoms::html,
     649               0 :                                            kNameSpaceID_XUL) &&
     650               0 :            dstAttr == nsGkAtoms::value)) {
     651                 :         // Flush out all our kids.
     652               0 :         PRUint32 childCount = realElement->GetChildCount();
     653               0 :         for (PRUint32 i = 0; i < childCount; i++)
     654               0 :           realElement->RemoveChildAt(0, aNotify);
     655                 : 
     656               0 :         if (!aRemoveFlag) {
     657                 :           // Construct a new text node and insert it.
     658               0 :           nsAutoString value;
     659               0 :           aChangedElement->GetAttr(aNameSpaceID, aAttribute, value);
     660               0 :           if (!value.IsEmpty()) {
     661               0 :             nsCOMPtr<nsIContent> textContent;
     662               0 :             NS_NewTextNode(getter_AddRefs(textContent),
     663               0 :                            realElement->NodeInfo()->NodeInfoManager());
     664               0 :             if (!textContent) {
     665               0 :               continue;
     666                 :             }
     667                 : 
     668               0 :             textContent->SetText(value, true);
     669               0 :             realElement->AppendChildTo(textContent, true);
     670                 :           }
     671                 :         }
     672                 :       }
     673                 :     }
     674                 : 
     675               0 :     xblAttr = xblAttr->GetNext();
     676                 :   }
     677                 : }
     678                 : 
     679                 : struct InsertionData {
     680                 :   nsXBLBinding* mBinding;
     681                 :   nsXBLPrototypeBinding* mPrototype;
     682                 : 
     683               0 :   InsertionData(nsXBLBinding* aBinding,
     684                 :                 nsXBLPrototypeBinding* aPrototype) 
     685               0 :     :mBinding(aBinding), mPrototype(aPrototype) {}
     686                 : };
     687                 : 
     688               0 : bool InstantiateInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
     689                 : {
     690               0 :   nsXBLInsertionPointEntry* entry = static_cast<nsXBLInsertionPointEntry*>(aData);
     691               0 :   InsertionData* data = static_cast<InsertionData*>(aClosure);
     692               0 :   nsXBLBinding* binding = data->mBinding;
     693               0 :   nsXBLPrototypeBinding* proto = data->mPrototype;
     694                 : 
     695                 :   // Get the insertion parent.
     696               0 :   nsIContent* content = entry->GetInsertionParent();
     697               0 :   PRUint32 index = entry->GetInsertionIndex();
     698               0 :   nsIContent* defContent = entry->GetDefaultContent();
     699                 : 
     700                 :   // Locate the real content.
     701               0 :   nsIContent *instanceRoot = binding->GetAnonymousContent();
     702               0 :   nsIContent *templRoot = proto->GetImmediateChild(nsGkAtoms::content);
     703                 :   nsIContent *realContent = proto->LocateInstance(nsnull, templRoot,
     704               0 :                                                   instanceRoot, content);
     705               0 :   if (!realContent)
     706               0 :     realContent = binding->GetBoundElement();
     707                 : 
     708                 :   // Now that we have the real content, look it up in our table.
     709               0 :   nsInsertionPointList* points = nsnull;
     710               0 :   binding->GetInsertionPointsFor(realContent, &points);
     711               0 :   nsXBLInsertionPoint* insertionPoint = nsnull;
     712               0 :   PRInt32 count = points->Length();
     713               0 :   PRInt32 i = 0;
     714               0 :   PRInt32 currIndex = 0;  
     715                 :   
     716               0 :   for ( ; i < count; i++) {
     717               0 :     nsXBLInsertionPoint* currPoint = points->ElementAt(i);
     718               0 :     currIndex = currPoint->GetInsertionIndex();
     719               0 :     if (currIndex == (PRInt32)index) {
     720                 :       // This is a match. Break out of the loop and set our variable.
     721               0 :       insertionPoint = currPoint;
     722               0 :       break;
     723                 :     }
     724                 :     
     725               0 :     if (currIndex > (PRInt32)index)
     726                 :       // There was no match. Break.
     727               0 :       break;
     728                 :   }
     729                 : 
     730               0 :   if (!insertionPoint) {
     731                 :     // We need to make a new insertion point.
     732               0 :     insertionPoint = new nsXBLInsertionPoint(realContent, index, defContent);
     733               0 :     if (insertionPoint) {
     734               0 :       points->InsertElementAt(i, insertionPoint);
     735                 :     }
     736                 :   }
     737                 : 
     738               0 :   return true;
     739                 : }
     740                 : 
     741                 : void
     742               0 : nsXBLPrototypeBinding::InstantiateInsertionPoints(nsXBLBinding* aBinding)
     743                 : {
     744               0 :   InsertionData data(aBinding, this);
     745               0 :   if (mInsertionPointTable)
     746               0 :     mInsertionPointTable->Enumerate(InstantiateInsertionPoint, &data);
     747               0 : }
     748                 : 
     749                 : nsIContent*
     750               0 : nsXBLPrototypeBinding::GetInsertionPoint(nsIContent* aBoundElement,
     751                 :                                          nsIContent* aCopyRoot,
     752                 :                                          const nsIContent* aChild,
     753                 :                                          PRUint32* aIndex)
     754                 : {
     755               0 :   if (!mInsertionPointTable)
     756               0 :     return nsnull;
     757                 : 
     758               0 :   nsISupportsKey key(aChild->Tag());
     759               0 :   nsXBLInsertionPointEntry* entry = static_cast<nsXBLInsertionPointEntry*>(mInsertionPointTable->Get(&key));
     760               0 :   if (!entry) {
     761               0 :     nsISupportsKey key2(nsGkAtoms::children);
     762               0 :     entry = static_cast<nsXBLInsertionPointEntry*>(mInsertionPointTable->Get(&key2));
     763                 :   }
     764                 : 
     765               0 :   nsIContent *realContent = nsnull;
     766               0 :   if (entry) {
     767               0 :     nsIContent* content = entry->GetInsertionParent();
     768               0 :     *aIndex = entry->GetInsertionIndex();
     769               0 :     nsIContent* templContent = GetImmediateChild(nsGkAtoms::content);
     770               0 :     realContent = LocateInstance(nsnull, templContent, aCopyRoot, content);
     771                 :   }
     772                 :   else {
     773                 :     // We got nothin'.  Bail.
     774               0 :     return nsnull;
     775                 :   }
     776                 : 
     777               0 :   return realContent ? realContent : aBoundElement;
     778                 : }
     779                 : 
     780                 : nsIContent*
     781               0 : nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
     782                 :                                                nsIContent* aCopyRoot,
     783                 :                                                PRUint32* aIndex,
     784                 :                                                bool* aMultipleInsertionPoints)
     785                 : { 
     786               0 :   *aMultipleInsertionPoints = false;
     787               0 :   *aIndex = 0;
     788                 : 
     789               0 :   if (!mInsertionPointTable)
     790               0 :     return nsnull;
     791                 : 
     792               0 :   if (mInsertionPointTable->Count() != 1) {
     793               0 :     *aMultipleInsertionPoints = true;
     794               0 :     return nsnull;
     795                 :   }
     796                 : 
     797               0 :   nsISupportsKey key(nsGkAtoms::children);
     798                 :   nsXBLInsertionPointEntry* entry =
     799               0 :     static_cast<nsXBLInsertionPointEntry*>(mInsertionPointTable->Get(&key));
     800                 : 
     801               0 :   if (!entry) {
     802                 :     // The only insertion point specified was actually a filtered insertion
     803                 :     // point. This means (strictly speaking) that we actually have multiple
     804                 :     // insertion points: the filtered one and a generic insertion point
     805                 :     // (content that doesn't match the filter will just go right underneath the
     806                 :     // bound element).
     807                 : 
     808               0 :     *aMultipleInsertionPoints = true;
     809               0 :     *aIndex = 0;
     810               0 :     return nsnull;
     811                 :   }
     812                 : 
     813               0 :   *aMultipleInsertionPoints = false;
     814               0 :   *aIndex = entry->GetInsertionIndex();
     815                 : 
     816               0 :   nsIContent* templContent = GetImmediateChild(nsGkAtoms::content);
     817               0 :   nsIContent* content = entry->GetInsertionParent();
     818                 :   nsIContent *realContent = LocateInstance(nsnull, templContent, aCopyRoot,
     819               0 :                                            content);
     820                 : 
     821               0 :   return realContent ? realContent : aBoundElement;
     822                 : }
     823                 : 
     824                 : void
     825               0 : nsXBLPrototypeBinding::SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)
     826                 : {
     827               0 :   mBaseNameSpaceID = aNamespaceID;
     828               0 :   mBaseTag = aTag;
     829               0 : }
     830                 : 
     831                 : nsIAtom*
     832               0 : nsXBLPrototypeBinding::GetBaseTag(PRInt32* aNamespaceID)
     833                 : {
     834               0 :   if (mBaseTag) {
     835               0 :     *aNamespaceID = mBaseNameSpaceID;
     836               0 :     return mBaseTag;
     837                 :   }
     838                 : 
     839               0 :   return nsnull;
     840                 : }
     841                 : 
     842                 : bool
     843               0 : nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID) const
     844                 : {
     845                 :   // Check our IID table.
     846               0 :   if (mInterfaceTable) {
     847               0 :     nsIIDKey key(aIID);
     848               0 :     nsCOMPtr<nsISupports> supports = getter_AddRefs(static_cast<nsISupports*>(mInterfaceTable->Get(&key)));
     849               0 :     return supports != nsnull;
     850                 :   }
     851                 : 
     852               0 :   return false;
     853                 : }
     854                 : 
     855                 : // Internal helpers ///////////////////////////////////////////////////////////////////////
     856                 : 
     857                 : nsIContent*
     858               0 : nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag)
     859                 : {
     860               0 :   for (nsIContent* child = mBinding->GetFirstChild();
     861                 :        child;
     862               0 :        child = child->GetNextSibling()) {
     863               0 :     if (child->NodeInfo()->Equals(aTag, kNameSpaceID_XBL)) {
     864               0 :       return child;
     865                 :     }
     866                 :   }
     867                 : 
     868               0 :   return nsnull;
     869                 : }
     870                 :  
     871                 : nsresult
     872               0 : nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
     873                 :                                  JSContext * aContext, JSObject * aGlobal,
     874                 :                                  JSObject * aScriptObject,
     875                 :                                  JSObject** aClassObject)
     876                 : {
     877               0 :   NS_ENSURE_ARG_POINTER(aClassObject); 
     878                 : 
     879               0 :   *aClassObject = nsnull;
     880                 : 
     881                 :   return nsXBLBinding::DoInitJSClass(aContext, aGlobal, aScriptObject,
     882               0 :                                      aClassName, this, aClassObject);
     883                 : }
     884                 : 
     885                 : nsIContent*
     886               0 : nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
     887                 :                                       nsIContent* aTemplRoot,
     888                 :                                       nsIContent* aCopyRoot, 
     889                 :                                       nsIContent* aTemplChild)
     890                 : {
     891                 :   // XXX We will get in trouble if the binding instantiation deviates from the template
     892                 :   // in the prototype.
     893               0 :   if (aTemplChild == aTemplRoot || !aTemplChild)
     894               0 :     return nsnull;
     895                 : 
     896               0 :   nsCOMPtr<nsIContent> templParent = aTemplChild->GetParent();
     897               0 :   nsCOMPtr<nsIContent> childPoint;
     898                 : 
     899                 :   // We may be disconnected from our parent during cycle collection.
     900               0 :   if (!templParent)
     901               0 :     return nsnull;
     902                 :   
     903               0 :   if (aBoundElement) {
     904               0 :     if (templParent->NodeInfo()->Equals(nsGkAtoms::children,
     905               0 :                                         kNameSpaceID_XBL)) {
     906               0 :       childPoint = templParent;
     907               0 :       templParent = childPoint->GetParent();
     908                 :     }
     909                 :   }
     910                 : 
     911               0 :   if (!templParent)
     912               0 :     return nsnull;
     913                 : 
     914               0 :   nsIContent* result = nsnull;
     915                 :   nsIContent *copyParent;
     916                 : 
     917               0 :   if (templParent == aTemplRoot)
     918               0 :     copyParent = aCopyRoot;
     919                 :   else
     920               0 :     copyParent = LocateInstance(aBoundElement, aTemplRoot, aCopyRoot, templParent);
     921                 :   
     922               0 :   if (childPoint && aBoundElement) {
     923                 :     // First we have to locate this insertion point and use its index and its
     924                 :     // count to detemine our precise position within the template.
     925               0 :     nsIDocument* doc = aBoundElement->OwnerDoc();
     926               0 :     nsXBLBinding *binding = doc->BindingManager()->GetBinding(aBoundElement);
     927               0 :     nsIContent *anonContent = nsnull;
     928                 : 
     929               0 :     while (binding) {
     930               0 :       anonContent = binding->GetAnonymousContent();
     931               0 :       if (anonContent)
     932               0 :         break;
     933                 : 
     934               0 :       binding = binding->GetBaseBinding();
     935                 :     }
     936                 : 
     937               0 :     NS_ABORT_IF_FALSE(binding, "Bug 620181 this is unexpected");
     938               0 :     if (!binding)
     939               0 :       return nsnull;
     940                 : 
     941               0 :     nsInsertionPointList* points = nsnull;
     942               0 :     if (anonContent == copyParent)
     943               0 :       binding->GetInsertionPointsFor(aBoundElement, &points);
     944                 :     else
     945               0 :       binding->GetInsertionPointsFor(copyParent, &points);
     946               0 :     PRInt32 count = points->Length();
     947               0 :     for (PRInt32 i = 0; i < count; i++) {
     948                 :       // Next we have to find the real insertion point for this proto insertion
     949                 :       // point.  If it does not contain any default content, then we should 
     950                 :       // return null, since the content is not in the clone.
     951               0 :       nsXBLInsertionPoint* currPoint = static_cast<nsXBLInsertionPoint*>(points->ElementAt(i));
     952               0 :       nsCOMPtr<nsIContent> defContent = currPoint->GetDefaultContentTemplate();
     953               0 :       if (defContent == childPoint) {
     954                 :         // Now check to see if we even built default content at this
     955                 :         // insertion point.
     956               0 :         defContent = currPoint->GetDefaultContent();
     957               0 :         if (defContent) {
     958                 :           // Find out the index of the template element within the <children> elt.
     959               0 :           PRInt32 index = childPoint->IndexOf(aTemplChild);
     960                 :           
     961                 :           // Now we just have to find the corresponding elt underneath the cloned
     962                 :           // default content.
     963               0 :           result = defContent->GetChildAt(index);
     964                 :         } 
     965                 :         break;
     966                 :       }
     967                 :     }
     968                 :   }
     969               0 :   else if (copyParent)
     970                 :   {
     971               0 :     PRInt32 index = templParent->IndexOf(aTemplChild);
     972               0 :     result = copyParent->GetChildAt(index);
     973                 :   }
     974                 : 
     975               0 :   return result;
     976                 : }
     977                 : 
     978                 : struct nsXBLAttrChangeData
     979                 : {
     980                 :   nsXBLPrototypeBinding* mProto;
     981                 :   nsIContent* mBoundElement;
     982                 :   nsIContent* mContent;
     983                 :   PRInt32 mSrcNamespace;
     984                 : 
     985               0 :   nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
     986                 :                       nsIContent* aElt, nsIContent* aContent) 
     987               0 :   :mProto(aProto), mBoundElement(aElt), mContent(aContent) {}
     988                 : };
     989                 : 
     990                 : // XXXbz this duplicates lots of AttributeChanged
     991               0 : bool SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
     992                 : {
     993               0 :   nsXBLAttributeEntry* entry = static_cast<nsXBLAttributeEntry*>(aData);
     994               0 :   nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
     995                 : 
     996               0 :   nsIAtom* src = entry->GetSrcAttribute();
     997               0 :   PRInt32 srcNs = changeData->mSrcNamespace;
     998               0 :   nsAutoString value;
     999               0 :   bool attrPresent = true;
    1000                 : 
    1001               0 :   if (src == nsGkAtoms::text && srcNs == kNameSpaceID_XBL) {
    1002                 :     nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false,
    1003               0 :                                        value);
    1004               0 :     value.StripChar(PRUnichar('\n'));
    1005               0 :     value.StripChar(PRUnichar('\r'));
    1006               0 :     nsAutoString stripVal(value);
    1007               0 :     stripVal.StripWhitespace();
    1008                 : 
    1009               0 :     if (stripVal.IsEmpty()) 
    1010               0 :       attrPresent = false;
    1011                 :   }
    1012                 :   else {
    1013               0 :     attrPresent = changeData->mBoundElement->GetAttr(srcNs, src, value);
    1014                 :   }
    1015                 : 
    1016               0 :   if (attrPresent) {
    1017                 :     nsIContent* content =
    1018               0 :       changeData->mProto->GetImmediateChild(nsGkAtoms::content);
    1019                 : 
    1020               0 :     nsXBLAttributeEntry* curr = entry;
    1021               0 :     while (curr) {
    1022               0 :       nsIAtom* dst = curr->GetDstAttribute();
    1023               0 :       PRInt32 dstNs = curr->GetDstNameSpace();
    1024               0 :       nsIContent* element = curr->GetElement();
    1025                 : 
    1026                 :       nsIContent *realElement =
    1027                 :         changeData->mProto->LocateInstance(changeData->mBoundElement, content,
    1028               0 :                                            changeData->mContent, element);
    1029                 : 
    1030               0 :       if (realElement) {
    1031               0 :         realElement->SetAttr(dstNs, dst, value, false);
    1032                 : 
    1033                 :         // XXXndeakin shouldn't this be done in lieu of SetAttr?
    1034               0 :         if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
    1035                 :             (realElement->NodeInfo()->Equals(nsGkAtoms::html,
    1036               0 :                                              kNameSpaceID_XUL) &&
    1037               0 :              dst == nsGkAtoms::value && !value.IsEmpty())) {
    1038                 : 
    1039               0 :           nsCOMPtr<nsIContent> textContent;
    1040               0 :           NS_NewTextNode(getter_AddRefs(textContent),
    1041               0 :                          realElement->NodeInfo()->NodeInfoManager());
    1042               0 :           if (!textContent) {
    1043               0 :             continue;
    1044                 :           }
    1045                 : 
    1046               0 :           textContent->SetText(value, false);
    1047               0 :           realElement->AppendChildTo(textContent, false);
    1048                 :         }
    1049                 :       }
    1050                 : 
    1051               0 :       curr = curr->GetNext();
    1052                 :     }
    1053                 :   }
    1054                 : 
    1055               0 :   return true;
    1056                 : }
    1057                 : 
    1058               0 : bool SetAttrsNS(nsHashKey* aKey, void* aData, void* aClosure)
    1059                 : {
    1060               0 :   if (aData && aClosure) {
    1061               0 :     nsPRUint32Key * key = static_cast<nsPRUint32Key*>(aKey);
    1062                 :     nsObjectHashtable* xblAttributes =
    1063               0 :       static_cast<nsObjectHashtable*>(aData);
    1064                 :     nsXBLAttrChangeData * changeData = static_cast<nsXBLAttrChangeData *>
    1065               0 :                                                   (aClosure);
    1066               0 :     changeData->mSrcNamespace = key->GetValue();
    1067               0 :     xblAttributes->Enumerate(SetAttrs, (void*)changeData);
    1068                 :   }
    1069               0 :   return true;
    1070                 : }
    1071                 : 
    1072                 : void
    1073               0 : nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
    1074                 : {
    1075               0 :   if (mAttributeTable) {
    1076               0 :     nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
    1077               0 :     mAttributeTable->Enumerate(SetAttrsNS, (void*)&data);
    1078                 :   }
    1079               0 : }
    1080                 : 
    1081                 : nsIStyleRuleProcessor*
    1082               0 : nsXBLPrototypeBinding::GetRuleProcessor()
    1083                 : {
    1084               0 :   if (mResources) {
    1085               0 :     return mResources->mRuleProcessor;
    1086                 :   }
    1087                 :   
    1088               0 :   return nsnull;
    1089                 : }
    1090                 : 
    1091                 : nsXBLPrototypeResources::sheet_array_type*
    1092               0 : nsXBLPrototypeBinding::GetStyleSheets()
    1093                 : {
    1094               0 :   if (mResources) {
    1095               0 :     return &mResources->mStyleSheetList;
    1096                 :   }
    1097                 : 
    1098               0 :   return nsnull;
    1099                 : }
    1100                 : 
    1101                 : static bool
    1102               0 : DeleteAttributeEntry(nsHashKey* aKey, void* aData, void* aClosure)
    1103                 : {
    1104               0 :   nsXBLAttributeEntry::Destroy(static_cast<nsXBLAttributeEntry*>(aData));
    1105               0 :   return true;
    1106                 : }
    1107                 : 
    1108                 : static bool
    1109               0 : DeleteAttributeTable(nsHashKey* aKey, void* aData, void* aClosure)
    1110                 : {
    1111               0 :   delete static_cast<nsObjectHashtable*>(aData);
    1112               0 :   return true;
    1113                 : }
    1114                 : 
    1115                 : void
    1116               0 : nsXBLPrototypeBinding::EnsureAttributeTable()
    1117                 : {
    1118               0 :   if (!mAttributeTable) {
    1119                 :     mAttributeTable = new nsObjectHashtable(nsnull, nsnull,
    1120                 :                                             DeleteAttributeTable,
    1121               0 :                                             nsnull, 4);
    1122                 :   }
    1123               0 : }
    1124                 : 
    1125                 : void
    1126               0 : nsXBLPrototypeBinding::AddToAttributeTable(PRInt32 aSourceNamespaceID, nsIAtom* aSourceTag,
    1127                 :                                            PRInt32 aDestNamespaceID, nsIAtom* aDestTag,
    1128                 :                                            nsIContent* aContent)
    1129                 : {
    1130               0 :     nsPRUint32Key nskey(aSourceNamespaceID);
    1131                 :     nsObjectHashtable* attributesNS =
    1132               0 :       static_cast<nsObjectHashtable*>(mAttributeTable->Get(&nskey));
    1133               0 :     if (!attributesNS) {
    1134                 :       attributesNS = new nsObjectHashtable(nsnull, nsnull,
    1135                 :                                            DeleteAttributeEntry,
    1136               0 :                                            nsnull, 4);
    1137               0 :       mAttributeTable->Put(&nskey, attributesNS);
    1138                 :     }
    1139                 :   
    1140                 :     nsXBLAttributeEntry* xblAttr =
    1141               0 :       nsXBLAttributeEntry::Create(aSourceTag, aDestTag, aDestNamespaceID, aContent);
    1142                 : 
    1143               0 :     nsISupportsKey key(aSourceTag);
    1144                 :     nsXBLAttributeEntry* entry = static_cast<nsXBLAttributeEntry*>
    1145               0 :                                             (attributesNS->Get(&key));
    1146               0 :     if (!entry) {
    1147               0 :       attributesNS->Put(&key, xblAttr);
    1148                 :     } else {
    1149               0 :       while (entry->GetNext())
    1150               0 :         entry = entry->GetNext();
    1151               0 :       entry->SetNext(xblAttr);
    1152                 :     }
    1153               0 : }
    1154                 : 
    1155                 : void
    1156               0 : nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
    1157                 : {
    1158                 :   // Don't add entries for <children> elements, since those will get
    1159                 :   // removed from the DOM when we construct the insertion point table.
    1160               0 :   if (!aElement->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
    1161               0 :     nsAutoString inherits;
    1162               0 :     aElement->GetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, inherits);
    1163                 : 
    1164               0 :     if (!inherits.IsEmpty()) {
    1165               0 :       EnsureAttributeTable();
    1166                 : 
    1167                 :       // The user specified at least one attribute.
    1168               0 :       char* str = ToNewCString(inherits);
    1169                 :       char* newStr;
    1170                 :       // XXX We should use a strtok function that tokenizes PRUnichars
    1171                 :       // so that we don't have to convert from Unicode to ASCII and then back
    1172                 : 
    1173               0 :       char* token = nsCRT::strtok( str, ", ", &newStr );
    1174               0 :       while( token != NULL ) {
    1175                 :         // Build an atom out of this attribute.
    1176               0 :         nsCOMPtr<nsIAtom> atom;
    1177               0 :         PRInt32 atomNsID = kNameSpaceID_None;
    1178               0 :         nsCOMPtr<nsIAtom> attribute;
    1179               0 :         PRInt32 attributeNsID = kNameSpaceID_None;
    1180                 : 
    1181                 :         // Figure out if this token contains a :.
    1182               0 :         nsAutoString attrTok; attrTok.AssignWithConversion(token);
    1183               0 :         PRInt32 index = attrTok.Find("=", true);
    1184                 :         nsresult rv;
    1185               0 :         if (index != -1) {
    1186                 :           // This attribute maps to something different.
    1187               0 :           nsAutoString left, right;
    1188               0 :           attrTok.Left(left, index);
    1189               0 :           attrTok.Right(right, attrTok.Length()-index-1);
    1190                 : 
    1191                 :           rv = nsContentUtils::SplitQName(aElement, left, &attributeNsID,
    1192               0 :                                           getter_AddRefs(attribute));
    1193               0 :           if (NS_FAILED(rv))
    1194                 :             return;
    1195                 : 
    1196                 :           rv = nsContentUtils::SplitQName(aElement, right, &atomNsID,
    1197               0 :                                           getter_AddRefs(atom));
    1198               0 :           if (NS_FAILED(rv))
    1199                 :             return;
    1200                 :         }
    1201                 :         else {
    1202               0 :           nsAutoString tok;
    1203               0 :           tok.AssignWithConversion(token);
    1204                 :           rv = nsContentUtils::SplitQName(aElement, tok, &atomNsID, 
    1205               0 :                                           getter_AddRefs(atom));
    1206               0 :           if (NS_FAILED(rv))
    1207                 :             return;
    1208               0 :           attribute = atom;
    1209               0 :           attributeNsID = atomNsID;
    1210                 :         }
    1211                 : 
    1212               0 :         AddToAttributeTable(atomNsID, atom, attributeNsID, attribute, aElement);
    1213                 : 
    1214                 :         // Now remove the inherits attribute from the element so that it doesn't
    1215                 :         // show up on clones of the element.  It is used
    1216                 :         // by the template only, and we don't need it anymore.
    1217                 :         // XXXdwh Don't do this for XUL elements, since it faults them into heavyweight
    1218                 :         // elements. Should nuke from the prototype instead.
    1219                 :         // aElement->UnsetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, false);
    1220                 : 
    1221               0 :         token = nsCRT::strtok( newStr, ", ", &newStr );
    1222                 :       }
    1223                 : 
    1224               0 :       nsMemory::Free(str);
    1225                 :     }
    1226                 :   }
    1227                 : 
    1228                 :   // Recur into our children.
    1229               0 :   for (nsIContent* child = aElement->GetFirstChild();
    1230                 :        child;
    1231               0 :        child = child->GetNextSibling()) {
    1232               0 :     ConstructAttributeTable(child);
    1233                 :   }
    1234                 : }
    1235                 : 
    1236                 : static bool
    1237               0 : DeleteInsertionPointEntry(nsHashKey* aKey, void* aData, void* aClosure)
    1238                 : {
    1239               0 :   static_cast<nsXBLInsertionPointEntry*>(aData)->Release();
    1240               0 :   return true;
    1241                 : }
    1242                 : 
    1243                 : void 
    1244               0 : nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
    1245                 : {
    1246               0 :   nsCOMArray<nsIContent> childrenElements;
    1247                 :   GetNestedChildren(nsGkAtoms::children, kNameSpaceID_XBL, aContent,
    1248               0 :                     childrenElements);
    1249                 : 
    1250               0 :   PRInt32 count = childrenElements.Count();
    1251               0 :   if (count == 0)
    1252                 :     return;
    1253                 : 
    1254                 :   mInsertionPointTable = new nsObjectHashtable(nsnull, nsnull,
    1255                 :                                                DeleteInsertionPointEntry,
    1256               0 :                                                nsnull, 4);
    1257               0 :   if (!mInsertionPointTable)
    1258                 :     return;
    1259                 : 
    1260                 :   PRInt32 i;
    1261               0 :   for (i = 0; i < count; i++) {
    1262               0 :     nsIContent* child = childrenElements[i];
    1263               0 :     nsCOMPtr<nsIContent> parent = child->GetParent(); 
    1264                 : 
    1265                 :     // Create an XBL insertion point entry.
    1266               0 :     nsXBLInsertionPointEntry* xblIns = nsXBLInsertionPointEntry::Create(parent);
    1267                 : 
    1268               0 :     nsAutoString includes;
    1269               0 :     child->GetAttr(kNameSpaceID_None, nsGkAtoms::includes, includes);
    1270               0 :     if (includes.IsEmpty()) {
    1271               0 :       nsISupportsKey key(nsGkAtoms::children);
    1272               0 :       xblIns->AddRef();
    1273               0 :       mInsertionPointTable->Put(&key, xblIns);
    1274                 :     }
    1275                 :     else {
    1276                 :       // The user specified at least one attribute.
    1277               0 :       char* str = ToNewCString(includes);
    1278                 :       char* newStr;
    1279                 :       // XXX We should use a strtok function that tokenizes PRUnichar's
    1280                 :       // so that we don't have to convert from Unicode to ASCII and then back
    1281                 : 
    1282               0 :       char* token = nsCRT::strtok( str, "| ", &newStr );
    1283               0 :       while( token != NULL ) {
    1284               0 :         nsAutoString tok;
    1285               0 :         tok.AssignWithConversion(token);
    1286                 : 
    1287                 :         // Build an atom out of this string.
    1288               0 :         nsCOMPtr<nsIAtom> atom = do_GetAtom(tok);
    1289                 : 
    1290               0 :         nsISupportsKey key(atom);
    1291               0 :         xblIns->AddRef();
    1292               0 :         mInsertionPointTable->Put(&key, xblIns);
    1293                 :           
    1294               0 :         token = nsCRT::strtok( newStr, "| ", &newStr );
    1295                 :       }
    1296                 : 
    1297               0 :       nsMemory::Free(str);
    1298                 :     }
    1299                 : 
    1300                 :     // Compute the index of the <children> element.  This index is
    1301                 :     // equal to the index of the <children> in the template minus the #
    1302                 :     // of previous insertion point siblings removed.  Because our childrenElements
    1303                 :     // array was built in a DFS that went from left-to-right through siblings,
    1304                 :     // if we dynamically obtain our index each time, then the removals of previous
    1305                 :     // siblings will cause the index to adjust (and we won't have to take that into
    1306                 :     // account explicitly).
    1307               0 :     PRInt32 index = parent->IndexOf(child);
    1308               0 :     xblIns->SetInsertionIndex((PRUint32)index);
    1309                 : 
    1310                 :     // Now remove the <children> element from the template.  This ensures that the
    1311                 :     // binding instantiation will not contain a clone of the <children> element when
    1312                 :     // it clones the binding template.
    1313               0 :     parent->RemoveChildAt(index, false);
    1314                 : 
    1315                 :     // See if the insertion point contains default content.  Default content must
    1316                 :     // be cached in our insertion point entry, since it will need to be cloned
    1317                 :     // in situations where no content ends up being placed at the insertion point.
    1318               0 :     PRUint32 defaultCount = child->GetChildCount();
    1319               0 :     if (defaultCount > 0) {
    1320               0 :       nsAutoScriptBlocker scriptBlocker;
    1321                 :       // Annotate the insertion point with our default content.
    1322               0 :       xblIns->SetDefaultContent(child);
    1323                 : 
    1324                 :       // Reconnect back to our parent for access later.  This makes "inherits" easier
    1325                 :       // to work with on default content.
    1326                 :       // XXXbz this is somewhat screwed up, since it's sort of like anonymous
    1327                 :       // content... but not.
    1328                 :       nsresult rv =
    1329               0 :         child->BindToTree(parent->GetCurrentDoc(), parent, nsnull, false);
    1330               0 :       if (NS_FAILED(rv)) {
    1331                 :         // Well... now what?  Just unbind and bail out, I guess...
    1332                 :         // XXXbz This really shouldn't be a void method!
    1333               0 :         child->UnbindFromTree();
    1334                 :         return;
    1335                 :       }
    1336                 :     }
    1337                 :   }
    1338                 : }
    1339                 : 
    1340                 : nsresult
    1341               0 : nsXBLPrototypeBinding::ConstructInterfaceTable(const nsAString& aImpls)
    1342                 : {
    1343               0 :   if (!aImpls.IsEmpty()) {
    1344                 :     // Obtain the interface info manager that can tell us the IID
    1345                 :     // for a given interface name.
    1346                 :     nsCOMPtr<nsIInterfaceInfoManager>
    1347               0 :       infoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
    1348               0 :     if (!infoManager)
    1349               0 :       return NS_ERROR_FAILURE;
    1350                 : 
    1351                 :     // Create the table.
    1352               0 :     if (!mInterfaceTable)
    1353               0 :       mInterfaceTable = new nsSupportsHashtable(4);
    1354                 : 
    1355                 :     // The user specified at least one attribute.
    1356               0 :     NS_ConvertUTF16toUTF8 utf8impl(aImpls);
    1357               0 :     char* str = utf8impl.BeginWriting();
    1358                 :     char* newStr;
    1359                 :     // XXX We should use a strtok function that tokenizes PRUnichars
    1360                 :     // so that we don't have to convert from Unicode to ASCII and then back
    1361                 : 
    1362               0 :     char* token = nsCRT::strtok( str, ", ", &newStr );
    1363               0 :     while( token != NULL ) {
    1364                 :       // get the InterfaceInfo for the name
    1365               0 :       nsCOMPtr<nsIInterfaceInfo> iinfo;
    1366               0 :       infoManager->GetInfoForName(token, getter_AddRefs(iinfo));
    1367                 : 
    1368               0 :       if (iinfo) {
    1369                 :         // obtain an IID.
    1370               0 :         const nsIID* iid = nsnull;
    1371               0 :         iinfo->GetIIDShared(&iid);
    1372                 : 
    1373               0 :         if (iid) {
    1374                 :           // We found a valid iid.  Add it to our table.
    1375               0 :           nsIIDKey key(*iid);
    1376               0 :           mInterfaceTable->Put(&key, mBinding);
    1377                 : 
    1378                 :           // this block adds the parent interfaces of each interface
    1379                 :           // defined in the xbl definition (implements="nsI...")
    1380               0 :           nsCOMPtr<nsIInterfaceInfo> parentInfo;
    1381                 :           // if it has a parent, add it to the table
    1382               0 :           while (NS_SUCCEEDED(iinfo->GetParent(getter_AddRefs(parentInfo))) && parentInfo) {
    1383                 :             // get the iid
    1384               0 :             parentInfo->GetIIDShared(&iid);
    1385                 : 
    1386                 :             // don't add nsISupports to the table
    1387               0 :             if (!iid || iid->Equals(NS_GET_IID(nsISupports)))
    1388               0 :               break;
    1389                 : 
    1390                 :             // add the iid to the table
    1391               0 :             nsIIDKey parentKey(*iid);
    1392               0 :             mInterfaceTable->Put(&parentKey, mBinding);
    1393                 : 
    1394                 :             // look for the next parent
    1395               0 :             iinfo = parentInfo;
    1396                 :           }
    1397                 :         }
    1398                 :       }
    1399                 : 
    1400               0 :       token = nsCRT::strtok( newStr, ", ", &newStr );
    1401                 :     }
    1402                 :   }
    1403                 : 
    1404               0 :   return NS_OK;
    1405                 : }
    1406                 : 
    1407                 : void
    1408               0 : nsXBLPrototypeBinding::GetNestedChildren(nsIAtom* aTag, PRInt32 aNamespace,
    1409                 :                                          nsIContent* aContent,
    1410                 :                                          nsCOMArray<nsIContent> & aList)
    1411                 : {
    1412               0 :   for (nsIContent* child = aContent->GetFirstChild();
    1413                 :        child;
    1414               0 :        child = child->GetNextSibling()) {
    1415                 : 
    1416               0 :     if (child->NodeInfo()->Equals(aTag, aNamespace)) {
    1417               0 :       aList.AppendObject(child);
    1418                 :     }
    1419                 :     else
    1420               0 :       GetNestedChildren(aTag, aNamespace, child, aList);
    1421                 :   }
    1422               0 : }
    1423                 : 
    1424                 : nsresult
    1425               0 : nsXBLPrototypeBinding::AddResourceListener(nsIContent* aBoundElement)
    1426                 : {
    1427               0 :   if (!mResources)
    1428               0 :     return NS_ERROR_FAILURE; // Makes no sense to add a listener when the binding
    1429                 :                              // has no resources.
    1430                 : 
    1431               0 :   mResources->AddResourceListener(aBoundElement);
    1432               0 :   return NS_OK;
    1433                 : }
    1434                 : 
    1435                 : void
    1436               0 : nsXBLPrototypeBinding::CreateKeyHandlers()
    1437                 : {
    1438               0 :   nsXBLPrototypeHandler* curr = mPrototypeHandler;
    1439               0 :   while (curr) {
    1440               0 :     nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
    1441               0 :     if (eventAtom == nsGkAtoms::keyup ||
    1442               0 :         eventAtom == nsGkAtoms::keydown ||
    1443               0 :         eventAtom == nsGkAtoms::keypress) {
    1444               0 :       PRUint8 phase = curr->GetPhase();
    1445               0 :       PRUint8 type = curr->GetType();
    1446                 : 
    1447               0 :       PRInt32 count = mKeyHandlers.Count();
    1448                 :       PRInt32 i;
    1449               0 :       nsXBLKeyEventHandler* handler = nsnull;
    1450               0 :       for (i = 0; i < count; ++i) {
    1451               0 :         handler = mKeyHandlers[i];
    1452               0 :         if (handler->Matches(eventAtom, phase, type))
    1453               0 :           break;
    1454                 :       }
    1455                 : 
    1456               0 :       if (i == count) {
    1457               0 :         nsRefPtr<nsXBLKeyEventHandler> newHandler;
    1458                 :         NS_NewXBLKeyEventHandler(eventAtom, phase, type,
    1459               0 :                                  getter_AddRefs(newHandler));
    1460               0 :         if (newHandler)
    1461               0 :           mKeyHandlers.AppendObject(newHandler);
    1462               0 :         handler = newHandler;
    1463                 :       }
    1464                 : 
    1465               0 :       if (handler)
    1466               0 :         handler->AddProtoHandler(curr);
    1467                 :     }
    1468                 : 
    1469               0 :     curr = curr->GetNextHandler();
    1470                 :   }
    1471               0 : }
    1472                 : 
    1473                 : class XBLPrototypeSetupCleanup
    1474                 : {
    1475                 : public:
    1476               0 :   XBLPrototypeSetupCleanup(nsXBLDocumentInfo* aDocInfo, const nsACString& aID)
    1477               0 :   : mDocInfo(aDocInfo), mID(aID) {}
    1478                 : 
    1479               0 :   ~XBLPrototypeSetupCleanup()
    1480               0 :   {
    1481               0 :     if (mDocInfo) {
    1482               0 :       mDocInfo->RemovePrototypeBinding(mID);
    1483                 :     }
    1484               0 :   }
    1485                 : 
    1486               0 :   void Disconnect()
    1487                 :   {
    1488               0 :     mDocInfo = nsnull;
    1489               0 :   }
    1490                 : 
    1491                 :   nsXBLDocumentInfo* mDocInfo;
    1492                 :   nsCAutoString mID;
    1493                 : };
    1494                 : 
    1495                 : nsresult
    1496               0 : nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
    1497                 :                             nsXBLDocumentInfo* aDocInfo,
    1498                 :                             nsIDocument* aDocument,
    1499                 :                             PRUint8 aFlags)
    1500                 : {
    1501               0 :   mInheritStyle = (aFlags & XBLBinding_Serialize_InheritStyle) ? true : false;
    1502                 : 
    1503                 :   // nsXBLContentSink::ConstructBinding doesn't create a binding with an empty
    1504                 :   // id, so we don't here either.
    1505               0 :   nsCAutoString id;
    1506               0 :   nsresult rv = aStream->ReadCString(id);
    1507                 : 
    1508               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1509               0 :   NS_ENSURE_TRUE(!id.IsEmpty(), NS_ERROR_FAILURE);
    1510                 : 
    1511               0 :   nsCAutoString baseBindingURI;
    1512               0 :   rv = aStream->ReadCString(baseBindingURI);
    1513               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1514               0 :   mCheckedBaseProto = true;
    1515                 : 
    1516               0 :   if (!baseBindingURI.IsEmpty()) {
    1517               0 :     rv = NS_NewURI(getter_AddRefs(mBaseBindingURI), baseBindingURI);
    1518               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1519                 :   }
    1520                 : 
    1521               0 :   rv = ReadNamespace(aStream, mBaseNameSpaceID);
    1522               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1523                 : 
    1524               0 :   nsAutoString baseTag;
    1525               0 :   rv = aStream->ReadString(baseTag);
    1526               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1527               0 :   if (!baseTag.IsEmpty()) {
    1528               0 :     mBaseTag = do_GetAtom(baseTag);
    1529                 :   }
    1530                 : 
    1531               0 :   aDocument->CreateElem(NS_LITERAL_STRING("binding"), nsnull, kNameSpaceID_XBL,
    1532               0 :                         getter_AddRefs(mBinding));
    1533                 : 
    1534               0 :   nsCOMPtr<nsIContent> child;
    1535               0 :   rv = ReadContentNode(aStream, aDocument, aDocument->NodeInfoManager(), getter_AddRefs(child));
    1536               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1537                 : 
    1538               0 :   Element* rootElement = aDocument->GetRootElement();
    1539               0 :   if (rootElement)
    1540               0 :     rootElement->AppendChildTo(mBinding, false);
    1541                 : 
    1542               0 :   if (child) {
    1543               0 :     mBinding->AppendChildTo(child, false);
    1544                 :   }
    1545                 : 
    1546                 :   PRUint32 interfaceCount;
    1547               0 :   rv = aStream->Read32(&interfaceCount);
    1548               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1549                 : 
    1550               0 :   if (interfaceCount > 0) {
    1551               0 :     NS_ASSERTION(!mInterfaceTable, "non-null mInterfaceTable");
    1552               0 :     mInterfaceTable = new nsSupportsHashtable(interfaceCount);
    1553               0 :     NS_ENSURE_TRUE(mInterfaceTable, NS_ERROR_OUT_OF_MEMORY);
    1554                 : 
    1555               0 :     for (; interfaceCount > 0; interfaceCount--) {
    1556                 :       nsIID iid;
    1557               0 :       aStream->ReadID(&iid);
    1558               0 :       nsIIDKey key(iid);
    1559               0 :       mInterfaceTable->Put(&key, mBinding);
    1560                 :     }
    1561                 :   }
    1562                 : 
    1563               0 :   nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner(do_QueryObject(aDocInfo));
    1564               0 :   nsIScriptGlobalObject* globalObject = globalOwner->GetScriptGlobalObject();
    1565               0 :   NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
    1566                 : 
    1567               0 :   nsIScriptContext *context = globalObject->GetContext();
    1568               0 :   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
    1569                 : 
    1570               0 :   bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding;
    1571               0 :   rv = Init(id, aDocInfo, nsnull, isFirstBinding);
    1572               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1573                 : 
    1574                 :   // We need to set the prototype binding before reading the nsXBLProtoImpl,
    1575                 :   // as it may be retrieved within.
    1576               0 :   rv = aDocInfo->SetPrototypeBinding(id, this);
    1577               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1578                 : 
    1579               0 :   XBLPrototypeSetupCleanup cleanup(aDocInfo, id);  
    1580                 : 
    1581               0 :   nsCAutoString className;
    1582               0 :   rv = aStream->ReadCString(className);
    1583               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1584                 : 
    1585               0 :   if (!className.IsEmpty()) {
    1586                 :     nsXBLProtoImpl* impl; // NS_NewXBLProtoImpl will set mImplementation for us
    1587               0 :     NS_NewXBLProtoImpl(this, NS_ConvertUTF8toUTF16(className).get(), &impl);
    1588                 : 
    1589                 :     // This needs to happen after SetPrototypeBinding as calls are made to
    1590                 :     // retrieve the mapped bindings from within here. However, if an error
    1591                 :     // occurs, the mapping should be removed again so that we don't keep an
    1592                 :     // invalid binding around.
    1593               0 :     rv = mImplementation->Read(context, aStream, this, globalObject);
    1594               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1595                 :   }
    1596                 : 
    1597                 :   // Next read in the handlers.
    1598               0 :   nsXBLPrototypeHandler* previousHandler = nsnull;
    1599                 : 
    1600               0 :   do {
    1601                 :     XBLBindingSerializeDetails type;
    1602               0 :     rv = aStream->Read8(&type);
    1603               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1604                 : 
    1605               0 :     if (type == XBLBinding_Serialize_NoMoreItems)
    1606               0 :       break;
    1607                 : 
    1608               0 :     NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Handler,
    1609                 :                  "invalid handler type");
    1610                 : 
    1611               0 :     nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(this);
    1612               0 :     rv = handler->Read(context, aStream);
    1613               0 :     if (NS_FAILED(rv)) {
    1614               0 :       delete handler;
    1615               0 :       return rv;
    1616                 :     }
    1617                 : 
    1618               0 :     if (previousHandler) {
    1619               0 :       previousHandler->SetNextHandler(handler);
    1620                 :     }
    1621                 :     else {
    1622               0 :       SetPrototypeHandlers(handler);
    1623                 :     }
    1624               0 :     previousHandler = handler;
    1625                 :   } while (1);
    1626                 : 
    1627                 :   // Finally, read in the resources.
    1628               0 :   do {
    1629                 :     XBLBindingSerializeDetails type;
    1630               0 :     rv = aStream->Read8(&type);
    1631               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1632                 : 
    1633               0 :     if (type == XBLBinding_Serialize_NoMoreItems)
    1634                 :       break;
    1635                 : 
    1636               0 :     NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Stylesheet ||
    1637                 :                  (type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Image, "invalid resource type");
    1638                 : 
    1639               0 :     nsAutoString src;
    1640               0 :     rv = aStream->ReadString(src);
    1641               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1642                 : 
    1643                 :     AddResource(type == XBLBinding_Serialize_Stylesheet ? nsGkAtoms::stylesheet :
    1644               0 :                                                           nsGkAtoms::image, src);
    1645                 :   } while (1);
    1646                 : 
    1647               0 :   if (isFirstBinding) {
    1648               0 :     aDocInfo->SetFirstPrototypeBinding(this);
    1649                 :   }
    1650                 : 
    1651               0 :   cleanup.Disconnect();
    1652               0 :   return NS_OK;
    1653                 : }
    1654                 : 
    1655                 : static
    1656                 : bool
    1657               0 : GatherInsertionPoints(nsHashKey *aKey, void *aData, void* aClosure)
    1658                 : {
    1659                 :   ArrayOfInsertionPointsByContent* insertionPointsByContent =
    1660               0 :     static_cast<ArrayOfInsertionPointsByContent *>(aClosure);
    1661                 : 
    1662               0 :   nsXBLInsertionPointEntry* entry = static_cast<nsXBLInsertionPointEntry *>(aData);
    1663                 : 
    1664                 :   // Add a new blank array if it isn't already there.
    1665                 :   nsAutoTArray<InsertionItem, 1>* list;
    1666               0 :   if (!insertionPointsByContent->Get(entry->GetInsertionParent(), &list)) {
    1667               0 :     list = new nsAutoTArray<InsertionItem, 1>;
    1668               0 :     insertionPointsByContent->Put(entry->GetInsertionParent(), list);
    1669                 :   }
    1670                 : 
    1671                 :   // Add the item to the array and ensure it stays sorted by insertion index.
    1672                 :   nsIAtom* atom = static_cast<nsIAtom *>(
    1673               0 :                     static_cast<nsISupportsKey *>(aKey)->GetValue());
    1674               0 :   InsertionItem newitem(entry->GetInsertionIndex(), atom, entry->GetDefaultContent());
    1675               0 :   list->InsertElementSorted(newitem);
    1676                 : 
    1677               0 :   return kHashEnumerateNext;
    1678                 : }
    1679                 : 
    1680                 : static
    1681                 : bool
    1682               0 : WriteInterfaceID(nsHashKey *aKey, void *aData, void* aClosure)
    1683                 : {
    1684                 :   // We can just write out the ids. The cache will be invalidated when a
    1685                 :   // different build is used, so we don't need to worry about ids changing.
    1686               0 :   nsID iid = ((nsIIDKey *)aKey)->mKey;
    1687               0 :   static_cast<nsIObjectOutputStream *>(aClosure)->WriteID(iid);
    1688               0 :   return kHashEnumerateNext;
    1689                 : }
    1690                 : 
    1691                 : nsresult
    1692               0 : nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
    1693                 : {
    1694                 :   // This writes out the binding. Note that mCheckedBaseProto,
    1695                 :   // mKeyHandlersRegistered and mKeyHandlers are not serialized as they are
    1696                 :   // computed on demand.
    1697                 : 
    1698               0 :   nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner(do_QueryObject(mXBLDocInfoWeak));
    1699               0 :   nsIScriptGlobalObject* globalObject = globalOwner->GetScriptGlobalObject();
    1700               0 :   NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
    1701                 : 
    1702               0 :   nsIScriptContext *context = globalObject->GetContext();
    1703               0 :   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
    1704                 : 
    1705               0 :   PRUint8 flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0;
    1706                 : 
    1707                 :   // mAlternateBindingURI is only set on the first binding.
    1708               0 :   if (mAlternateBindingURI) {
    1709               0 :     flags |= XBLBinding_Serialize_IsFirstBinding;
    1710                 :   }
    1711                 : 
    1712               0 :   nsresult rv = aStream->Write8(flags);
    1713               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1714                 : 
    1715               0 :   nsCAutoString id;
    1716               0 :   mBindingURI->GetRef(id);
    1717               0 :   rv = aStream->WriteStringZ(id.get());
    1718               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1719                 : 
    1720                 :   // write out the extends and display attribute values
    1721               0 :   nsCAutoString extends;
    1722               0 :   ResolveBaseBinding();
    1723               0 :   if (mBaseBindingURI)
    1724               0 :     mBaseBindingURI->GetSpec(extends);
    1725                 : 
    1726               0 :   rv = aStream->WriteStringZ(extends.get());
    1727               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1728                 : 
    1729               0 :   rv = WriteNamespace(aStream, mBaseNameSpaceID);
    1730               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1731                 : 
    1732               0 :   nsAutoString baseTag;
    1733               0 :   if (mBaseTag) {
    1734               0 :     mBaseTag->ToString(baseTag);
    1735                 :   }
    1736               0 :   rv = aStream->WriteWStringZ(baseTag.get());
    1737               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1738                 : 
    1739                 :   // The binding holds insertions points keyed by the tag that is going to be
    1740                 :   // inserted, however, the cache would prefer to know insertion points keyed
    1741                 :   // by where they are in the content hierarchy. GatherInsertionPoints is used
    1742                 :   // to iterate over the insertion points and store them temporarily in this
    1743                 :   // latter hashtable.
    1744               0 :   ArrayOfInsertionPointsByContent insertionPointsByContent;
    1745               0 :   insertionPointsByContent.Init();
    1746               0 :   if (mInsertionPointTable) {
    1747               0 :     mInsertionPointTable->Enumerate(GatherInsertionPoints, &insertionPointsByContent);
    1748                 :   }
    1749                 : 
    1750               0 :   nsIContent* content = GetImmediateChild(nsGkAtoms::content);
    1751               0 :   if (content) {
    1752               0 :     rv = WriteContentNode(aStream, content, insertionPointsByContent);
    1753               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1754                 :   }
    1755                 :   else {
    1756                 :     // Write a marker to indicate that there is no content.
    1757               0 :     rv = aStream->Write8(XBLBinding_Serialize_NoContent);
    1758               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1759                 :   }
    1760                 : 
    1761                 :   // Enumerate and write out the implemented interfaces.
    1762               0 :   if (mInterfaceTable) {
    1763               0 :     rv = aStream->Write32(mInterfaceTable->Count());
    1764               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1765                 : 
    1766               0 :     mInterfaceTable->Enumerate(WriteInterfaceID, aStream);
    1767                 :   }
    1768                 :   else {
    1769               0 :     rv = aStream->Write32(0);
    1770               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1771                 :   }
    1772                 : 
    1773                 :   // Write out the implementation details.
    1774               0 :   if (mImplementation) {
    1775               0 :     rv = mImplementation->Write(context, aStream, this);
    1776               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1777                 :   }
    1778                 :   else {
    1779                 :     // Write out an empty classname. This indicates that the binding does not
    1780                 :     // define an implementation.
    1781               0 :     rv = aStream->WriteWStringZ(EmptyString().get());
    1782               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1783                 :   }
    1784                 : 
    1785                 :   // Write out the handlers.
    1786               0 :   nsXBLPrototypeHandler* handler = mPrototypeHandler;
    1787               0 :   while (handler) {
    1788               0 :     rv = handler->Write(context, aStream);
    1789               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1790                 : 
    1791               0 :     handler = handler->GetNextHandler();
    1792                 :   }
    1793                 : 
    1794               0 :   aStream->Write8(XBLBinding_Serialize_NoMoreItems);
    1795               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1796                 : 
    1797                 :   // Write out the resources
    1798               0 :   if (mResources) {
    1799               0 :     rv = mResources->Write(aStream);
    1800               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1801                 :   }
    1802                 : 
    1803                 :   // Write out an end mark at the end.
    1804               0 :   return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
    1805                 : }
    1806                 : 
    1807                 : nsresult
    1808               0 : nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
    1809                 :                                        nsIDocument* aDocument,
    1810                 :                                        nsNodeInfoManager* aNim,
    1811                 :                                        nsIContent** aContent)
    1812                 : {
    1813               0 :   *aContent = nsnull;
    1814                 : 
    1815                 :   PRInt32 namespaceID;
    1816               0 :   nsresult rv = ReadNamespace(aStream, namespaceID);
    1817               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1818                 : 
    1819                 :   // There is no content to read so just return.
    1820               0 :   if (namespaceID == XBLBinding_Serialize_NoContent)
    1821               0 :     return NS_OK;
    1822                 : 
    1823               0 :   nsCOMPtr<nsIContent> content;
    1824                 : 
    1825                 :   // If this is a text type, just read the string and return.
    1826               0 :   if (namespaceID == XBLBinding_Serialize_TextNode ||
    1827                 :       namespaceID == XBLBinding_Serialize_CDATANode ||
    1828                 :       namespaceID == XBLBinding_Serialize_CommentNode) {
    1829               0 :     switch (namespaceID) {
    1830                 :       case XBLBinding_Serialize_TextNode:
    1831               0 :         rv = NS_NewTextNode(getter_AddRefs(content), aNim);
    1832               0 :         break;
    1833                 :       case XBLBinding_Serialize_CDATANode:
    1834               0 :         rv = NS_NewXMLCDATASection(getter_AddRefs(content), aNim);
    1835               0 :         break;
    1836                 :       case XBLBinding_Serialize_CommentNode:
    1837               0 :         rv = NS_NewCommentNode(getter_AddRefs(content), aNim);
    1838               0 :         break;
    1839                 :       default:
    1840               0 :         break;
    1841                 :     }
    1842               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1843                 : 
    1844               0 :     nsAutoString text;
    1845               0 :     rv = aStream->ReadString(text);
    1846               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1847                 : 
    1848               0 :     content->SetText(text, false);
    1849               0 :     content.swap(*aContent);
    1850               0 :     return NS_OK;
    1851                 :   }
    1852                 : 
    1853                 :   // Otherwise, it's an element, so read its tag, attributes and children.
    1854               0 :   nsAutoString prefix, tag;
    1855               0 :   rv = aStream->ReadString(prefix);
    1856               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1857                 : 
    1858               0 :   nsCOMPtr<nsIAtom> prefixAtom;
    1859               0 :   if (!prefix.IsEmpty())
    1860               0 :     prefixAtom = do_GetAtom(prefix);
    1861                 : 
    1862               0 :   rv = aStream->ReadString(tag);
    1863               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1864                 : 
    1865               0 :   nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(tag);
    1866                 :   nsCOMPtr<nsINodeInfo> nodeInfo =
    1867               0 :     aNim->GetNodeInfo(tagAtom, prefixAtom, namespaceID, nsIDOMNode::ELEMENT_NODE);
    1868                 : 
    1869                 :   PRUint32 attrCount;
    1870               0 :   rv = aStream->Read32(&attrCount);
    1871               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1872                 : 
    1873                 :   // Create XUL prototype elements, or regular elements for other namespaces.
    1874                 :   // This needs to match the code in nsXBLContentSink::CreateElement.
    1875                 : #ifdef MOZ_XUL
    1876               0 :   if (namespaceID == kNameSpaceID_XUL) {
    1877               0 :     nsIURI* documentURI = aDocument->GetDocumentURI();
    1878                 : 
    1879               0 :     nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
    1880               0 :     NS_ENSURE_TRUE(prototype, NS_ERROR_OUT_OF_MEMORY);
    1881                 : 
    1882               0 :     prototype->mNodeInfo = nodeInfo;
    1883               0 :     prototype->mScriptTypeID = nsIProgrammingLanguage::JAVASCRIPT;
    1884                 : 
    1885               0 :     nsCOMPtr<Element> result;
    1886                 :     nsresult rv =
    1887               0 :       nsXULElement::Create(prototype, aDocument, false, getter_AddRefs(result));
    1888               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1889               0 :     content = result;
    1890                 : 
    1891               0 :     nsXULPrototypeAttribute* attrs = nsnull;
    1892               0 :     if (attrCount > 0) {
    1893               0 :       attrs = new nsXULPrototypeAttribute[attrCount];
    1894                 :     }
    1895                 : 
    1896               0 :     prototype->mAttributes = attrs;
    1897               0 :     prototype->mNumAttributes = attrCount;
    1898                 : 
    1899               0 :     for (PRUint32 i = 0; i < attrCount; i++) {
    1900               0 :       rv = ReadNamespace(aStream, namespaceID);
    1901               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1902                 : 
    1903               0 :       nsAutoString prefix, name, val;
    1904               0 :       rv = aStream->ReadString(prefix);
    1905               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1906               0 :       rv = aStream->ReadString(name);
    1907               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1908               0 :       rv = aStream->ReadString(val);
    1909               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1910                 : 
    1911               0 :       nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name);
    1912               0 :       if (namespaceID == kNameSpaceID_None) {
    1913               0 :         attrs[i].mName.SetTo(nameAtom);
    1914                 :       }
    1915                 :       else {
    1916               0 :         nsCOMPtr<nsIAtom> prefixAtom;
    1917               0 :         if (!prefix.IsEmpty())
    1918               0 :           prefixAtom = do_GetAtom(prefix);
    1919                 : 
    1920                 :         nsCOMPtr<nsINodeInfo> ni =
    1921                 :           aNim->GetNodeInfo(nameAtom, prefixAtom,
    1922               0 :                             namespaceID, nsIDOMNode::ATTRIBUTE_NODE);
    1923               0 :         attrs[i].mName.SetTo(ni);
    1924                 :       }
    1925                 :       
    1926               0 :       rv = prototype->SetAttrAt(i, val, documentURI);
    1927               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1928                 :     }
    1929                 :   }
    1930                 :   else {
    1931                 : #endif
    1932               0 :     NS_NewElement(getter_AddRefs(content), nodeInfo.forget(), NOT_FROM_PARSER);
    1933                 : 
    1934               0 :     for (PRUint32 i = 0; i < attrCount; i++) {
    1935               0 :       rv = ReadNamespace(aStream, namespaceID);
    1936               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1937                 : 
    1938               0 :       nsAutoString prefix, name, val;
    1939               0 :       rv = aStream->ReadString(prefix);
    1940               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1941               0 :       rv = aStream->ReadString(name);
    1942               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1943               0 :       rv = aStream->ReadString(val);
    1944               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1945                 : 
    1946               0 :       nsCOMPtr<nsIAtom> prefixAtom;
    1947               0 :       if (!prefix.IsEmpty())
    1948               0 :         prefixAtom = do_GetAtom(prefix);
    1949                 : 
    1950               0 :       nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name);
    1951               0 :       content->SetAttr(namespaceID, nameAtom, prefixAtom, val, false);
    1952                 :     }
    1953                 : 
    1954                 : #ifdef MOZ_XUL
    1955                 :   }
    1956                 : #endif
    1957                 : 
    1958                 :   // Now read the attribute forwarding entries (xbl:inherits)
    1959                 : 
    1960                 :   PRInt32 srcNamespaceID, destNamespaceID;
    1961               0 :   rv = ReadNamespace(aStream, srcNamespaceID);
    1962               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1963                 : 
    1964               0 :   while (srcNamespaceID != XBLBinding_Serialize_NoMoreAttributes) {
    1965               0 :     nsAutoString srcAttribute, destAttribute;
    1966               0 :     rv = aStream->ReadString(srcAttribute);
    1967               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1968               0 :     rv = ReadNamespace(aStream, destNamespaceID);
    1969               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1970               0 :     rv = aStream->ReadString(destAttribute);
    1971               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1972                 : 
    1973               0 :     nsCOMPtr<nsIAtom> srcAtom = do_GetAtom(srcAttribute);
    1974               0 :     nsCOMPtr<nsIAtom> destAtom = do_GetAtom(destAttribute);
    1975                 : 
    1976               0 :     EnsureAttributeTable();
    1977               0 :     AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, content);
    1978                 : 
    1979               0 :     rv = ReadNamespace(aStream, srcNamespaceID);
    1980               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1981                 :   }
    1982                 : 
    1983                 :   // Next, read the insertion points.
    1984                 :   PRUint32 insertionPointIndex;
    1985               0 :   rv = aStream->Read32(&insertionPointIndex);
    1986               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1987               0 :   while (insertionPointIndex != XBLBinding_Serialize_NoMoreInsertionPoints) {
    1988                 :     nsRefPtr<nsXBLInsertionPointEntry> xblIns =
    1989               0 :       nsXBLInsertionPointEntry::Create(content);
    1990               0 :     xblIns->SetInsertionIndex(insertionPointIndex);
    1991                 : 
    1992                 :     // If the insertion point has default content, read it.
    1993               0 :     nsCOMPtr<nsIContent> defaultContent;
    1994               0 :     rv = ReadContentNode(aStream, aDocument, aNim, getter_AddRefs(defaultContent));
    1995               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1996                 : 
    1997               0 :     if (defaultContent) {
    1998               0 :       xblIns->SetDefaultContent(defaultContent);
    1999                 : 
    2000               0 :       rv = defaultContent->BindToTree(nsnull, content, nsnull, false);
    2001               0 :       if (NS_FAILED(rv)) {
    2002               0 :         defaultContent->UnbindFromTree();
    2003               0 :         return rv;
    2004                 :       }
    2005                 :     }
    2006                 : 
    2007               0 :     if (!mInsertionPointTable) {
    2008                 :       mInsertionPointTable = new nsObjectHashtable(nsnull, nsnull,
    2009                 :                                                    DeleteInsertionPointEntry,
    2010               0 :                                                    nsnull, 4);
    2011                 :     }
    2012                 : 
    2013                 :     // Now read in the tags that can be inserted at this point, which is
    2014                 :     // specified by the syntax includes="menupopup|panel", and add them to
    2015                 :     // the hash.
    2016                 :     PRUint32 count;
    2017               0 :     rv = aStream->Read32(&count);
    2018               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2019                 : 
    2020               0 :     for (; count > 0; count --) {
    2021               0 :       aStream->ReadString(tag);
    2022               0 :       nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(tag);
    2023                 : 
    2024               0 :       nsISupportsKey key(tagAtom);
    2025               0 :       NS_ADDREF(xblIns.get());
    2026               0 :       mInsertionPointTable->Put(&key, xblIns);
    2027                 :     }
    2028                 : 
    2029               0 :     rv = aStream->Read32(&insertionPointIndex);
    2030               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2031                 :   }
    2032                 : 
    2033                 :   // Finally, read in the child nodes.
    2034                 :   PRUint32 childCount;
    2035               0 :   rv = aStream->Read32(&childCount);
    2036               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2037                 : 
    2038               0 :   for (PRUint32 i = 0; i < childCount; i++) {
    2039               0 :     nsCOMPtr<nsIContent> child;
    2040               0 :     ReadContentNode(aStream, aDocument, aNim, getter_AddRefs(child));
    2041                 : 
    2042                 :     // Child may be null if this was a comment for example and can just be ignored.
    2043               0 :     if (child) {
    2044               0 :       content->AppendChildTo(child, false);
    2045                 :     }
    2046                 :   }
    2047                 : 
    2048               0 :   content.swap(*aContent);
    2049               0 :   return NS_OK;
    2050                 : }
    2051                 : 
    2052                 : // This structure holds information about a forwarded attribute that needs to be
    2053                 : // written out. This is used because we need several fields passed within the
    2054                 : // enumeration closure.
    2055                 : struct WriteAttributeData
    2056                 : {
    2057                 :   nsXBLPrototypeBinding* binding;
    2058                 :   nsIObjectOutputStream* stream;
    2059                 :   nsIContent* content;
    2060                 :   PRInt32 srcNamespace;
    2061                 : 
    2062               0 :   WriteAttributeData(nsXBLPrototypeBinding* aBinding,
    2063                 :                      nsIObjectOutputStream* aStream,
    2064                 :                      nsIContent* aContent)
    2065               0 :     : binding(aBinding), stream(aStream), content(aContent)
    2066               0 :   { }
    2067                 : };
    2068                 : 
    2069                 : static
    2070                 : bool
    2071               0 : WriteAttribute(nsHashKey *aKey, void *aData, void* aClosure)
    2072                 : {
    2073               0 :   WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
    2074               0 :   nsIObjectOutputStream* stream = data->stream;
    2075               0 :   const PRInt32 srcNamespace = data->srcNamespace;
    2076                 : 
    2077               0 :   nsXBLAttributeEntry* entry = static_cast<nsXBLAttributeEntry *>(aData);
    2078               0 :   do {
    2079               0 :     if (entry->GetElement() == data->content) {
    2080               0 :       data->binding->WriteNamespace(stream, srcNamespace);
    2081               0 :       stream->WriteWStringZ(nsDependentAtomString(entry->GetSrcAttribute()).get());
    2082               0 :       data->binding->WriteNamespace(stream, entry->GetDstNameSpace());
    2083               0 :       stream->WriteWStringZ(nsDependentAtomString(entry->GetDstAttribute()).get());
    2084                 :     }
    2085                 : 
    2086               0 :     entry = entry->GetNext();
    2087                 :   } while (entry);
    2088                 : 
    2089               0 :   return kHashEnumerateNext;
    2090                 : }
    2091                 : 
    2092                 : // WriteAttributeNS is the callback to enumerate over the attribute
    2093                 : // forwarding entries. Since these are stored in a hash of hashes,
    2094                 : // we need to iterate over the inner hashes, calling WriteAttribute
    2095                 : // to do the actual work.
    2096                 : static
    2097                 : bool
    2098               0 : WriteAttributeNS(nsHashKey *aKey, void *aData, void* aClosure)
    2099                 : {
    2100               0 :   WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
    2101               0 :   data->srcNamespace = static_cast<nsPRUint32Key *>(aKey)->GetValue();
    2102                 : 
    2103               0 :   nsObjectHashtable* attributes = static_cast<nsObjectHashtable*>(aData);
    2104               0 :   attributes->Enumerate(WriteAttribute, data);
    2105                 : 
    2106               0 :   return kHashEnumerateNext;
    2107                 : }
    2108                 : 
    2109                 : nsresult
    2110               0 : nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
    2111                 :                                         nsIContent* aNode,
    2112                 :                                         ArrayOfInsertionPointsByContent& aInsertionPointsByContent)
    2113                 : {
    2114                 :   nsresult rv;
    2115                 : 
    2116               0 :   if (!aNode->IsElement()) {
    2117                 :     // Text is writen out as a single byte for the type, followed by the text.
    2118               0 :     PRUint8 type = XBLBinding_Serialize_NoContent;
    2119               0 :     switch (aNode->NodeType()) {
    2120                 :       case nsIDOMNode::TEXT_NODE:
    2121               0 :         type = XBLBinding_Serialize_TextNode;
    2122               0 :         break;
    2123                 :       case nsIDOMNode::CDATA_SECTION_NODE:
    2124               0 :         type = XBLBinding_Serialize_CDATANode;
    2125               0 :         break;
    2126                 :       case nsIDOMNode::COMMENT_NODE:
    2127               0 :         type = XBLBinding_Serialize_CommentNode;
    2128               0 :         break;
    2129                 :       default:
    2130               0 :         break;
    2131                 :     }
    2132                 : 
    2133               0 :     rv = aStream->Write8(type);
    2134               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2135                 : 
    2136               0 :     nsAutoString content;
    2137               0 :     aNode->GetText()->AppendTo(content);
    2138               0 :     return aStream->WriteWStringZ(content.get());
    2139                 :   }
    2140                 : 
    2141                 :   // Otherwise, this is an element.
    2142                 : 
    2143                 :   // Write the namespace id followed by the tag name
    2144               0 :   rv = WriteNamespace(aStream, aNode->GetNameSpaceID());
    2145               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2146                 : 
    2147               0 :   nsAutoString prefixStr;
    2148               0 :   aNode->NodeInfo()->GetPrefix(prefixStr);
    2149               0 :   rv = aStream->WriteWStringZ(prefixStr.get());
    2150               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2151                 : 
    2152               0 :   rv = aStream->WriteWStringZ(nsDependentAtomString(aNode->Tag()).get());
    2153               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2154                 : 
    2155                 :   // Write attributes
    2156               0 :   PRUint32 count = aNode->GetAttrCount();
    2157               0 :   rv = aStream->Write32(count);
    2158               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2159                 : 
    2160                 :   PRUint32 i;
    2161               0 :   for (i = 0; i < count; i++) {
    2162                 :     // Write out the namespace id, the namespace prefix, the local tag name,
    2163                 :     // and the value, in that order.
    2164                 : 
    2165               0 :     const nsAttrName* attr = aNode->GetAttrNameAt(i);
    2166                 : 
    2167                 :     // XXXndeakin don't write out xbl:inherits?
    2168               0 :     PRInt32 namespaceID = attr->NamespaceID();
    2169               0 :     rv = WriteNamespace(aStream, namespaceID);
    2170               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2171                 : 
    2172               0 :     nsAutoString prefixStr;
    2173               0 :     nsIAtom* prefix = attr->GetPrefix();
    2174               0 :     if (prefix)
    2175               0 :       prefix->ToString(prefixStr);
    2176               0 :     rv = aStream->WriteWStringZ(prefixStr.get());
    2177               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2178                 : 
    2179               0 :     rv = aStream->WriteWStringZ(nsDependentAtomString(attr->LocalName()).get());
    2180               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2181                 : 
    2182               0 :     nsAutoString val;
    2183               0 :     aNode->GetAttr(attr->NamespaceID(), attr->LocalName(), val);
    2184               0 :     rv = aStream->WriteWStringZ(val.get());
    2185               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2186                 :   }
    2187                 : 
    2188                 :   // Write out the attribute fowarding information
    2189               0 :   if (mAttributeTable) {
    2190               0 :     WriteAttributeData data(this, aStream, aNode);
    2191               0 :     mAttributeTable->Enumerate(WriteAttributeNS, &data);
    2192                 :   }
    2193               0 :   rv = aStream->Write8(XBLBinding_Serialize_NoMoreAttributes);
    2194               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2195                 : 
    2196                 :   // Write out the insertion points.
    2197                 :   nsAutoTArray<InsertionItem, 1>* list;
    2198               0 :   if (aInsertionPointsByContent.Get(aNode, &list)) {
    2199               0 :     PRUint32 lastInsertionIndex = 0xFFFFFFFF;
    2200                 : 
    2201                 :     // Iterate over the insertion points and see if they match this point
    2202                 :     // in the content tree by comparing insertion indices.
    2203               0 :     for (PRUint32 l = 0; l < list->Length(); l++) {
    2204               0 :       InsertionItem item = list->ElementAt(l);
    2205                 :       // The list is sorted by insertionIndex so all items pertaining to
    2206                 :       // this point will be in the list in order. We only need to write out the
    2207                 :       // default content and the number of tags once for each index.
    2208               0 :       if (item.insertionIndex != lastInsertionIndex) {
    2209               0 :         lastInsertionIndex = item.insertionIndex;
    2210               0 :         aStream->Write32(item.insertionIndex);
    2211                 :         // If the insertion point has default content, write that out, or
    2212                 :         // write out XBLBinding_Serialize_NoContent if there isn't any.
    2213               0 :         if (item.defaultContent) {
    2214                 :           rv = WriteContentNode(aStream, item.defaultContent,
    2215               0 :                                 aInsertionPointsByContent);
    2216                 :         }
    2217                 :         else {
    2218               0 :           rv = aStream->Write8(XBLBinding_Serialize_NoContent);
    2219                 :         }
    2220               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2221                 : 
    2222                 :         // Determine how many insertion points share the same index, so that
    2223                 :         // the total count can be written out.
    2224               0 :         PRUint32 icount = 1;
    2225               0 :         for (PRUint32 i = l + 1; i < list->Length(); i++) {
    2226               0 :           if (list->ElementAt(i).insertionIndex != lastInsertionIndex)
    2227               0 :             break;
    2228               0 :           icount++;
    2229                 :         }
    2230                 : 
    2231               0 :         rv = aStream->Write32(icount);
    2232               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2233                 :       }
    2234                 : 
    2235               0 :       rv = aStream->WriteWStringZ(nsDependentAtomString(list->ElementAt(l).tag).get());
    2236               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2237                 :     }
    2238                 :   }
    2239                 : 
    2240                 :   // Write out an end marker after the insertion points. If there weren't
    2241                 :   // any, this will be all that is written out.
    2242               0 :   rv = aStream->Write32(XBLBinding_Serialize_NoMoreInsertionPoints);
    2243               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2244                 : 
    2245                 :   // Finally, write out the child nodes.
    2246               0 :   count = aNode->GetChildCount();
    2247               0 :   rv = aStream->Write32(count);
    2248               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2249                 : 
    2250               0 :   for (i = 0; i < count; i++) {
    2251               0 :     rv = WriteContentNode(aStream, aNode->GetChildAt(i), aInsertionPointsByContent);
    2252               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2253                 :   }
    2254                 : 
    2255               0 :   return NS_OK;
    2256                 : }
    2257                 : 
    2258                 : nsresult
    2259               0 : nsXBLPrototypeBinding::ReadNamespace(nsIObjectInputStream* aStream,
    2260                 :                                      PRInt32& aNameSpaceID)
    2261                 : {
    2262                 :   PRUint8 namespaceID;
    2263               0 :   nsresult rv = aStream->Read8(&namespaceID);
    2264               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2265                 : 
    2266               0 :   if (namespaceID == XBLBinding_Serialize_CustomNamespace) {
    2267               0 :     nsAutoString namesp;
    2268               0 :     rv = aStream->ReadString(namesp);
    2269               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2270                 :   
    2271               0 :     nsContentUtils::NameSpaceManager()->RegisterNameSpace(namesp, aNameSpaceID);
    2272                 :   }
    2273                 :   else {
    2274               0 :     aNameSpaceID = namespaceID;
    2275                 :   }
    2276                 : 
    2277               0 :   return NS_OK;
    2278                 : }
    2279                 : 
    2280                 : nsresult
    2281               0 : nsXBLPrototypeBinding::WriteNamespace(nsIObjectOutputStream* aStream,
    2282                 :                                       PRInt32 aNameSpaceID)
    2283                 : {
    2284                 :   // Namespaces are stored as a single byte id for well-known namespaces.
    2285                 :   // This saves time and space as other namespaces aren't very common in
    2286                 :   // XBL. If another namespace is used however, the namespace id will be
    2287                 :   // XBLBinding_Serialize_CustomNamespace and the string namespace written
    2288                 :   // out directly afterwards.
    2289                 :   nsresult rv;
    2290                 : 
    2291               0 :   if (aNameSpaceID <= kNameSpaceID_LastBuiltin) {
    2292               0 :     rv = aStream->Write8((PRInt8)aNameSpaceID);
    2293               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2294                 :   }
    2295                 :   else {
    2296               0 :     rv = aStream->Write8(XBLBinding_Serialize_CustomNamespace);
    2297               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2298                 :   
    2299               0 :     nsAutoString namesp;
    2300               0 :     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, namesp);
    2301               0 :     aStream->WriteWStringZ(namesp.get());
    2302                 :   }
    2303                 : 
    2304               0 :   return NS_OK;
    2305                 : }
    2306                 : 
    2307                 : 
    2308               0 : bool CheckTagNameWhiteList(PRInt32 aNameSpaceID, nsIAtom *aTagName)
    2309                 : {
    2310                 :   static nsIContent::AttrValuesArray kValidXULTagNames[] =  {
    2311                 :     &nsGkAtoms::autorepeatbutton, &nsGkAtoms::box, &nsGkAtoms::browser,
    2312                 :     &nsGkAtoms::button, &nsGkAtoms::hbox, &nsGkAtoms::image, &nsGkAtoms::menu,
    2313                 :     &nsGkAtoms::menubar, &nsGkAtoms::menuitem, &nsGkAtoms::menupopup,
    2314                 :     &nsGkAtoms::row, &nsGkAtoms::slider, &nsGkAtoms::spacer,
    2315                 :     &nsGkAtoms::splitter, &nsGkAtoms::text, &nsGkAtoms::tree, nsnull};
    2316                 : 
    2317                 :   PRUint32 i;
    2318               0 :   if (aNameSpaceID == kNameSpaceID_XUL) {
    2319               0 :     for (i = 0; kValidXULTagNames[i]; ++i) {
    2320               0 :       if (aTagName == *(kValidXULTagNames[i])) {
    2321               0 :         return true;
    2322                 :       }
    2323                 :     }
    2324                 :   }
    2325               0 :   else if (aNameSpaceID == kNameSpaceID_SVG &&
    2326                 :            aTagName == nsGkAtoms::generic) {
    2327               0 :     return true;
    2328                 :   }
    2329                 : 
    2330               0 :   return false;
    2331                 : }
    2332                 : 
    2333                 : nsresult
    2334               0 : nsXBLPrototypeBinding::ResolveBaseBinding()
    2335                 : {
    2336               0 :   if (mCheckedBaseProto)
    2337               0 :     return NS_OK;
    2338               0 :   mCheckedBaseProto = true;
    2339                 : 
    2340               0 :   nsCOMPtr<nsIDocument> doc = mXBLDocInfoWeak->GetDocument();
    2341                 : 
    2342                 :   // Check for the presence of 'extends' and 'display' attributes
    2343               0 :   nsAutoString display, extends;
    2344               0 :   mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::extends, extends);
    2345               0 :   if (extends.IsEmpty())
    2346               0 :     return NS_OK;
    2347                 : 
    2348               0 :   mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::display, display);
    2349               0 :   bool hasDisplay = !display.IsEmpty();
    2350                 : 
    2351               0 :   nsAutoString value(extends);
    2352                 :        
    2353                 :   // Now slice 'em up to see what we've got.
    2354               0 :   nsAutoString prefix;
    2355                 :   PRInt32 offset;
    2356               0 :   if (hasDisplay) {
    2357               0 :     offset = display.FindChar(':');
    2358               0 :     if (-1 != offset) {
    2359               0 :       display.Left(prefix, offset);
    2360               0 :       display.Cut(0, offset+1);
    2361                 :     }
    2362                 :   }
    2363                 :   else {
    2364               0 :     offset = extends.FindChar(':');
    2365               0 :     if (-1 != offset) {
    2366               0 :       extends.Left(prefix, offset);
    2367               0 :       extends.Cut(0, offset+1);
    2368               0 :       display = extends;
    2369                 :     }
    2370                 :   }
    2371                 : 
    2372               0 :   nsAutoString nameSpace;
    2373                 : 
    2374               0 :   if (!prefix.IsEmpty()) {
    2375               0 :     mBinding->LookupNamespaceURI(prefix, nameSpace);
    2376               0 :     if (!nameSpace.IsEmpty()) {
    2377                 :       PRInt32 nameSpaceID =
    2378               0 :         nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace);
    2379                 : 
    2380               0 :       nsCOMPtr<nsIAtom> tagName = do_GetAtom(display);
    2381                 :       // Check the white list
    2382               0 :       if (!CheckTagNameWhiteList(nameSpaceID, tagName)) {
    2383               0 :         const PRUnichar* params[] = { display.get() };
    2384                 :         nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
    2385                 :                                         "XBL", nsnull,
    2386                 :                                         nsContentUtils::eXBL_PROPERTIES,
    2387                 :                                        "InvalidExtendsBinding",
    2388                 :                                         params, ArrayLength(params),
    2389               0 :                                         doc->GetDocumentURI());
    2390               0 :         NS_ASSERTION(!nsXBLService::IsChromeOrResourceURI(doc->GetDocumentURI()),
    2391                 :                      "Invalid extends value");
    2392               0 :         return NS_ERROR_ILLEGAL_VALUE;
    2393                 :       }
    2394                 : 
    2395               0 :       SetBaseTag(nameSpaceID, tagName);
    2396                 :     }
    2397                 :   }
    2398                 : 
    2399               0 :   if (hasDisplay || nameSpace.IsEmpty()) {
    2400               0 :     mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, false);
    2401               0 :     mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::display, false);
    2402                 : 
    2403               0 :     return NS_NewURI(getter_AddRefs(mBaseBindingURI), value,
    2404               0 :                      doc->GetDocumentCharacterSet().get(),
    2405               0 :                      doc->GetDocBaseURI());
    2406                 :   }
    2407                 : 
    2408               0 :   return NS_OK;
    2409            4392 : }

Generated by: LCOV version 1.7