Back to index

lightning-sunbird  0.9+nobinonly
nsXBLBinding.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Brendan Eich (brendan@mozilla.org)
00024  *   Scott MacGregor (mscott@netscape.com)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsIAtom.h"
00042 #include "nsIXBLDocumentInfo.h"
00043 #include "nsIInputStream.h"
00044 #include "nsINameSpaceManager.h"
00045 #include "nsHashtable.h"
00046 #include "nsIURI.h"
00047 #include "nsIURL.h"
00048 #include "nsIDOMEventReceiver.h"
00049 #include "nsIChannel.h"
00050 #include "nsXPIDLString.h"
00051 #include "nsReadableUtils.h"
00052 #include "nsIParser.h"
00053 #include "nsParserCIID.h"
00054 #include "nsNetUtil.h"
00055 #include "plstr.h"
00056 #include "nsIContent.h"
00057 #include "nsIDocument.h"
00058 #include "nsContentUtils.h"
00059 #ifdef MOZ_XUL
00060 #include "nsIXULDocument.h"
00061 #endif
00062 #include "nsIXMLContentSink.h"
00063 #include "nsContentCID.h"
00064 #include "nsXMLDocument.h"
00065 #include "nsIDOMElement.h"
00066 #include "nsIDOMText.h"
00067 #include "nsSupportsArray.h"
00068 #include "jsapi.h"
00069 #include "nsXBLService.h"
00070 #include "nsXBLInsertionPoint.h"
00071 #include "nsIXPConnect.h"
00072 #include "nsIScriptContext.h"
00073 #include "nsCRT.h"
00074 
00075 // Event listeners
00076 #include "nsIEventListenerManager.h"
00077 #include "nsIDOMMouseListener.h"
00078 #include "nsIDOMMouseMotionListener.h"
00079 #include "nsIDOMLoadListener.h"
00080 #include "nsIDOMFocusListener.h"
00081 #include "nsIDOMPaintListener.h"
00082 #include "nsIDOMKeyListener.h"
00083 #include "nsIDOMFormListener.h"
00084 #include "nsIDOMXULListener.h"
00085 #include "nsIDOMDragListener.h"
00086 #include "nsIDOMMutationListener.h"
00087 #include "nsIDOMContextMenuListener.h"
00088 #include "nsIDOMEventGroup.h"
00089 
00090 #include "nsXBLAtoms.h"
00091 #include "nsXULAtoms.h"
00092 
00093 #include "nsIDOMAttr.h"
00094 #include "nsIDOMNamedNodeMap.h"
00095 
00096 #include "nsXBLPrototypeHandler.h"
00097 
00098 #include "nsXBLPrototypeBinding.h"
00099 #include "nsXBLBinding.h"
00100 #include "nsBindingManager.h"
00101 #include "nsIPrincipal.h"
00102 #include "nsIScriptSecurityManager.h"
00103 #include "nsIEventListenerManager.h"
00104 #include "nsGUIEvent.h"
00105 
00106 #include "prprf.h"
00107 
00108 nsresult NS_DOMClassInfo_PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
00109 
00110 // Helper classes
00111 
00112 /***********************************************************************/
00113 //
00114 // The JS class for XBLBinding
00115 //
00116 PR_STATIC_CALLBACK(void)
00117 XBLFinalize(JSContext *cx, JSObject *obj)
00118 {
00119   nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, ::JS_GetClass(cx, obj));
00120   c->Drop();
00121 }
00122 
00123 nsXBLJSClass::nsXBLJSClass(const nsAFlatCString& aClassName)
00124 {
00125   memset(this, 0, sizeof(nsXBLJSClass));
00126   next = prev = NS_STATIC_CAST(JSCList*, this);
00127   name = ToNewCString(aClassName);
00128   addProperty = delProperty = setProperty = getProperty = ::JS_PropertyStub;
00129   enumerate = ::JS_EnumerateStub;
00130   resolve = ::JS_ResolveStub;
00131   convert = ::JS_ConvertStub;
00132   finalize = XBLFinalize;
00133 }
00134 
00135 nsrefcnt
00136 nsXBLJSClass::Destroy()
00137 {
00138   NS_ASSERTION(next == prev && prev == NS_STATIC_CAST(JSCList*, this),
00139                "referenced nsXBLJSClass is on LRU list already!?");
00140 
00141   if (nsXBLService::gClassTable) {
00142     nsCStringKey key(name);
00143     (nsXBLService::gClassTable)->Remove(&key);
00144   }
00145 
00146   if (nsXBLService::gClassLRUListLength >= nsXBLService::gClassLRUListQuota) {
00147     // Over LRU list quota, just unhash and delete this class.
00148     delete this;
00149   } else {
00150     // Put this most-recently-used class on end of the LRU-sorted freelist.
00151     JSCList* mru = NS_STATIC_CAST(JSCList*, this);
00152     JS_APPEND_LINK(mru, &nsXBLService::gClassLRUList);
00153     nsXBLService::gClassLRUListLength++;
00154   }
00155 
00156   return 0;
00157 }
00158 
00159 // Implementation /////////////////////////////////////////////////////////////////
00160 
00161 // Constructors/Destructors
00162 nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
00163   : mPrototypeBinding(aBinding),
00164     mInsertionPointTable(nsnull),
00165     mIsStyleBinding(PR_TRUE),
00166     mMarkedForDeath(PR_FALSE)
00167 {
00168   NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
00169   // Grab a ref to the document info so the prototype binding won't die
00170   NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
00171 }
00172 
00173 
00174 nsXBLBinding::~nsXBLBinding(void)
00175 {
00176   delete mInsertionPointTable;
00177   nsIXBLDocumentInfo* info = mPrototypeBinding->XBLDocumentInfo();
00178   NS_RELEASE(info);
00179 }
00180 
00181 void
00182 nsXBLBinding::SetBaseBinding(nsXBLBinding* aBinding)
00183 {
00184   if (mNextBinding) {
00185     NS_ERROR("Base XBL binding is already defined!");
00186     return;
00187   }
00188 
00189   mNextBinding = aBinding; // Comptr handles rel/add
00190 }
00191 
00192 void
00193 nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement)
00194 {
00195   // We need to ensure two things.
00196   // (1) The anonymous content should be fooled into thinking it's in the bound
00197   // element's document, assuming that the bound element is in a document
00198   // Note that we don't change the current doc of aAnonParent here, since that
00199   // quite simply does not matter.  aAnonParent is just a way of keeping refs
00200   // to all its kids, which are anonymous content from the point of view of
00201   // aElement.
00202   // (2) The children's parent back pointer should not be to this synthetic root
00203   // but should instead point to the enclosing parent element.
00204   nsIDocument* doc = aElement->GetCurrentDoc();
00205   PRBool allowScripts = AllowScripts();
00206 
00207   PRUint32 childCount = aAnonParent->GetChildCount();
00208   for (PRUint32 i = 0; i < childCount; i++) {
00209     nsIContent *child = aAnonParent->GetChildAt(i);
00210     child->UnbindFromTree();
00211     nsresult rv =
00212       child->BindToTree(doc, aElement, mBoundElement, allowScripts);
00213     if (NS_FAILED(rv)) {
00214       // Oh, well... Just give up.
00215       // XXXbz This really shouldn't be a void method!
00216       child->UnbindFromTree();
00217       return;
00218     }        
00219 
00220 #ifdef MOZ_XUL
00221     // To make XUL templates work (and other goodies that happen when
00222     // an element is added to a XUL document), we need to notify the
00223     // XUL document using its special API.
00224     nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(doc));
00225     if (xuldoc)
00226       xuldoc->AddSubtreeToDocument(child);
00227 #endif
00228   }
00229 }
00230 
00231 void
00232 nsXBLBinding::SetBoundElement(nsIContent* aElement)
00233 {
00234   mBoundElement = aElement;
00235   if (mNextBinding)
00236     mNextBinding->SetBoundElement(aElement);
00237 }
00238 
00239 nsXBLBinding*
00240 nsXBLBinding::GetFirstBindingWithConstructor()
00241 {
00242   if (mPrototypeBinding->GetConstructor())
00243     return this;
00244 
00245   if (mNextBinding)
00246     return mNextBinding->GetFirstBindingWithConstructor();
00247 
00248   return nsnull;
00249 }
00250 
00251 PRBool
00252 nsXBLBinding::HasStyleSheets() const
00253 {
00254   // Find out if we need to re-resolve style.  We'll need to do this
00255   // if we have additional stylesheets in our binding document.
00256   if (mPrototypeBinding->HasStyleSheets())
00257     return PR_TRUE;
00258 
00259   return mNextBinding ? mNextBinding->HasStyleSheets() : PR_FALSE;
00260 }
00261 
00262 struct EnumData {
00263   nsXBLBinding* mBinding;
00264  
00265   EnumData(nsXBLBinding* aBinding)
00266     :mBinding(aBinding)
00267   {};
00268 };
00269 
00270 struct ContentListData : public EnumData {
00271   nsIBindingManager* mBindingManager;
00272 
00273   ContentListData(nsXBLBinding* aBinding, nsIBindingManager* aManager)
00274     :EnumData(aBinding), mBindingManager(aManager)
00275   {};
00276 };
00277 
00278 
00279 
00280 PR_STATIC_CALLBACK(PRBool)
00281 BuildContentLists(nsHashKey* aKey, void* aData, void* aClosure)
00282 {
00283   ContentListData* data = (ContentListData*)aClosure;
00284   nsIBindingManager* bm = data->mBindingManager;
00285   nsXBLBinding* binding = data->mBinding;
00286 
00287   nsIContent *boundElement = binding->GetBoundElement();
00288 
00289   nsVoidArray* arr = NS_STATIC_CAST(nsVoidArray*, aData);
00290   PRInt32 count = arr->Count();
00291   
00292   if (count == 0)
00293     return NS_OK;
00294 
00295   // XXX Could this array just be altered in place and passed directly to
00296   // SetContentListFor?  We'd save space if we could pull this off.
00297   nsVoidArray* contentList = new nsVoidArray();
00298 
00299   // Figure out the relevant content node.
00300   nsXBLInsertionPoint* currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(0));
00301   nsCOMPtr<nsIContent> parent = currPoint->GetInsertionParent();
00302   PRInt32 currIndex = currPoint->GetInsertionIndex();
00303 
00304   nsCOMPtr<nsIDOMNodeList> nodeList;
00305   if (parent == boundElement) {
00306     // We are altering anonymous nodes to accommodate insertion points.
00307     nodeList = binding->GetAnonymousNodes();
00308   }
00309   else {
00310     // We are altering the explicit content list of a node to accommodate insertion points.
00311     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(parent));
00312     node->GetChildNodes(getter_AddRefs(nodeList));
00313   }
00314 
00315   nsXBLInsertionPoint* pseudoPoint = nsnull;
00316   PRUint32 childCount;
00317   nodeList->GetLength(&childCount);
00318   PRInt32 j = 0;
00319 
00320   for (PRUint32 i = 0; i < childCount; i++) {
00321     nsCOMPtr<nsIDOMNode> node;
00322     nodeList->Item(i, getter_AddRefs(node));
00323     nsCOMPtr<nsIContent> child(do_QueryInterface(node));
00324     if (((PRInt32)i) == currIndex) {
00325       // Add the currPoint to the supports array.
00326       NS_IF_ADDREF(currPoint);
00327       contentList->AppendElement(currPoint);
00328 
00329       // Get the next real insertion point and update our currIndex.
00330       j++;
00331       if (j < count) {
00332         currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(j));
00333         currIndex = currPoint->GetInsertionIndex();
00334       }
00335 
00336       // Null out our current pseudo-point.
00337       pseudoPoint = nsnull;
00338     }
00339     
00340     if (!pseudoPoint) {
00341       pseudoPoint = new nsXBLInsertionPoint(parent, (PRUint32) -1, nsnull);
00342       if (pseudoPoint) {
00343         NS_ADDREF(pseudoPoint);
00344         contentList->AppendElement(pseudoPoint);
00345       }
00346     }
00347     if (pseudoPoint) {
00348       pseudoPoint->AddChild(child);
00349     }
00350   }
00351 
00352   // Add in all the remaining insertion points.
00353   for ( ; j < count; j++) {
00354     currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(j));
00355     NS_IF_ADDREF(currPoint);
00356     contentList->AppendElement(currPoint);
00357   }
00358   
00359   // Now set the content list using the binding manager,
00360   // If the bound element is the parent, then we alter the anonymous node list
00361   // instead.  This allows us to always maintain two distinct lists should
00362   // insertion points be nested into an inner binding.
00363   if (parent == boundElement)
00364     bm->SetAnonymousNodesFor(parent, contentList);
00365   else 
00366     bm->SetContentListFor(parent, contentList);
00367   return PR_TRUE;
00368 }
00369 
00370 PR_STATIC_CALLBACK(PRBool)
00371 RealizeDefaultContent(nsHashKey* aKey, void* aData, void* aClosure)
00372 {
00373   ContentListData* data = (ContentListData*)aClosure;
00374   nsIBindingManager* bm = data->mBindingManager;
00375   nsXBLBinding* binding = data->mBinding;
00376 
00377   nsVoidArray* arr = (nsVoidArray*)aData;
00378   PRInt32 count = arr->Count();
00379  
00380   for (PRInt32 i = 0; i < count; i++) {
00381     nsXBLInsertionPoint* currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(i));
00382     PRInt32 insCount = currPoint->ChildCount();
00383     
00384     if (insCount == 0) {
00385       nsCOMPtr<nsIContent> defContent = currPoint->GetDefaultContentTemplate();
00386       if (defContent) {
00387         // We need to take this template and use it to realize the
00388         // actual default content (through cloning).
00389         // Clone this insertion point element.
00390         nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(defContent));
00391         nsCOMPtr<nsIDOMNode> clonedNode;
00392         elt->CloneNode(PR_TRUE, getter_AddRefs(clonedNode));
00393 
00394         nsCOMPtr<nsIContent> insParent = currPoint->GetInsertionParent();
00395 
00396         // Now that we have the cloned content, install the default content as
00397         // if it were additional anonymous content.
00398         nsCOMPtr<nsIContent> clonedContent(do_QueryInterface(clonedNode));
00399         binding->InstallAnonymousContent(clonedContent, insParent);
00400 
00401         // Cache the clone so that it can be properly destroyed if/when our
00402         // other anonymous content is destroyed.
00403         currPoint->SetDefaultContent(clonedContent);
00404 
00405         // Now make sure the kids of the clone are added to the insertion point as
00406         // children.
00407         PRUint32 cloneKidCount = clonedContent->GetChildCount();
00408         for (PRUint32 k = 0; k < cloneKidCount; k++) {
00409           nsIContent *cloneChild = clonedContent->GetChildAt(k);
00410           bm->SetInsertionParent(cloneChild, insParent);
00411           currPoint->AddChild(cloneChild);
00412         }
00413       }
00414     }
00415   }
00416 
00417   return PR_TRUE;
00418 }
00419 
00420 PR_STATIC_CALLBACK(PRBool)
00421 ChangeDocumentForDefaultContent(nsHashKey* aKey, void* aData, void* aClosure)
00422 {
00423   nsVoidArray* arr = NS_STATIC_CAST(nsVoidArray*, aData);
00424   PRInt32 count = arr->Count();
00425   
00426   for (PRInt32 i = 0; i < count; i++) {
00427     nsXBLInsertionPoint* currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(i));
00428     nsCOMPtr<nsIContent> defContent = currPoint->GetDefaultContent();
00429     
00430     if (defContent)
00431       defContent->UnbindFromTree();
00432   }
00433 
00434   return PR_TRUE;
00435 }
00436 
00437 void
00438 nsXBLBinding::GenerateAnonymousContent()
00439 {
00440   // Fetch the content element for this binding.
00441   nsIContent* content =
00442     mPrototypeBinding->GetImmediateChild(nsXBLAtoms::content);
00443 
00444   if (!content) {
00445     // We have no anonymous content.
00446     if (mNextBinding)
00447       mNextBinding->GenerateAnonymousContent();
00448 
00449     return;
00450   }
00451      
00452   // Find out if we're really building kids or if we're just
00453   // using the attribute-setting shorthand hack.
00454   PRUint32 contentCount = content->GetChildCount();
00455 
00456   // Plan to build the content by default.
00457   PRBool hasContent = (contentCount > 0);
00458   PRBool hasInsertionPoints = mPrototypeBinding->HasInsertionPoints();
00459 
00460 #ifdef DEBUG
00461   // See if there's an includes attribute.
00462   nsAutoString includes;
00463   content->GetAttr(kNameSpaceID_None, nsXBLAtoms::includes, includes);
00464   if (!includes.IsEmpty()) {
00465     nsCAutoString id;
00466     mPrototypeBinding->GetID(id);
00467     nsCAutoString message("An XBL Binding with an id of ");
00468     message += id;
00469     message += " and found in the file ";
00470     nsCAutoString uri;
00471     mPrototypeBinding->DocURI()->GetSpec(uri);
00472     message += uri;
00473     message += " is still using the deprecated\n<content includes=\"\"> syntax! Use <children> instead!\n"; 
00474     NS_WARNING(message.get());
00475   }
00476 #endif
00477 
00478   if (hasContent || hasInsertionPoints) {
00479     nsIDocument* doc = mBoundElement->GetOwnerDoc();
00480 
00481     // XXX doc will be null if we're in the midst of paint suppression.
00482     if (! doc)
00483       return;
00484     
00485     nsIBindingManager *bindingManager = doc->BindingManager();
00486 
00487     nsCOMPtr<nsIDOMNodeList> children;
00488     bindingManager->GetContentListFor(mBoundElement, getter_AddRefs(children));
00489  
00490     nsCOMPtr<nsIDOMNode> node;
00491     nsCOMPtr<nsIContent> childContent;
00492     PRUint32 length;
00493     children->GetLength(&length);
00494     if (length > 0 && !hasInsertionPoints) {
00495       // There are children being placed underneath us, but we have no specified
00496       // insertion points, and therefore no place to put the kids.  Don't generate
00497       // anonymous content.
00498       // Special case template and observes.
00499       for (PRUint32 i = 0; i < length; i++) {
00500         children->Item(i, getter_AddRefs(node));
00501         childContent = do_QueryInterface(node);
00502 
00503         nsINodeInfo *ni = childContent->GetNodeInfo();
00504 
00505         if (!ni || (!ni->Equals(nsXULAtoms::observes, kNameSpaceID_XUL) &&
00506                     !ni->Equals(nsXULAtoms::templateAtom, kNameSpaceID_XUL))) {
00507           hasContent = PR_FALSE;
00508           break;
00509         }
00510       }
00511     }
00512 
00513     if (hasContent || hasInsertionPoints) {
00514       nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(content));
00515 
00516       nsCOMPtr<nsIDOMNode> clonedNode;
00517       domElement->CloneNode(PR_TRUE, getter_AddRefs(clonedNode));
00518   
00519       mContent = do_QueryInterface(clonedNode);
00520       InstallAnonymousContent(mContent, mBoundElement);
00521 
00522       if (hasInsertionPoints) {
00523         // Now check and see if we have a single insertion point 
00524         // or multiple insertion points.
00525       
00526         // Enumerate the prototype binding's insertion table to build
00527         // our table of instantiated insertion points.
00528         mPrototypeBinding->InstantiateInsertionPoints(this);
00529 
00530         // We now have our insertion point table constructed.  We
00531         // enumerate this table.  For each array of insertion points
00532         // bundled under the same content node, we generate a content
00533         // list.  In the case of the bound element, we generate a new
00534         // anonymous node list that will be used in place of the binding's
00535         // cached anonymous node list.
00536         ContentListData data(this, bindingManager);
00537         mInsertionPointTable->Enumerate(BuildContentLists, &data);
00538       
00539         // We need to place the children
00540         // at their respective insertion points.
00541         PRUint32 index = 0;
00542         PRBool multiplePoints = PR_FALSE;
00543         nsIContent *singlePoint = GetSingleInsertionPoint(&index,
00544                                                           &multiplePoints);
00545       
00546         if (children) {
00547           if (multiplePoints) {
00548             // We must walk the entire content list in order to determine where
00549             // each child belongs.
00550             children->GetLength(&length);
00551             for (PRUint32 i = 0; i < length; i++) {
00552               children->Item(i, getter_AddRefs(node));
00553               childContent = do_QueryInterface(node);
00554 
00555               // Now determine the insertion point in the prototype table.
00556               PRUint32 index;
00557               nsIContent *point = GetInsertionPoint(childContent, &index);
00558               bindingManager->SetInsertionParent(childContent, point);
00559 
00560               // Find the correct nsIXBLInsertion point in our table.
00561               nsVoidArray* arr;
00562               GetInsertionPointsFor(point, &arr);
00563               nsXBLInsertionPoint* insertionPoint = nsnull;
00564               PRInt32 arrCount = arr->Count();
00565               for (PRInt32 j = 0; j < arrCount; j++) {
00566                 insertionPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(j));
00567                 if (insertionPoint->Matches(point, index))
00568                   break;
00569                 insertionPoint = nsnull;
00570               }
00571 
00572               if (insertionPoint) 
00573                 insertionPoint->AddChild(childContent);
00574               else {
00575                 // We were unable to place this child.  All anonymous content
00576                 // should be thrown out.  Special-case template and observes.
00577 
00578                 nsINodeInfo *ni = childContent->GetNodeInfo();
00579 
00580                 if (!ni ||
00581                     (!ni->Equals(nsXULAtoms::observes, kNameSpaceID_XUL) &&
00582                      !ni->Equals(nsXULAtoms::templateAtom, kNameSpaceID_XUL))) {
00583                   // Kill all anonymous content.
00584                   mContent = nsnull;
00585                   bindingManager->SetContentListFor(mBoundElement, nsnull);
00586                   bindingManager->SetAnonymousNodesFor(mBoundElement, nsnull);
00587                   return;
00588                 }
00589               }
00590             }
00591           }
00592           else {
00593             // All of our children are shunted to this single insertion point.
00594             nsVoidArray* arr;
00595             GetInsertionPointsFor(singlePoint, &arr);
00596             nsXBLInsertionPoint* insertionPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(0));
00597         
00598             nsCOMPtr<nsIDOMNode> node;
00599             nsCOMPtr<nsIContent> content;
00600             PRUint32 length;
00601             children->GetLength(&length);
00602           
00603             for (PRUint32 i = 0; i < length; i++) {
00604               children->Item(i, getter_AddRefs(node));
00605               content = do_QueryInterface(node);
00606               bindingManager->SetInsertionParent(content, singlePoint);
00607               insertionPoint->AddChild(content);
00608             }
00609           }
00610         }
00611 
00612         // Now that all of our children have been added, we need to walk all of our
00613         // nsIXBLInsertion points to see if any of them have default content that
00614         // needs to be built.
00615         mInsertionPointTable->Enumerate(RealizeDefaultContent, &data);
00616       }
00617     }
00618 
00619     mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
00620   }
00621 
00622   // Always check the content element for potential attributes.
00623   // This shorthand hack always happens, even when we didn't
00624   // build anonymous content.
00625   PRUint32 length = content->GetAttrCount();
00626 
00627   PRInt32 namespaceID;
00628   nsCOMPtr<nsIAtom> name;
00629   nsCOMPtr<nsIAtom> prefix;
00630 
00631   for (PRUint32 i = 0; i < length; ++i) {
00632     content->GetAttrNameAt(i, &namespaceID, getter_AddRefs(name),
00633                            getter_AddRefs(prefix));
00634 
00635     if (name != nsXBLAtoms::includes) {
00636       nsAutoString value;
00637       mBoundElement->GetAttr(namespaceID, name, value);
00638       if (value.IsEmpty()) {
00639         nsAutoString value2;
00640         content->GetAttr(namespaceID, name, value2);
00641         mBoundElement->SetAttr(namespaceID, name, value2, PR_FALSE);
00642       }
00643     }
00644 
00645     // Conserve space by wiping the attributes off the clone.
00646     if (mContent)
00647       mContent->UnsetAttr(namespaceID, name, PR_FALSE);
00648   }
00649 }
00650 
00651 void
00652 nsXBLBinding::InstallEventHandlers()
00653 {
00654   // Don't install handlers if scripts aren't allowed.
00655   if (AllowScripts()) {
00656     // Fetch the handlers prototypes for this binding.
00657     nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
00658 
00659     if (handlerChain) {
00660       nsCOMPtr<nsIEventListenerManager> manager;
00661       mBoundElement->GetListenerManager(getter_AddRefs(manager));
00662       if (!manager)
00663         return;
00664 
00665       nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
00666 
00667       nsXBLPrototypeHandler* curr;
00668       for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
00669         // Fetch the event type.
00670         nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
00671         if (!eventAtom ||
00672             eventAtom == nsXBLAtoms::keyup ||
00673             eventAtom == nsXBLAtoms::keydown ||
00674             eventAtom == nsXBLAtoms::keypress)
00675           continue;
00676 
00677         nsAutoString type;
00678         eventAtom->ToString(type);
00679 
00680         // If this is a command, add it in the system event group, otherwise 
00681         // add it to the standard event group.
00682 
00683         // This is a weak ref. systemEventGroup above is already a
00684         // strong ref, so we are guaranteed it will not go away.
00685         nsIDOMEventGroup* eventGroup = nsnull;
00686         if (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
00687           if (!systemEventGroup)
00688             manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
00689           eventGroup = systemEventGroup;
00690         }
00691 
00692         nsXBLEventHandler* handler = curr->GetEventHandler();
00693         if (handler) {
00694           // Figure out if we're using capturing or not.
00695           PRInt32 flags = (curr->GetPhase() == NS_PHASE_CAPTURING) ?
00696             NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
00697 
00698           if (curr->AllowUntrustedEvents()) {
00699             flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
00700           }
00701 
00702           manager->AddEventListenerByType(handler, type, flags, eventGroup);
00703         }
00704       }
00705 
00706       const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
00707         mPrototypeBinding->GetKeyEventHandlers();
00708       PRInt32 i;
00709       for (i = 0; i < keyHandlers->Count(); ++i) {
00710         nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
00711 
00712         nsAutoString type;
00713         handler->GetEventName(type);
00714 
00715         // If this is a command, add it in the system event group, otherwise 
00716         // add it to the standard event group.
00717 
00718         // This is a weak ref. systemEventGroup above is already a
00719         // strong ref, so we are guaranteed it will not go away.
00720         nsIDOMEventGroup* eventGroup = nsnull;
00721         if (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
00722           if (!systemEventGroup)
00723             manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
00724           eventGroup = systemEventGroup;
00725         }
00726 
00727         // Figure out if we're using capturing or not.
00728         PRInt32 flags = (handler->GetPhase() == NS_PHASE_CAPTURING) ?
00729           NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
00730 
00731         // For key handlers we have to set NS_PRIV_EVENT_UNTRUSTED_PERMITTED flag.
00732         // Whether the handling of the event is allowed or not is handled in
00733         // nsXBLKeyEventHandler::HandleEvent
00734         flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
00735 
00736         manager->AddEventListenerByType(handler, type, flags, eventGroup);
00737       }
00738     }
00739   }
00740 
00741   if (mNextBinding)
00742     mNextBinding->InstallEventHandlers();
00743 }
00744 
00745 nsresult
00746 nsXBLBinding::InstallImplementation()
00747 {
00748   // Always install the base class properties first, so that
00749   // derived classes can reference the base class properties.
00750 
00751   if (mNextBinding) {
00752     nsresult rv = mNextBinding->InstallImplementation();
00753     NS_ENSURE_SUCCESS(rv, rv);
00754   }
00755   
00756   // iterate through each property in the prototype's list and install the property.
00757   if (AllowScripts())
00758     return mPrototypeBinding->InstallImplementation(mBoundElement);
00759 
00760   return NS_OK;
00761 }
00762 
00763 nsIAtom*
00764 nsXBLBinding::GetBaseTag(PRInt32* aNameSpaceID)
00765 {
00766   nsIAtom *tag = mPrototypeBinding->GetBaseTag(aNameSpaceID);
00767   if (!tag && mNextBinding)
00768     return mNextBinding->GetBaseTag(aNameSpaceID);
00769 
00770   return tag;
00771 }
00772 
00773 void
00774 nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID,
00775                                PRBool aRemoveFlag, PRBool aNotify)
00776 {
00777   // XXX Change if we ever allow multiple bindings in a chain to contribute anonymous content
00778   if (!mContent) {
00779     if (mNextBinding)
00780       mNextBinding->AttributeChanged(aAttribute, aNameSpaceID,
00781                                      aRemoveFlag, aNotify);
00782   } else {
00783     mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag,
00784                                         mBoundElement, mContent, aNotify);
00785   }
00786 }
00787 
00788 void
00789 nsXBLBinding::ExecuteAttachedHandler()
00790 {
00791   if (mNextBinding)
00792     mNextBinding->ExecuteAttachedHandler();
00793 
00794   if (AllowScripts())
00795     mPrototypeBinding->BindingAttached(mBoundElement);
00796 }
00797 
00798 void
00799 nsXBLBinding::ExecuteDetachedHandler()
00800 {
00801   if (AllowScripts())
00802     mPrototypeBinding->BindingDetached(mBoundElement);
00803 
00804   if (mNextBinding)
00805     mNextBinding->ExecuteDetachedHandler();
00806 }
00807 
00808 void
00809 nsXBLBinding::UnhookEventHandlers()
00810 {
00811   nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
00812 
00813   if (handlerChain) {
00814     nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(mBoundElement);
00815     nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(receiver);
00816     nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
00817 
00818     nsXBLPrototypeHandler* curr;
00819     for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
00820       nsXBLEventHandler* handler = curr->GetCachedEventHandler();
00821       if (handler) {
00822         nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
00823         if (!eventAtom ||
00824             eventAtom == nsXBLAtoms::keyup ||
00825             eventAtom == nsXBLAtoms::keydown ||
00826             eventAtom == nsXBLAtoms::keypress)
00827           continue;
00828 
00829         nsAutoString type;
00830         eventAtom->ToString(type);
00831 
00832         // Figure out if we're using capturing or not.
00833         PRBool useCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
00834 
00835         // If this is a command, remove it from the system event group, otherwise 
00836         // remove it from the standard event group.
00837 
00838         // This is a weak ref. systemEventGroup above is already a
00839         // strong ref, so we are guaranteed it will not go away.
00840         nsIDOMEventGroup* eventGroup = nsnull;
00841         if (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
00842           if (!systemEventGroup)
00843             receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
00844           eventGroup = systemEventGroup;
00845         }
00846 
00847         target->RemoveGroupedEventListener(type, handler, useCapture,
00848                                            eventGroup);
00849       }
00850     }
00851 
00852     const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
00853       mPrototypeBinding->GetKeyEventHandlers();
00854     PRInt32 i;
00855     for (i = 0; i < keyHandlers->Count(); ++i) {
00856       nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
00857 
00858       nsAutoString type;
00859       handler->GetEventName(type);
00860 
00861       // Figure out if we're using capturing or not.
00862       PRBool useCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
00863 
00864       // If this is a command, remove it from the system event group, otherwise 
00865       // remove it from the standard event group.
00866 
00867       // This is a weak ref. systemEventGroup above is already a
00868       // strong ref, so we are guaranteed it will not go away.
00869       nsIDOMEventGroup* eventGroup = nsnull;
00870       if (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
00871         if (!systemEventGroup)
00872           receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
00873         eventGroup = systemEventGroup;
00874       }
00875 
00876       target->RemoveGroupedEventListener(type, handler, useCapture,
00877                                          eventGroup);
00878     }
00879   }
00880 }
00881 
00882 void
00883 nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument)
00884 {
00885   if (aOldDocument != aNewDocument) {
00886     if (mNextBinding)
00887       mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
00888 
00889     // Only style bindings get their prototypes unhooked.
00890     if (mIsStyleBinding) {
00891       // Now the binding dies.  Unhook our prototypes.
00892       nsIContent* interfaceElement =
00893         mPrototypeBinding->GetImmediateChild(nsXBLAtoms::implementation);
00894 
00895       if (interfaceElement) { 
00896         nsIScriptGlobalObject *global = aOldDocument->GetScriptGlobalObject();
00897         if (global) {
00898           nsIScriptContext *context = global->GetContext();
00899           if (context) {
00900             JSContext *jscontext = (JSContext *)context->GetNativeContext();
00901  
00902             nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
00903             nsresult rv = nsContentUtils::XPConnect()->
00904               WrapNative(jscontext, global->GetGlobalJSObject(),
00905                          mBoundElement, NS_GET_IID(nsISupports),
00906                          getter_AddRefs(wrapper));
00907             if (NS_FAILED(rv))
00908               return;
00909 
00910             JSObject* scriptObject = nsnull;
00911             rv = wrapper->GetJSObject(&scriptObject);
00912             if (NS_FAILED(rv))
00913               return;
00914 
00915             // XXX Stay in sync! What if a layered binding has an
00916             // <interface>?!
00917 
00918             // XXX Sanity check to make sure our class name matches
00919             // Pull ourselves out of the proto chain.
00920             JSObject* ourProto = ::JS_GetPrototype(jscontext, scriptObject);
00921             if (ourProto)
00922             {
00923               JSObject* grandProto = ::JS_GetPrototype(jscontext, ourProto);
00924               ::JS_SetPrototype(jscontext, scriptObject, grandProto);
00925             }
00926 
00927             // Don't remove the reference from the document to the
00928             // wrapper here since it'll be removed by the element
00929             // itself when that's taken out of the document.
00930           }
00931         }
00932       }
00933     }
00934 
00935     // Update the anonymous content.
00936     nsIContent *anonymous = mContent;
00937     if (anonymous) {
00938       // Also kill the default content within all our insertion points.
00939       if (mInsertionPointTable)
00940         mInsertionPointTable->Enumerate(ChangeDocumentForDefaultContent,
00941                                         nsnull);
00942 
00943 #ifdef MOZ_XUL
00944       nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(aOldDocument));
00945 #endif
00946 
00947       anonymous->UnbindFromTree(); // Kill it.
00948 
00949 #ifdef MOZ_XUL
00950       // To make XUL templates work (and other XUL-specific stuff),
00951       // we'll need to notify it using its add & remove APIs. Grab the
00952       // interface now...
00953       if (xuldoc)
00954         xuldoc->RemoveSubtreeFromDocument(anonymous);
00955 #endif
00956     }
00957 
00958     // Make sure that henceforth we don't claim that mBoundElement's children
00959     // have insertion parents in the old document.
00960     nsIBindingManager* bindingManager = aOldDocument->BindingManager();
00961     for (PRUint32 i = mBoundElement->GetChildCount(); i > 0; --i) {
00962       NS_ASSERTION(mBoundElement->GetChildAt(i-1),
00963                    "Must have child at i for 0 <= i < GetChildCount()!");
00964       bindingManager->SetInsertionParent(mBoundElement->GetChildAt(i-1),
00965                                          nsnull);
00966     }
00967   }
00968 }
00969 
00970 PRBool
00971 nsXBLBinding::InheritsStyle() const
00972 {
00973   // XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
00974   // Most derived binding with anonymous content determines style inheritance for now.
00975 
00976   // XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
00977   if (mContent)
00978     return mPrototypeBinding->InheritsStyle();
00979   
00980   if (mNextBinding)
00981     return mNextBinding->InheritsStyle();
00982 
00983   return PR_TRUE;
00984 }
00985 
00986 void
00987 nsXBLBinding::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData)
00988 {
00989   if (mNextBinding)
00990     mNextBinding->WalkRules(aFunc, aData);
00991 
00992   nsIStyleRuleProcessor *rules = mPrototypeBinding->GetRuleProcessor();
00993   if (rules)
00994     (*aFunc)(rules, aData);
00995 }
00996 
00997 // Internal helper methods ////////////////////////////////////////////////////////////////
00998 
00999 // static
01000 nsresult
01001 nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
01002                             const nsAFlatCString& aClassName,
01003                             void **aClassObject)
01004 {
01005   // First ensure our JS class is initialized.
01006   jsval val;
01007   JSObject* proto;
01008 
01009   nsCAutoString className(aClassName);
01010   JSObject* parent_proto = nsnull;  // If we have an "obj" we can set this
01011   if (obj) {
01012     // Retrieve the current prototype of obj.
01013     parent_proto = ::JS_GetPrototype(cx, obj);
01014     if (parent_proto) {
01015       // We need to create a unique classname based on aClassName and
01016       // parent_proto.  Append a space (an invalid URI character) to ensure that
01017       // we don't have accidental collisions with the case when parent_proto is
01018       // null and aClassName ends in some bizarre numbers (yeah, it's unlikely).
01019       jsid parent_proto_id;
01020       if (!::JS_GetObjectId(cx, parent_proto, &parent_proto_id)) {
01021         // Probably OOM
01022         return NS_ERROR_OUT_OF_MEMORY;
01023       }
01024 
01025       // One space, maybe "0x", at most 16 chars (on a 64-bit system) of long,
01026       // and a null-terminator (which PR_snprintf ensures is there even if the
01027       // string representation of what we're printing does not fit in the buffer
01028       // provided).
01029       char buf[20];
01030       PR_snprintf(buf, sizeof(buf), " %lx", parent_proto_id);
01031       className.Append(buf);
01032     }
01033   }
01034 
01035   if ((!::JS_LookupPropertyWithFlags(cx, global, className.get(),
01036                                      JSRESOLVE_CLASSNAME,
01037                                      &val)) ||
01038       JSVAL_IS_PRIMITIVE(val)) {
01039     // We need to initialize the class.
01040 
01041     nsXBLJSClass* c;
01042     void* classObject;
01043     nsCStringKey key(className);
01044     classObject = (nsXBLService::gClassTable)->Get(&key);
01045 
01046     if (classObject) {
01047       c = NS_STATIC_CAST(nsXBLJSClass*, classObject);
01048 
01049       // If c is on the LRU list (i.e., not linked to itself), remove it now!
01050       JSCList* link = NS_STATIC_CAST(JSCList*, c);
01051       if (c->next != link) {
01052         JS_REMOVE_AND_INIT_LINK(link);
01053         nsXBLService::gClassLRUListLength--;
01054       }
01055     } else {
01056       if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) {
01057         // We need to create a struct for this class.
01058         c = new nsXBLJSClass(className);
01059 
01060         if (!c)
01061           return NS_ERROR_OUT_OF_MEMORY;
01062       } else {
01063         // Pull the least recently used class struct off the list.
01064         JSCList* lru = (nsXBLService::gClassLRUList).next;
01065         JS_REMOVE_AND_INIT_LINK(lru);
01066         nsXBLService::gClassLRUListLength--;
01067 
01068         // Remove any mapping from the old name to the class struct.
01069         c = NS_STATIC_CAST(nsXBLJSClass*, lru);
01070         nsCStringKey oldKey(c->name);
01071         (nsXBLService::gClassTable)->Remove(&oldKey);
01072 
01073         // Change the class name and we're done.
01074         nsMemory::Free((void*) c->name);
01075         c->name = ToNewCString(className);
01076       }
01077 
01078       // Add c to our table.
01079       (nsXBLService::gClassTable)->Put(&key, (void*)c);
01080     }
01081 
01082     // The prototype holds a strong reference to its class struct.
01083     c->Hold();
01084 
01085     // Make a new object prototyped by parent_proto and parented by global.
01086     proto = ::JS_InitClass(cx,                  // context
01087                            global,              // global object
01088                            parent_proto,        // parent proto 
01089                            c,                   // JSClass
01090                            nsnull,              // JSNative ctor
01091                            0,                   // ctor args
01092                            nsnull,              // proto props
01093                            nsnull,              // proto funcs
01094                            nsnull,              // ctor props (static)
01095                            nsnull);             // ctor funcs (static)
01096     if (!proto) {
01097       // This will happen if we're OOM or if the security manager
01098       // denies defining the new class...
01099 
01100       (nsXBLService::gClassTable)->Remove(&key);
01101 
01102       c->Drop();
01103 
01104       return NS_ERROR_OUT_OF_MEMORY;
01105     }
01106 
01107     *aClassObject = (void*)proto;
01108   }
01109   else {
01110     proto = JSVAL_TO_OBJECT(val);
01111   }
01112 
01113   if (obj) {
01114     // Set the prototype of our object to be the new class.
01115     if (!::JS_SetPrototype(cx, obj, proto)) {
01116       return NS_ERROR_FAILURE;
01117     }
01118   }
01119 
01120   return NS_OK;
01121 }
01122 
01123 
01124 nsresult
01125 nsXBLBinding::InitClass(const nsCString& aClassName,
01126                         nsIScriptContext* aContext, 
01127                         nsIDocument* aDocument, void** aScriptObject,
01128                         void** aClassObject)
01129 {
01130   *aClassObject = nsnull;
01131   *aScriptObject = nsnull;
01132 
01133   nsresult rv;
01134 
01135   // Obtain the bound element's current script object.
01136   JSContext* cx = (JSContext*)aContext->GetNativeContext();
01137 
01138   nsIDocument *ownerDoc = mBoundElement->GetOwnerDoc();
01139   nsIScriptGlobalObject *sgo;
01140 
01141   if (!ownerDoc || !(sgo = ownerDoc->GetScriptGlobalObject())) {
01142     NS_ERROR("Can't find global object for bound content!");
01143 
01144     return NS_ERROR_UNEXPECTED;
01145   }
01146 
01147   nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
01148   rv = nsContentUtils::XPConnect()->WrapNative(cx, sgo->GetGlobalJSObject(),
01149                                                mBoundElement,
01150                                                NS_GET_IID(nsISupports),
01151                                                getter_AddRefs(wrapper));
01152   NS_ENSURE_SUCCESS(rv, rv);
01153 
01154   JSObject* object = nsnull;
01155   rv = wrapper->GetJSObject(&object);
01156   NS_ENSURE_SUCCESS(rv, rv);
01157 
01158   *aScriptObject = object;
01159 
01160   // First ensure our JS class is initialized.
01161 
01162   rv = DoInitJSClass(cx, sgo->GetGlobalJSObject(), object, aClassName,
01163                      aClassObject);
01164   NS_ENSURE_SUCCESS(rv, rv);
01165 
01166   // Root mBoundElement so that it doesn't lose it's binding
01167   nsIDocument* doc = mBoundElement->GetOwnerDoc();
01168 
01169   if (doc) {
01170     nsCOMPtr<nsIXPConnectWrappedNative> native_wrapper =
01171       do_QueryInterface(wrapper);
01172 
01173     if (native_wrapper) {
01174       NS_DOMClassInfo_PreserveNodeWrapper(native_wrapper);
01175     }
01176   }
01177 
01178   return NS_OK;
01179 }
01180 
01181 nsresult
01182 nsXBLBinding::GetTextData(nsIContent *aParent, nsString& aResult)
01183 {
01184   aResult.Truncate(0);
01185 
01186   PRUint32 textCount = aParent->GetChildCount();
01187   nsAutoString answer;
01188   for (PRUint32 j = 0; j < textCount; j++) {
01189     // Get the child.
01190     nsCOMPtr<nsIDOMText> text(do_QueryInterface(aParent->GetChildAt(j)));
01191     if (text) {
01192       nsAutoString data;
01193       text->GetData(data);
01194       aResult += data;
01195     }
01196   }
01197   return NS_OK;
01198 }
01199 
01200 PRBool
01201 nsXBLBinding::AllowScripts()
01202 {
01203   PRBool result;
01204   mPrototypeBinding->GetAllowScripts(&result);
01205   if (!result) {
01206     return result;
01207   }
01208 
01209   // Nasty hack.  Use the JSContext of the bound node, since the
01210   // security manager API expects to get the docshell type from
01211   // that.  But use the nsIPrincipal of our document.
01212   nsIScriptSecurityManager* mgr = nsContentUtils::GetSecurityManager();
01213   if (!mgr) {
01214     return PR_FALSE;
01215   }
01216   
01217   nsIDocument* doc = mBoundElement->GetOwnerDoc();
01218   if (!doc) {
01219     return PR_FALSE;
01220   }
01221 
01222   nsIScriptGlobalObject* global = doc->GetScriptGlobalObject();
01223   if (!global) {
01224     return PR_FALSE;
01225   }
01226 
01227   nsCOMPtr<nsIScriptContext> context = global->GetContext();
01228   if (!context) {
01229     return PR_FALSE;
01230   }
01231   
01232   JSContext* cx = (JSContext*) context->GetNativeContext();
01233 
01234   nsCOMPtr<nsIDocument> ourDocument;
01235   mPrototypeBinding->XBLDocumentInfo()->GetDocument(getter_AddRefs(ourDocument));
01236   nsIPrincipal* principal = ourDocument->GetPrincipal();
01237   if (!principal) {
01238     return PR_FALSE;
01239   }
01240 
01241   PRBool canExecute;
01242   nsresult rv = mgr->CanExecuteScripts(cx, principal, &canExecute);
01243   return NS_SUCCEEDED(rv) && canExecute;
01244 }
01245 
01246 PR_STATIC_CALLBACK(PRBool)
01247 DeleteVoidArray(nsHashKey* aKey, void* aData, void* aClosure)
01248 {
01249   nsVoidArray* array = NS_STATIC_CAST(nsVoidArray*, aData);
01250   if (array) {
01251     array->EnumerateForwards(ReleaseInsertionPoint, nsnull);
01252     delete array;
01253   }
01254   return PR_TRUE;
01255 }
01256 
01257 nsresult
01258 nsXBLBinding::GetInsertionPointsFor(nsIContent* aParent, nsVoidArray** aResult)
01259 {
01260   if (!mInsertionPointTable) {
01261     mInsertionPointTable = new nsObjectHashtable(nsnull, nsnull,
01262                                                  DeleteVoidArray, nsnull, 4);
01263 
01264     NS_ENSURE_TRUE(mInsertionPointTable, NS_ERROR_OUT_OF_MEMORY);
01265   }
01266 
01267   nsISupportsKey key(aParent);
01268   *aResult = NS_STATIC_CAST(nsVoidArray*, mInsertionPointTable->Get(&key));
01269 
01270   if (!*aResult) {
01271     *aResult = new nsVoidArray();
01272     NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
01273     mInsertionPointTable->Put(&key, *aResult);
01274   }
01275 
01276   return NS_OK;
01277 }
01278 
01279 nsIContent*
01280 nsXBLBinding::GetInsertionPoint(nsIContent* aChild, PRUint32* aIndex)
01281 {
01282   if (mContent) {
01283     return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent,
01284                                                 aChild, aIndex);
01285   }
01286 
01287   if (mNextBinding)
01288     return mNextBinding->GetInsertionPoint(aChild, aIndex);
01289 
01290   return nsnull;
01291 }
01292 
01293 nsIContent*
01294 nsXBLBinding::GetSingleInsertionPoint(PRUint32* aIndex,
01295                                       PRBool* aMultipleInsertionPoints)
01296 {
01297   *aMultipleInsertionPoints = PR_FALSE;
01298   if (mContent) {
01299     return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, 
01300                                                       aIndex, 
01301                                                       aMultipleInsertionPoints);
01302   }
01303 
01304   if (mNextBinding)
01305     return mNextBinding->GetSingleInsertionPoint(aIndex,
01306                                                  aMultipleInsertionPoints);
01307 
01308   return nsnull;
01309 }
01310 
01311 nsXBLBinding*
01312 nsXBLBinding::RootBinding()
01313 {
01314   if (mNextBinding)
01315     return mNextBinding->RootBinding();
01316 
01317   return this;
01318 }
01319 
01320 nsXBLBinding*
01321 nsXBLBinding::GetFirstStyleBinding()
01322 {
01323   if (mIsStyleBinding)
01324     return this;
01325 
01326   return mNextBinding ? mNextBinding->GetFirstStyleBinding() : nsnull;
01327 }
01328 
01329 void
01330 nsXBLBinding::MarkForDeath()
01331 {
01332   mMarkedForDeath = PR_TRUE;
01333   ExecuteDetachedHandler();
01334 }
01335 
01336 PRBool
01337 nsXBLBinding::ImplementsInterface(REFNSIID aIID) const
01338 {
01339   return mPrototypeBinding->ImplementsInterface(aIID) ||
01340     (mNextBinding && mNextBinding->ImplementsInterface(aIID));
01341 }
01342 
01343 already_AddRefed<nsIDOMNodeList>
01344 nsXBLBinding::GetAnonymousNodes()
01345 {
01346   if (mContent) {
01347     nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
01348     nsIDOMNodeList *nodeList = nsnull;
01349     elt->GetChildNodes(&nodeList);
01350     return nodeList;
01351   }
01352 
01353   if (mNextBinding)
01354     return mNextBinding->GetAnonymousNodes();
01355 
01356   return nsnull;
01357 }
01358 
01359 PRBool
01360 nsXBLBinding::ShouldBuildChildFrames() const
01361 {
01362   if (mContent)
01363     return mPrototypeBinding->ShouldBuildChildFrames();
01364 
01365   if (mNextBinding) 
01366     return mNextBinding->ShouldBuildChildFrames();
01367 
01368   return PR_TRUE;
01369 }