Back to index

lightning-sunbird  0.9+nobinonly
nsXBLService.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  *   Original Author: David W. Hyatt (hyatt@netscape.com)
00024  *   - Brendan Eich (brendan@mozilla.org)
00025  *   - Mike Pinkerton (pinkerton@netscape.com)
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsCOMPtr.h"
00042 #include "nsNetUtil.h"
00043 #include "nsXBLService.h"
00044 #include "nsXBLWindowKeyHandler.h"
00045 #include "nsXBLWindowDragHandler.h"
00046 #include "nsIInputStream.h"
00047 #include "nsINameSpaceManager.h"
00048 #include "nsHashtable.h"
00049 #include "nsIURI.h"
00050 #include "nsIDOMElement.h"
00051 #include "nsIURL.h"
00052 #include "nsIChannel.h"
00053 #include "nsXPIDLString.h"
00054 #include "nsIParser.h"
00055 #include "nsParserCIID.h"
00056 #include "nsNetUtil.h"
00057 #include "plstr.h"
00058 #include "nsIContent.h"
00059 #include "nsIDOMElement.h"
00060 #include "nsIDocument.h"
00061 #include "nsIXMLContentSink.h"
00062 #include "nsContentCID.h"
00063 #include "nsXMLDocument.h"
00064 #include "nsHTMLAtoms.h"
00065 #include "nsSupportsArray.h"
00066 #include "nsITextContent.h"
00067 #include "nsIMemory.h"
00068 #include "nsIObserverService.h"
00069 #include "nsIDOMNodeList.h"
00070 #include "nsXBLContentSink.h"
00071 #include "nsXBLBinding.h"
00072 #include "nsXBLPrototypeBinding.h"
00073 #include "nsIXBLDocumentInfo.h"
00074 #include "nsXBLAtoms.h"
00075 #include "nsXULAtoms.h"
00076 #include "nsCRT.h"
00077 #include "nsContentUtils.h"
00078 #include "nsISyncLoadDOMService.h"
00079 #include "nsIDOM3Node.h"
00080 #include "nsContentPolicyUtils.h"
00081 
00082 #include "nsIPresShell.h"
00083 #include "nsIDocumentObserver.h"
00084 #include "nsFrameManager.h"
00085 #include "nsStyleContext.h"
00086 #include "nsIScriptSecurityManager.h"
00087 
00088 #ifdef MOZ_XUL
00089 #include "nsIXULPrototypeCache.h"
00090 #endif
00091 #include "nsIDOMLoadListener.h"
00092 #include "nsIDOMEventGroup.h"
00093 #include "nsDocument.h"
00094 
00095 // Static IIDs/CIDs. Try to minimize these.
00096 static NS_DEFINE_CID(kXMLDocumentCID,             NS_XMLDOCUMENT_CID);
00097 
00098 static PRBool IsChromeOrResourceURI(nsIURI* aURI)
00099 {
00100   PRBool isChrome = PR_FALSE;
00101   PRBool isResource = PR_FALSE;
00102   if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && 
00103       NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
00104       return (isChrome || isResource);
00105   return PR_FALSE;
00106 }
00107 
00108 // Individual binding requests.
00109 class nsXBLBindingRequest
00110 {
00111 public:
00112   nsCOMPtr<nsIURL> mBindingURL;
00113   nsCOMPtr<nsIContent> mBoundElement;
00114 
00115   static nsXBLBindingRequest*
00116   Create(nsFixedSizeAllocator& aPool, nsIURL* aURL, nsIContent* aBoundElement) {
00117     void* place = aPool.Alloc(sizeof(nsXBLBindingRequest));
00118     return place ? ::new (place) nsXBLBindingRequest(aURL, aBoundElement) : nsnull;
00119   }
00120 
00121   static void
00122   Destroy(nsFixedSizeAllocator& aPool, nsXBLBindingRequest* aRequest) {
00123     aRequest->~nsXBLBindingRequest();
00124     aPool.Free(aRequest, sizeof(*aRequest));
00125   }
00126 
00127   void DocumentLoaded(nsIDocument* aBindingDoc)
00128   {
00129     // We only need the document here to cause frame construction, so
00130     // we need the current doc, not the owner doc.
00131     nsIDocument* doc = mBoundElement->GetCurrentDoc();
00132     if (!doc)
00133       return;
00134 
00135     // Get the binding.
00136     PRBool ready = PR_FALSE;
00137     gXBLService->BindingReady(mBoundElement, mBindingURL, &ready);
00138 
00139     if (!ready)
00140       return;
00141 
00142     // XXX Deal with layered bindings.  For example, mBoundElement may be anonymous content.
00143     // Now do a ContentInserted notification to cause the frames to get installed finally,
00144     nsIContent* parent = mBoundElement->GetParent();
00145     PRInt32 index = 0;
00146     if (parent)
00147       index = parent->IndexOf(mBoundElement);
00148         
00149     // If |mBoundElement| is (in addition to having binding |mBinding|)
00150     // also a descendant of another element with binding |mBinding|,
00151     // then we might have just constructed it due to the
00152     // notification of its parent.  (We can know about both if the
00153     // binding loads were triggered from the DOM rather than frame
00154     // construction.)  So we have to check both whether the element
00155     // has a primary frame and whether it's in the undisplayed map
00156     // before sending a ContentInserted notification, or bad things
00157     // will happen.
00158     nsIPresShell *shell = doc->GetShellAt(0);
00159     if (shell) {
00160       nsIFrame* childFrame;
00161       shell->GetPrimaryFrameFor(mBoundElement, &childFrame);
00162       if (!childFrame) {
00163         // Check to see if it's in the undisplayed content map.
00164         nsStyleContext* sc =
00165           shell->FrameManager()->GetUndisplayedContent(mBoundElement);
00166 
00167         if (!sc) {
00168           nsCOMPtr<nsIDocumentObserver> obs(do_QueryInterface(shell));
00169           nsCOMPtr<nsIDocument> doc = shell->GetDocument();
00170           obs->BeginUpdate(doc, UPDATE_CONTENT_MODEL);
00171           obs->ContentInserted(doc, parent, mBoundElement, index);
00172           obs->EndUpdate(doc, UPDATE_CONTENT_MODEL);
00173         }
00174       }
00175     }
00176   }
00177 
00178   static nsIXBLService* gXBLService;
00179   static int gRefCnt;
00180 
00181 protected:
00182   nsXBLBindingRequest(nsIURL* aURL, nsIContent* aBoundElement)
00183     : mBindingURL(aURL),
00184       mBoundElement(aBoundElement)
00185   {
00186     gRefCnt++;
00187     if (gRefCnt == 1) {
00188       CallGetService("@mozilla.org/xbl;1", &gXBLService);
00189     }
00190   }
00191 
00192   ~nsXBLBindingRequest()
00193   {
00194     gRefCnt--;
00195     if (gRefCnt == 0) {
00196       NS_IF_RELEASE(gXBLService);
00197     }
00198   }
00199 
00200 private:
00201   // Hide so that only Create() and Destroy() can be used to
00202   // allocate and deallocate from the heap
00203   static void* operator new(size_t) CPP_THROW_NEW { return 0; }
00204   static void operator delete(void*, size_t) {}
00205 };
00206 
00207 static const size_t kBucketSizes[] = {
00208   sizeof(nsXBLBindingRequest)
00209 };
00210 
00211 static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
00212 static const PRInt32 kNumElements = 64;
00213 static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLBindingRequest))) * kNumElements;
00214 
00215 nsIXBLService* nsXBLBindingRequest::gXBLService = nsnull;
00216 int nsXBLBindingRequest::gRefCnt = 0;
00217 
00218 // nsXBLStreamListener, a helper class used for 
00219 // asynchronous parsing of URLs
00220 /* Header file */
00221 class nsXBLStreamListener : public nsIStreamListener, public nsIDOMLoadListener
00222 {
00223 public:
00224   NS_DECL_ISUPPORTS
00225   NS_DECL_NSISTREAMLISTENER
00226   NS_DECL_NSIREQUESTOBSERVER
00227 
00228   NS_IMETHOD Load(nsIDOMEvent* aEvent);
00229   NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent) { return NS_OK; }
00230   NS_IMETHOD Unload(nsIDOMEvent* aEvent) { return NS_OK; }
00231   NS_IMETHOD Abort(nsIDOMEvent* aEvent) { return NS_OK; }
00232   NS_IMETHOD Error(nsIDOMEvent* aEvent) { return NS_OK; }
00233   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
00234 
00235 #ifdef MOZ_XUL
00236   static nsIXULPrototypeCache* gXULCache;
00237   static PRInt32 gRefCnt;
00238 #endif
00239 
00240   nsXBLStreamListener(nsXBLService* aXBLService, nsIStreamListener* aInner, nsIDocument* aDocument, nsIDocument* aBindingDocument);
00241   virtual ~nsXBLStreamListener();
00242   
00243   void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); };
00244   PRBool HasRequest(nsIURI* aURI, nsIContent* aBoundElement);
00245 
00246 private:
00247   nsXBLService* mXBLService; // [WEAK]
00248 
00249   nsCOMPtr<nsIStreamListener> mInner;
00250   nsAutoVoidArray mBindingRequests;
00251   
00252   nsCOMPtr<nsIWeakReference> mDocument;
00253   nsCOMPtr<nsIDocument> mBindingDocument;
00254 };
00255 
00256 #ifdef MOZ_XUL
00257 nsIXULPrototypeCache* nsXBLStreamListener::gXULCache = nsnull;
00258 PRInt32 nsXBLStreamListener::gRefCnt = 0;
00259 #endif
00260 
00261 /* Implementation file */
00262 NS_IMPL_ISUPPORTS4(nsXBLStreamListener, nsIStreamListener, nsIRequestObserver, nsIDOMLoadListener, nsIDOMEventListener)
00263 
00264 nsXBLStreamListener::nsXBLStreamListener(nsXBLService* aXBLService,
00265                                          nsIStreamListener* aInner, nsIDocument* aDocument,
00266                                          nsIDocument* aBindingDocument)
00267 {
00268   /* member initializers and constructor code */
00269   mXBLService = aXBLService;
00270   mInner = aInner;
00271   mDocument = do_GetWeakReference(aDocument);
00272   mBindingDocument = aBindingDocument;
00273 #ifdef MOZ_XUL
00274   gRefCnt++;
00275   if (gRefCnt == 1) {
00276     nsresult rv = CallGetService("@mozilla.org/xul/xul-prototype-cache;1",
00277                                  &gXULCache);
00278     if (NS_FAILED(rv)) return;
00279   }
00280 #endif
00281 }
00282 
00283 nsXBLStreamListener::~nsXBLStreamListener()
00284 {
00285 #ifdef MOZ_XUL
00286   /* destructor code */
00287   gRefCnt--;
00288   if (gRefCnt == 0) {
00289     NS_IF_RELEASE(gXULCache);
00290   }
00291 #endif
00292 }
00293 
00294 NS_IMETHODIMP
00295 nsXBLStreamListener::OnDataAvailable(nsIRequest *request, nsISupports* aCtxt, nsIInputStream* aInStr, 
00296                                      PRUint32 aSourceOffset, PRUint32 aCount)
00297 {
00298   if (mInner)
00299     return mInner->OnDataAvailable(request, aCtxt, aInStr, aSourceOffset, aCount);
00300   return NS_ERROR_FAILURE;
00301 }
00302 
00303 NS_IMETHODIMP
00304 nsXBLStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aCtxt)
00305 {
00306   if (mInner)
00307     return mInner->OnStartRequest(request, aCtxt);
00308     
00309   return NS_ERROR_FAILURE;
00310 }
00311 
00312 NS_IMETHODIMP 
00313 nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aCtxt, nsresult aStatus)
00314 {
00315   nsresult rv = NS_OK;
00316   if (mInner) {
00317      rv = mInner->OnStopRequest(request, aCtxt, aStatus);
00318   }
00319 
00320   if (NS_FAILED(rv) || NS_FAILED(aStatus))
00321   {
00322     nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
00323     if (aChannel)
00324        {
00325       nsCOMPtr<nsIURI> channelURI;
00326       aChannel->GetURI(getter_AddRefs(channelURI));
00327       nsCAutoString str;
00328       channelURI->GetAsciiSpec(str);
00329       printf("Failed to load XBL document %s\n", str.get());
00330        }
00331 
00332     PRUint32 count = mBindingRequests.Count();
00333     for (PRUint32 i = 0; i < count; i++) {
00334       nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
00335       nsXBLBindingRequest::Destroy(mXBLService->mPool, req);
00336     }
00337 
00338     mBindingRequests.Clear();
00339     mDocument = nsnull;
00340     mBindingDocument = nsnull;
00341   }
00342 
00343   return rv;
00344 }
00345 
00346 PRBool
00347 nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt)
00348 {
00349   // XXX Could be more efficient.
00350   PRUint32 count = mBindingRequests.Count();
00351   for (PRUint32 i = 0; i < count; i++) {
00352     nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
00353     PRBool eq;
00354     if (req->mBoundElement == aElt &&
00355         NS_SUCCEEDED(req->mBindingURL->Equals(aURI, &eq)) && eq)
00356       return PR_TRUE;
00357   }
00358 
00359   return PR_FALSE;
00360 }
00361 
00362 nsresult
00363 nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
00364 {
00365   nsresult rv = NS_OK;
00366   PRUint32 i;
00367   PRUint32 count = mBindingRequests.Count();
00368   
00369   // See if we're still alive.
00370   nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
00371   if (!doc) {
00372     NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n");
00373   }
00374   else {
00375     // Clear script handling object on asynchronously loaded XBL documents.
00376     NS_STATIC_CAST(nsDocument*, NS_STATIC_CAST(nsIDocument*, doc.get()))->
00377       ClearScriptHandlingObject();
00378 
00379     // We have to do a flush prior to notification of the document load.
00380     // This has to happen since the HTML content sink can be holding on
00381     // to notifications related to our children (e.g., if you bind to the
00382     // <body> tag) that result in duplication of content.  
00383     // We need to get the sink's notifications flushed and then make the binding
00384     // ready.
00385     if (count > 0) {
00386       nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(0);
00387       nsIDocument* document = req->mBoundElement->GetCurrentDoc();
00388       if (document)
00389         document->FlushPendingNotifications(Flush_ContentAndNotify);
00390     }
00391 
00392     // Remove ourselves from the set of pending docs.
00393     nsIBindingManager *bindingManager = doc->BindingManager();
00394     nsIURI* documentURI = mBindingDocument->GetDocumentURI();
00395     bindingManager->RemoveLoadingDocListener(documentURI);
00396 
00397     if (!mBindingDocument->GetRootContent()) {
00398       NS_ERROR("*** XBL doc with no root element! Something went horribly wrong! ***");
00399       return NS_ERROR_FAILURE;
00400     }
00401 
00402     // Put our doc info in the doc table.
00403     nsCOMPtr<nsIXBLDocumentInfo> info;
00404     nsIBindingManager *xblDocBindingManager = mBindingDocument->BindingManager();
00405     xblDocBindingManager->GetXBLDocumentInfo(documentURI, getter_AddRefs(info));
00406     xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
00407     if (!info) {
00408       NS_ERROR("An XBL file is malformed.  Did you forget the XBL namespace on the bindings tag?");
00409       return NS_ERROR_FAILURE;
00410     }
00411 
00412     // If the doc is a chrome URI, then we put it into the XUL cache.
00413 #ifdef MOZ_XUL
00414     if (IsChromeOrResourceURI(documentURI)) {
00415       PRBool useXULCache;
00416       gXULCache->GetEnabled(&useXULCache);
00417       if (useXULCache)
00418         gXULCache->PutXBLDocumentInfo(info);
00419     }
00420 #endif
00421   
00422     bindingManager->PutXBLDocumentInfo(info);
00423 
00424     // Notify all pending requests that their bindings are
00425     // ready and can be installed.
00426     for (i = 0; i < count; i++) {
00427       nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
00428       req->DocumentLoaded(mBindingDocument);
00429     }
00430   }
00431   
00432   for (i = 0; i < count; i++) {
00433     nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
00434     nsXBLBindingRequest::Destroy(mXBLService->mPool, req);
00435   }
00436 
00437   nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mBindingDocument));
00438   rec->RemoveEventListener(NS_LITERAL_STRING("load"), (nsIDOMLoadListener*)this, PR_FALSE);
00439 
00440   mBindingRequests.Clear();
00441   mDocument = nsnull;
00442   mBindingDocument = nsnull;
00443 
00444   return rv;
00445 }
00446 
00447 // Implementation /////////////////////////////////////////////////////////////////
00448 
00449 // Static member variable initialization
00450 PRUint32 nsXBLService::gRefCnt = 0;
00451 #ifdef MOZ_XUL
00452 nsIXULPrototypeCache* nsXBLService::gXULCache = nsnull;
00453 #endif
00454  
00455 nsHashtable* nsXBLService::gClassTable = nsnull;
00456 
00457 JSCList  nsXBLService::gClassLRUList = JS_INIT_STATIC_CLIST(&nsXBLService::gClassLRUList);
00458 PRUint32 nsXBLService::gClassLRUListLength = 0;
00459 PRUint32 nsXBLService::gClassLRUListQuota = 64;
00460 
00461 // Enabled by default. Must be over-ridden to disable
00462 PRBool nsXBLService::gDisableChromeCache = PR_FALSE;
00463 static const char kDisableChromeCachePref[] = "nglayout.debug.disable_xul_cache";
00464 
00465 // Implement our nsISupports methods
00466 NS_IMPL_ISUPPORTS3(nsXBLService, nsIXBLService, nsIObserver, nsISupportsWeakReference)
00467 
00468 // Constructors/Destructors
00469 nsXBLService::nsXBLService(void)
00470 {
00471   mPool.Init("XBL Binding Requests", kBucketSizes, kNumBuckets, kInitialSize);
00472 
00473   gRefCnt++;
00474   if (gRefCnt == 1) {
00475     gClassTable = new nsHashtable();
00476 
00477 #ifdef MOZ_XUL
00478     // Find out if the XUL cache is on or off
00479     gDisableChromeCache = nsContentUtils::GetBoolPref(kDisableChromeCachePref,
00480                                                       gDisableChromeCache);
00481 
00482     CallGetService("@mozilla.org/xul/xul-prototype-cache;1", &gXULCache);
00483 #endif
00484   }
00485 }
00486 
00487 nsXBLService::~nsXBLService(void)
00488 {
00489   gRefCnt--;
00490   if (gRefCnt == 0) {
00491     // Walk the LRU list removing and deleting the nsXBLJSClasses.
00492     FlushMemory();
00493 
00494     // Any straggling nsXBLJSClass instances held by unfinalized JS objects
00495     // created for bindings will be deleted when those objects are finalized
00496     // (and not put on gClassLRUList, because length >= quota).
00497     gClassLRUListLength = gClassLRUListQuota = 0;
00498 
00499     // At this point, the only hash table entries should be for referenced
00500     // XBL class structs held by unfinalized JS binding objects.
00501     delete gClassTable;
00502     gClassTable = nsnull;
00503 
00504 #ifdef MOZ_XUL
00505     NS_IF_RELEASE(gXULCache);
00506 #endif
00507   }
00508 }
00509 
00510 // This function loads a particular XBL file and installs all of the bindings
00511 // onto the element.
00512 NS_IMETHODIMP
00513 nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL, PRBool aAugmentFlag,
00514                            nsXBLBinding** aBinding, PRBool* aResolveStyle) 
00515 { 
00516   *aBinding = nsnull;
00517   *aResolveStyle = PR_FALSE;
00518 
00519   nsresult rv;
00520 
00521   nsCOMPtr<nsIDocument> document = aContent->GetOwnerDoc();
00522 
00523   // XXX document may be null if we're in the midst of paint suppression
00524   if (!document)
00525     return NS_OK;
00526 
00527   nsIBindingManager *bindingManager = document->BindingManager();
00528   
00529   nsXBLBinding *binding = bindingManager->GetBinding(aContent);
00530   if (binding && !aAugmentFlag) {
00531     nsXBLBinding *styleBinding = binding->GetFirstStyleBinding();
00532     if (styleBinding) {
00533       if (binding->MarkedForDeath()) {
00534         FlushStyleBindings(aContent);
00535         binding = nsnull;
00536       }
00537       else {
00538         // See if the URIs match.
00539         nsIURI* uri = styleBinding->PrototypeBinding()->BindingURI();
00540         PRBool equal;
00541         if (NS_SUCCEEDED(uri->Equals(aURL, &equal)) && equal)
00542           return NS_OK;
00543         FlushStyleBindings(aContent);
00544         binding = nsnull;
00545       }
00546     }
00547   }
00548 
00549   // Security check - remote pages can't load local bindings, except from chrome
00550   nsIURI *docURI = document->GetDocumentURI();
00551   PRBool isChrome = PR_FALSE;
00552   rv = docURI->SchemeIs("chrome", &isChrome);
00553 
00554   // Not everything with a chrome URI has a system principal.  See bug 160042.
00555   if (NS_FAILED(rv) || !isChrome) {
00556     nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
00557 
00558     rv = secMan->
00559       CheckLoadURIWithPrincipal(document->GetPrincipal(), aURL,
00560                                 nsIScriptSecurityManager::ALLOW_CHROME);
00561     if (NS_FAILED(rv))
00562       return rv;
00563   }
00564 
00565   // Content policy check.  We have to be careful to not pass aContent as the
00566   // context here.  Otherwise, if there is a JS-implemented content policy, we
00567   // will attempt to wrap the content node, which will try to load XBL bindings
00568   // for it, if any.  Since we're not done loading this binding yet, that will
00569   // reenter this method and we'll end up creating a binding and then
00570   // immediately clobbering it in our table.  That makes things very confused,
00571   // leading to misbehavior and crashes.
00572   PRInt16 decision = nsIContentPolicy::ACCEPT;
00573   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
00574                                  aURL,
00575                                  docURI,
00576                                  document,        // context
00577                                  EmptyCString(),  // mime guess
00578                                  nsnull,          // extra
00579                                  &decision);
00580 
00581   if (NS_SUCCEEDED(rv) && !NS_CP_ACCEPTED(decision))
00582     rv = NS_ERROR_NOT_AVAILABLE;
00583 
00584   if (NS_FAILED(rv))
00585     return rv;
00586 
00587   PRBool ready;
00588   nsRefPtr<nsXBLBinding> newBinding;
00589   if (NS_FAILED(rv = GetBinding(aContent, aURL, PR_FALSE, &ready,
00590                                 getter_AddRefs(newBinding)))) {
00591     return rv;
00592   }
00593 
00594   if (!newBinding) {
00595 #ifdef DEBUG
00596     nsCAutoString spec;
00597     aURL->GetSpec(spec);
00598     nsCAutoString str(NS_LITERAL_CSTRING("Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over.  The invalid binding name is: ") + spec);
00599     NS_ERROR(str.get());
00600 #endif
00601     return NS_OK;
00602   }
00603 
00604   if (aAugmentFlag) {
00605     nsXBLBinding *baseBinding;
00606     nsXBLBinding *nextBinding = newBinding;
00607     do {
00608       baseBinding = nextBinding;
00609       nextBinding = baseBinding->GetBaseBinding();
00610       baseBinding->SetIsStyleBinding(PR_FALSE);
00611     } while (nextBinding);
00612 
00613     // XXX Handle adjusting the prototype chain! We need to somehow indicate to
00614     // InstallImplementation that the whole chain should just be whacked and rebuilt.
00615     // We are becoming the new binding.
00616     baseBinding->SetBaseBinding(binding);
00617     bindingManager->SetBinding(aContent, newBinding);
00618   }
00619   else {
00620     // We loaded a style binding.  It goes on the end.
00621     if (binding) {
00622       // Get the last binding that is in the append layer.
00623       binding->RootBinding()->SetBaseBinding(newBinding);
00624     }
00625     else {
00626       // Install the binding on the content node.
00627       bindingManager->SetBinding(aContent, newBinding);
00628     }
00629   }
00630 
00631   // Set the binding's bound element.
00632   newBinding->SetBoundElement(aContent);
00633 
00634   // Tell the binding to build the anonymous content.
00635   newBinding->GenerateAnonymousContent();
00636 
00637   // Tell the binding to install event handlers
00638   newBinding->InstallEventHandlers();
00639 
00640   // Set up our properties
00641   rv = newBinding->InstallImplementation();
00642   NS_ENSURE_SUCCESS(rv, rv);
00643 
00644   // Figure out if we need to execute a constructor.
00645   *aBinding = newBinding->GetFirstBindingWithConstructor();
00646   NS_IF_ADDREF(*aBinding);
00647 
00648   // Figure out if we have any scoped sheets.  If so, we do a second resolve.
00649   *aResolveStyle = newBinding->HasStyleSheets();
00650   
00651   return NS_OK; 
00652 }
00653 
00654 nsresult
00655 nsXBLService::FlushStyleBindings(nsIContent* aContent)
00656 {
00657   nsCOMPtr<nsIDocument> document = aContent->GetOwnerDoc();
00658 
00659   // XXX doc will be null if we're in the midst of paint suppression.
00660   if (! document)
00661     return NS_OK;
00662 
00663   nsIBindingManager *bindingManager = document->BindingManager();
00664   
00665   nsXBLBinding *binding = bindingManager->GetBinding(aContent);
00666   
00667   if (binding) {
00668     nsXBLBinding *styleBinding = binding->GetFirstStyleBinding();
00669 
00670     if (styleBinding) {
00671       // Clear out the script references.
00672       styleBinding->UnhookEventHandlers();
00673       styleBinding->ChangeDocument(document, nsnull);
00674     }
00675 
00676     if (styleBinding == binding) 
00677       bindingManager->SetBinding(aContent, nsnull); // Flush old style bindings
00678   }
00679    
00680   return NS_OK;
00681 }
00682 
00683 NS_IMETHODIMP
00684 nsXBLService::ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID,
00685                          nsIAtom** aResult)
00686 {
00687   nsIDocument* document = aContent->GetOwnerDoc();
00688   if (document) {
00689     return document->BindingManager()->ResolveTag(aContent, aNameSpaceID,
00690                                                   aResult);
00691   }
00692 
00693   *aNameSpaceID = aContent->GetNameSpaceID();
00694   NS_ADDREF(*aResult = aContent->Tag());
00695 
00696   return NS_OK;
00697 }
00698 
00699 nsresult
00700 nsXBLService::GetXBLDocumentInfo(nsIURI* aURI, nsIContent* aBoundElement, nsIXBLDocumentInfo** aResult)
00701 {
00702   *aResult = nsnull;
00703 
00704 #ifdef MOZ_XUL
00705   PRBool useXULCache;
00706   gXULCache->GetEnabled(&useXULCache);
00707   if (useXULCache) {
00708     // The first line of defense is the chrome cache.  
00709     // This cache crosses the entire product, so any XBL bindings that are
00710     // part of chrome will be reused across all XUL documents.
00711     gXULCache->GetXBLDocumentInfo(aURI, aResult);
00712   }
00713 #endif
00714 
00715   if (!*aResult) {
00716     // The second line of defense is the binding manager's document table.
00717     nsIDocument* boundDocument = aBoundElement->GetOwnerDoc();
00718     if (boundDocument)
00719       boundDocument->BindingManager()->GetXBLDocumentInfo(aURI, aResult);
00720   }
00721   return NS_OK;
00722 }
00723 
00724 
00725 //
00726 // AttachGlobalKeyHandler
00727 //
00728 // Creates a new key handler and prepares to listen to key events on the given
00729 // event receiver (either a document or an content node). If the receiver is content,
00730 // then extra work needs to be done to hook it up to the document (XXX WHY??)
00731 //
00732 NS_IMETHODIMP
00733 nsXBLService::AttachGlobalKeyHandler(nsIDOMEventReceiver* aReceiver)
00734 {
00735   // check if the receiver is a content node (not a document), and hook
00736   // it to the document if that is the case.
00737   nsCOMPtr<nsIDOMEventReceiver> rec = aReceiver;
00738   nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aReceiver));
00739   if (contentNode) {
00740     // Only attach if we're really in a document
00741     nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc();
00742     if (doc)
00743       rec = do_QueryInterface(doc); // We're a XUL keyset. Attach to our document.
00744   }
00745     
00746   if (!rec)
00747     return NS_ERROR_FAILURE;
00748     
00749   nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(contentNode));
00750 
00751   // Create the key handler
00752   nsXBLWindowKeyHandler* handler;
00753   NS_NewXBLWindowKeyHandler(elt, rec, &handler); // This addRef's
00754   if (!handler)
00755     return NS_ERROR_FAILURE;
00756 
00757   // listen to these events
00758   nsCOMPtr<nsIDOMEventGroup> systemGroup;
00759   rec->GetSystemEventGroup(getter_AddRefs(systemGroup));
00760   nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(rec);
00761 
00762   target->AddGroupedEventListener(NS_LITERAL_STRING("keydown"), handler,
00763                                   PR_FALSE, systemGroup);
00764   target->AddGroupedEventListener(NS_LITERAL_STRING("keyup"), handler, 
00765                                   PR_FALSE, systemGroup);
00766   target->AddGroupedEventListener(NS_LITERAL_STRING("keypress"), handler, 
00767                                   PR_FALSE, systemGroup);
00768 
00769   // Release.  Do this so that only the event receiver holds onto the key handler.
00770   NS_RELEASE(handler);
00771 
00772   return NS_OK;
00773 }
00774 
00775 
00776 //
00777 // AttachGlobalDragDropHandler
00778 //
00779 // Creates a new drag handler and prepares to listen to dragNdrop events on the given
00780 // event receiver.
00781 //
00782 NS_IMETHODIMP
00783 nsXBLService::AttachGlobalDragHandler(nsIDOMEventReceiver* aReceiver)
00784 {
00785   // Create the DnD handler
00786   nsXBLWindowDragHandler* handler;
00787   NS_NewXBLWindowDragHandler(aReceiver, &handler);
00788   if (!handler)
00789     return NS_ERROR_FAILURE;
00790 
00791   nsCOMPtr<nsIDOMEventGroup> systemGroup;
00792   aReceiver->GetSystemEventGroup(getter_AddRefs(systemGroup));
00793   nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(aReceiver);
00794 
00795   // listen to these events
00796   target->AddGroupedEventListener(NS_LITERAL_STRING("draggesture"), handler,
00797                                   PR_FALSE, systemGroup);
00798   target->AddGroupedEventListener(NS_LITERAL_STRING("dragenter"), handler,
00799                                   PR_FALSE, systemGroup);
00800   target->AddGroupedEventListener(NS_LITERAL_STRING("dragexit"), handler,
00801                                   PR_FALSE, systemGroup);
00802   target->AddGroupedEventListener(NS_LITERAL_STRING("dragover"), handler,
00803                                   PR_FALSE, systemGroup);
00804   target->AddGroupedEventListener(NS_LITERAL_STRING("dragdrop"), handler,
00805                                   PR_FALSE, systemGroup);
00806 
00807   // Release.  Do this so that only the event receiver holds onto the handler.
00808   NS_RELEASE(handler);
00809 
00810   return NS_OK;
00811 
00812 } // AttachGlobalDragDropHandler
00813 
00814 
00815 NS_IMETHODIMP
00816 nsXBLService::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
00817 {
00818   if (nsCRT::strcmp(aTopic, "memory-pressure") == 0)
00819     FlushMemory();
00820 
00821   return NS_OK;
00822 }
00823 
00824 nsresult
00825 nsXBLService::FlushMemory()
00826 {
00827   while (!JS_CLIST_IS_EMPTY(&gClassLRUList)) {
00828     JSCList* lru = gClassLRUList.next;
00829     nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, lru);
00830 
00831     JS_REMOVE_AND_INIT_LINK(lru);
00832     delete c;
00833     gClassLRUListLength--;
00834   }
00835   return NS_OK;
00836 }
00837 
00838 // Internal helper methods ////////////////////////////////////////////////////////////////
00839 
00840 NS_IMETHODIMP nsXBLService::BindingReady(nsIContent* aBoundElement, 
00841                                          nsIURI* aURI, 
00842                                          PRBool* aIsReady)
00843 {
00844   return GetBinding(aBoundElement, aURI, PR_TRUE, aIsReady, nsnull);
00845 }
00846 
00847 nsresult
00848 nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI, 
00849                          PRBool aPeekOnly, PRBool* aIsReady, 
00850                          nsXBLBinding** aResult)
00851 {
00852   if (aResult)
00853     *aResult = nsnull;
00854 
00855   if (!aURI)
00856     return NS_ERROR_FAILURE;
00857 
00858   nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
00859   if (!url) {
00860 #ifdef DEBUG
00861     NS_ERROR("Binding load from a non-URL URI not allowed.");
00862     nsCAutoString spec;
00863     aURI->GetSpec(spec);
00864     fprintf(stderr, "Spec of non-URL URI is: '%s'\n", spec.get());
00865 #endif
00866     return NS_ERROR_FAILURE;
00867   }
00868 
00869   nsCAutoString ref;
00870   url->GetRef(ref);
00871   NS_ASSERTION(!ref.IsEmpty(), "Incorrect syntax for an XBL binding");
00872   if (ref.IsEmpty())
00873     return NS_ERROR_FAILURE;
00874   
00875   nsCOMPtr<nsIDocument> boundDocument = aBoundElement->GetOwnerDoc();
00876 
00877   nsCOMPtr<nsIXBLDocumentInfo> docInfo;
00878   LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI, PR_FALSE,
00879                           getter_AddRefs(docInfo));
00880   if (!docInfo)
00881     return NS_ERROR_FAILURE;
00882 
00883   // Get our doc info and determine our script access.
00884   nsCOMPtr<nsIDocument> doc;
00885   docInfo->GetDocument(getter_AddRefs(doc));
00886   PRBool allowScripts;
00887   docInfo->GetScriptAccess(&allowScripts);
00888 
00889   nsXBLPrototypeBinding* protoBinding;
00890   docInfo->GetPrototypeBinding(ref, &protoBinding);
00891 
00892   NS_ASSERTION(protoBinding, "Unable to locate an XBL binding.");
00893   if (!protoBinding)
00894     return NS_ERROR_FAILURE;
00895 
00896   nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement();
00897 
00898   // Our prototype binding must have all its resources loaded.
00899   PRBool ready = protoBinding->LoadResources();
00900   if (!ready) {
00901     // Add our bound element to the protos list of elts that should
00902     // be notified when the stylesheets and scripts finish loading.
00903     protoBinding->AddResourceListener(aBoundElement);
00904     return NS_ERROR_FAILURE; // The binding isn't ready yet.
00905   }
00906 
00907   // If our prototype already has a base, then don't check for an "extends" attribute.
00908   nsRefPtr<nsXBLBinding> baseBinding;
00909   PRBool hasBase = protoBinding->HasBasePrototype();
00910   nsXBLPrototypeBinding* baseProto = protoBinding->GetBasePrototype();
00911   if (baseProto) {
00912     if (NS_FAILED(GetBinding(aBoundElement, baseProto->BindingURI(),
00913                              aPeekOnly, aIsReady, getter_AddRefs(baseBinding))))
00914       return NS_ERROR_FAILURE; // We aren't ready yet.
00915   }
00916   else if (hasBase) {
00917     // Check for the presence of 'extends' and 'display' attributes
00918     nsAutoString display, extends;
00919     child->GetAttr(kNameSpaceID_None, nsXBLAtoms::display, display);
00920     child->GetAttr(kNameSpaceID_None, nsXBLAtoms::extends, extends);
00921     PRBool hasDisplay = !display.IsEmpty();
00922     PRBool hasExtends = !extends.IsEmpty();
00923     
00924     nsAutoString value(extends);
00925          
00926     if (!hasExtends) 
00927       protoBinding->SetHasBasePrototype(PR_FALSE);
00928     else {
00929       // Now slice 'em up to see what we've got.
00930       nsAutoString prefix;
00931       PRInt32 offset;
00932       if (hasDisplay) {
00933         offset = display.FindChar(':');
00934         if (-1 != offset) {
00935           display.Left(prefix, offset);
00936           display.Cut(0, offset+1);
00937         }
00938       }
00939       else if (hasExtends) {
00940         offset = extends.FindChar(':');
00941         if (-1 != offset) {
00942           extends.Left(prefix, offset);
00943           extends.Cut(0, offset+1);
00944           display = extends;
00945         }
00946       }
00947 
00948       nsAutoString nameSpace;
00949 
00950       if (!prefix.IsEmpty()) {
00951         nsCOMPtr<nsIAtom> prefixAtom = do_GetAtom(prefix);
00952 
00953         nsCOMPtr<nsIDOM3Node> node(do_QueryInterface(child));
00954 
00955         if (node) {
00956           node->LookupNamespaceURI(prefix, nameSpace);
00957 
00958           if (!nameSpace.IsEmpty()) {
00959             if (!hasDisplay) {
00960               // We extend some widget/frame. We don't really have a
00961               // base binding.
00962               protoBinding->SetHasBasePrototype(PR_FALSE);
00963               //child->UnsetAttr(kNameSpaceID_None, nsXBLAtoms::extends, PR_FALSE);
00964             }
00965 
00966             PRInt32 nameSpaceID;
00967 
00968             nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(nameSpace,
00969                                                                   &nameSpaceID);
00970 
00971             nsCOMPtr<nsIAtom> tagName = do_GetAtom(display);
00972             protoBinding->SetBaseTag(nameSpaceID, tagName);
00973           }
00974         }
00975       }
00976 
00977       if (hasExtends && (hasDisplay || nameSpace.IsEmpty())) {
00978         // Look up the prefix.
00979         // We have a base class binding. Load it right now.
00980         nsCOMPtr<nsIURI> bindingURI;
00981         nsresult rv =
00982           NS_NewURI(getter_AddRefs(bindingURI), value,
00983                     doc->GetDocumentCharacterSet().get(),
00984                     doc->GetBaseURI());
00985         NS_ENSURE_SUCCESS(rv, rv);
00986         
00987         if (NS_FAILED(GetBinding(aBoundElement, bindingURI, aPeekOnly,
00988                                  aIsReady, getter_AddRefs(baseBinding))))
00989           return NS_ERROR_FAILURE; // Binding not yet ready or an error occurred.
00990         if (!aPeekOnly) {
00991           // Make sure to set the base prototype.
00992           baseProto = baseBinding->PrototypeBinding();
00993           protoBinding->SetBasePrototype(baseProto);
00994           child->UnsetAttr(kNameSpaceID_None, nsXBLAtoms::extends, PR_FALSE);
00995           child->UnsetAttr(kNameSpaceID_None, nsXBLAtoms::display, PR_FALSE);
00996         }
00997       }
00998     }
00999   }
01000 
01001   *aIsReady = PR_TRUE;
01002   if (!aPeekOnly) {
01003     // Make a new binding
01004     nsXBLBinding *newBinding = new nsXBLBinding(protoBinding);
01005     NS_ENSURE_TRUE(newBinding, NS_ERROR_OUT_OF_MEMORY);
01006 
01007     if (baseBinding)
01008       newBinding->SetBaseBinding(baseBinding);
01009 
01010     NS_ADDREF(*aResult = newBinding);
01011   }
01012 
01013   return NS_OK;
01014 }
01015 
01016 NS_IMETHODIMP
01017 nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
01018                                       nsIDocument* aBoundDocument,
01019                                       nsIURI* aBindingURI,
01020                                       PRBool aForceSyncLoad,
01021                                       nsIXBLDocumentInfo** aResult)
01022 {
01023   NS_PRECONDITION(aBindingURI, "Must have a binding URI");
01024   
01025   nsresult rv = NS_OK;
01026 
01027   *aResult = nsnull;
01028   nsCOMPtr<nsIXBLDocumentInfo> info;
01029 
01030   nsCOMPtr<nsIURI> uriClone;
01031   rv = aBindingURI->Clone(getter_AddRefs(uriClone));
01032   NS_ENSURE_SUCCESS(rv, rv);
01033   
01034   nsCOMPtr<nsIURL> documentURI(do_QueryInterface(uriClone, &rv));
01035   NS_ENSURE_TRUE(documentURI, rv);
01036 
01037   documentURI->SetRef(EmptyCString());
01038 
01039 #ifdef MOZ_XUL
01040   // We've got a file.  Check our XBL document cache.
01041   PRBool useXULCache;
01042   gXULCache->GetEnabled(&useXULCache);
01043 
01044   if (useXULCache) {
01045     // The first line of defense is the chrome cache.  
01046     // This cache crosses the entire product, so that any XBL bindings that are
01047     // part of chrome will be reused across all XUL documents.
01048     gXULCache->GetXBLDocumentInfo(documentURI, getter_AddRefs(info));
01049   }
01050 #endif
01051 
01052   if (!info) {
01053     // The second line of defense is the binding manager's document table.
01054     nsIBindingManager *bindingManager = nsnull;
01055 
01056     nsCOMPtr<nsIURL> bindingURL(do_QueryInterface(aBindingURI, &rv));
01057     NS_ENSURE_SUCCESS(rv, rv);
01058 
01059     if (aBoundDocument) {
01060       bindingManager = aBoundDocument->BindingManager();
01061       bindingManager->GetXBLDocumentInfo(documentURI, getter_AddRefs(info));
01062     }
01063 
01064     nsINodeInfo *ni = nsnull;
01065     if (aBoundElement)
01066       ni = aBoundElement->GetNodeInfo();
01067 
01068     if (!info && bindingManager &&
01069         (!ni || !(ni->Equals(nsXULAtoms::scrollbar, kNameSpaceID_XUL) ||
01070                   ni->Equals(nsXULAtoms::thumb, kNameSpaceID_XUL) ||
01071                   ((ni->Equals(nsHTMLAtoms::input) ||
01072                     ni->Equals(nsHTMLAtoms::select)) &&
01073                    aBoundElement->IsContentOfType(nsIContent::eHTML)))) &&
01074         !aForceSyncLoad) {
01075       // The third line of defense is to investigate whether or not the
01076       // document is currently being loaded asynchronously.  If so, there's no
01077       // document yet, but we need to glom on our request so that it will be
01078       // processed whenever the doc does finish loading.
01079       nsCOMPtr<nsIStreamListener> listener;
01080       if (bindingManager)
01081         bindingManager->GetLoadingDocListener(documentURI, getter_AddRefs(listener));
01082       if (listener) {
01083         nsIStreamListener* ilist = listener.get();
01084         nsXBLStreamListener* xblListener = NS_STATIC_CAST(nsXBLStreamListener*, ilist);
01085         // Create a new load observer.
01086         if (!xblListener->HasRequest(aBindingURI, aBoundElement)) {
01087           nsXBLBindingRequest* req = nsXBLBindingRequest::Create(mPool, bindingURL, aBoundElement);
01088           xblListener->AddRequest(req);
01089         }
01090         return NS_OK;
01091       }
01092     }
01093      
01094     if (!info) {
01095       // Finally, if all lines of defense fail, we go and fetch the binding
01096       // document.
01097       
01098       // Always load chrome synchronously
01099       PRBool chrome;
01100       if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome)
01101         aForceSyncLoad = PR_TRUE;
01102 
01103       nsCOMPtr<nsIDocument> document;
01104       FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
01105                            bindingURL, aForceSyncLoad, getter_AddRefs(document));
01106    
01107       if (document) {
01108         nsIBindingManager *xblDocBindingManager = document->BindingManager();
01109         xblDocBindingManager->GetXBLDocumentInfo(documentURI, getter_AddRefs(info));
01110         if (!info) {
01111           NS_ERROR("An XBL file is malformed.  Did you forget the XBL namespace on the bindings tag?");
01112           return NS_ERROR_FAILURE;
01113         }
01114         xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
01115 
01116         // If the doc is a chrome URI, then we put it into the XUL cache.
01117 #ifdef MOZ_XUL
01118         if (IsChromeOrResourceURI(documentURI)) {
01119           if (useXULCache)
01120             gXULCache->PutXBLDocumentInfo(info);
01121         }
01122 #endif
01123         
01124         if (bindingManager) {
01125           // Also put it in our binding manager's document table.
01126           bindingManager->PutXBLDocumentInfo(info);
01127         }
01128       }
01129     }
01130   }
01131 
01132   if (!info)
01133     return NS_OK;
01134  
01135   *aResult = info;
01136   NS_IF_ADDREF(*aResult);
01137 
01138   return NS_OK;
01139 }
01140 
01141 nsresult
01142 nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
01143                                    nsIURI* aDocumentURI, nsIURL* aBindingURL, 
01144                                    PRBool aForceSyncLoad, nsIDocument** aResult)
01145 {
01146   nsresult rv = NS_OK;
01147   // Initialize our out pointer to nsnull
01148   *aResult = nsnull;
01149 
01150   // Now we have to synchronously load the binding file.
01151   // Create an XML content sink and a parser. 
01152   nsCOMPtr<nsILoadGroup> loadGroup;
01153   if (aBoundDocument)
01154     loadGroup = aBoundDocument->GetDocumentLoadGroup();
01155 
01156   // We really shouldn't have to force a sync load for anything here... could
01157   // we get away with not doing that?  Not sure.
01158   if (IsChromeOrResourceURI(aDocumentURI))
01159     aForceSyncLoad = PR_TRUE;
01160 
01161   if(!aForceSyncLoad) {
01162     // Create the XML document
01163     nsCOMPtr<nsIDocument> doc = do_CreateInstance(kXMLDocumentCID, &rv);
01164     NS_ENSURE_SUCCESS(rv, rv);
01165 
01166     nsCOMPtr<nsIChannel> channel;
01167     rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nsnull, loadGroup);
01168     if (NS_FAILED(rv)) return rv;
01169 
01170     nsCOMPtr<nsIStreamListener> listener;
01171     nsCOMPtr<nsIXMLContentSink> xblSink;
01172     NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nsnull);
01173     if (!xblSink)
01174       return NS_ERROR_FAILURE;
01175 
01176     if (NS_FAILED(rv = doc->StartDocumentLoad("loadAsInteractiveData", 
01177                                               channel, 
01178                                               loadGroup, 
01179                                               nsnull, 
01180                                               getter_AddRefs(listener),
01181                                               PR_TRUE,
01182                                               xblSink))) {
01183       NS_ERROR("Failure to init XBL doc prior to load.");
01184       return rv;
01185     }
01186 
01187     // We can be asynchronous
01188     nsXBLStreamListener* xblListener = new nsXBLStreamListener(this, listener, aBoundDocument, doc);
01189     NS_ENSURE_TRUE(xblListener,NS_ERROR_OUT_OF_MEMORY);
01190 
01191     nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(doc));
01192     rec->AddEventListener(NS_LITERAL_STRING("load"), (nsIDOMLoadListener*)xblListener, PR_FALSE);
01193 
01194     // Add ourselves to the list of loading docs.
01195     nsIBindingManager *bindingManager;
01196     if (aBoundDocument)
01197       bindingManager = aBoundDocument->BindingManager();
01198     else
01199       bindingManager = nsnull;
01200 
01201     if (bindingManager)
01202       bindingManager->PutLoadingDocListener(aDocumentURI, xblListener);
01203 
01204     // Add our request.
01205     nsXBLBindingRequest* req = nsXBLBindingRequest::Create(mPool,
01206                                                            aBindingURL,
01207                                                            aBoundElement);
01208     xblListener->AddRequest(req);
01209 
01210     // Now kick off the async read.
01211     channel->AsyncOpen(xblListener, nsnull);
01212     return NS_OK;
01213   }
01214 
01215   // Now do a blocking synchronous parse of the file.
01216 
01217   nsCOMPtr<nsIDOMDocument> domDoc;
01218   nsCOMPtr<nsISyncLoadDOMService> loader =
01219     do_GetService("@mozilla.org/content/syncload-dom-service;1", &rv);
01220   NS_ENSURE_SUCCESS(rv, rv);
01221 
01222   // Open channel
01223   nsCOMPtr<nsIChannel> channel;
01224   rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nsnull, loadGroup);
01225   NS_ENSURE_SUCCESS(rv, rv);
01226 
01227   rv = loader->LoadLocalXBLDocument(channel, getter_AddRefs(domDoc));
01228   if (rv == NS_ERROR_FILE_NOT_FOUND) {
01229       return NS_OK;
01230   }
01231   NS_ENSURE_SUCCESS(rv, rv);
01232 
01233   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
01234   // Clear script handling object on synchronously loaded XBL documents.
01235   NS_STATIC_CAST(nsDocument*, NS_STATIC_CAST(nsIDocument*, doc.get()))->
01236     ClearScriptHandlingObject();
01237 
01238   return CallQueryInterface(domDoc, aResult);
01239 }
01240 
01241 // Creation Routine ///////////////////////////////////////////////////////////////////////
01242 
01243 nsresult NS_NewXBLService(nsIXBLService** aResult);
01244 
01245 nsresult
01246 NS_NewXBLService(nsIXBLService** aResult)
01247 {
01248   nsXBLService* result = new nsXBLService;
01249   if (! result)
01250     return NS_ERROR_OUT_OF_MEMORY;
01251 
01252   NS_ADDREF(*aResult = result);
01253 
01254   // Register the first (and only) nsXBLService as a memory pressure observer
01255   // so it can flush the LRU list in low-memory situations.
01256   nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
01257   if (os)
01258     os->AddObserver(result, "memory-pressure", PR_TRUE);
01259 
01260   return NS_OK;
01261 }
01262