LCOV - code coverage report
Current view: directory - content/xbl/src - nsXBLService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 503 0 0.0 %
Date: 2012-06-02 Functions: 39 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Original Author: David W. Hyatt (hyatt@netscape.com)
      24                 :  *   - Brendan Eich (brendan@mozilla.org)
      25                 :  *   - Mike Pinkerton (pinkerton@netscape.com)
      26                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include "mozilla/Util.h"
      43                 : 
      44                 : #include "nsCOMPtr.h"
      45                 : #include "nsNetUtil.h"
      46                 : #include "nsXBLService.h"
      47                 : #include "nsXBLWindowKeyHandler.h"
      48                 : #include "nsIInputStream.h"
      49                 : #include "nsINameSpaceManager.h"
      50                 : #include "nsHashtable.h"
      51                 : #include "nsIURI.h"
      52                 : #include "nsIDOMElement.h"
      53                 : #include "nsIURL.h"
      54                 : #include "nsIChannel.h"
      55                 : #include "nsXPIDLString.h"
      56                 : #include "nsIParser.h"
      57                 : #include "nsParserCIID.h"
      58                 : #include "nsNetUtil.h"
      59                 : #include "plstr.h"
      60                 : #include "nsIContent.h"
      61                 : #include "nsIDOMElement.h"
      62                 : #include "nsIDocument.h"
      63                 : #include "nsIXMLContentSink.h"
      64                 : #include "nsContentCID.h"
      65                 : #include "nsXMLDocument.h"
      66                 : #include "mozilla/FunctionTimer.h"
      67                 : #include "nsGkAtoms.h"
      68                 : #include "nsIMemory.h"
      69                 : #include "nsIObserverService.h"
      70                 : #include "nsIDOMNodeList.h"
      71                 : #include "nsXBLContentSink.h"
      72                 : #include "nsXBLBinding.h"
      73                 : #include "nsXBLPrototypeBinding.h"
      74                 : #include "nsXBLDocumentInfo.h"
      75                 : #include "nsCRT.h"
      76                 : #include "nsContentUtils.h"
      77                 : #include "nsSyncLoadService.h"
      78                 : #include "nsContentPolicyUtils.h"
      79                 : #include "nsTArray.h"
      80                 : #include "nsContentErrors.h"
      81                 : 
      82                 : #include "nsIPresShell.h"
      83                 : #include "nsIDocumentObserver.h"
      84                 : #include "nsFrameManager.h"
      85                 : #include "nsStyleContext.h"
      86                 : #include "nsIScriptSecurityManager.h"
      87                 : #include "nsIScriptError.h"
      88                 : #include "nsXBLSerialize.h"
      89                 : 
      90                 : #ifdef MOZ_XUL
      91                 : #include "nsXULPrototypeCache.h"
      92                 : #endif
      93                 : #include "nsIDOMEventListener.h"
      94                 : #include "mozilla/Preferences.h"
      95                 : #include "mozilla/dom/Element.h"
      96                 : 
      97                 : using namespace mozilla;
      98                 : 
      99                 : #define NS_MAX_XBL_BINDING_RECURSION 20
     100                 : 
     101                 : static bool
     102               0 : IsAncestorBinding(nsIDocument* aDocument,
     103                 :                   nsIURI* aChildBindingURI,
     104                 :                   nsIContent* aChild)
     105                 : {
     106               0 :   NS_ASSERTION(aDocument, "expected a document");
     107               0 :   NS_ASSERTION(aChildBindingURI, "expected a binding URI");
     108               0 :   NS_ASSERTION(aChild, "expected a child content");
     109                 : 
     110               0 :   PRUint32 bindingRecursion = 0;
     111               0 :   nsBindingManager* bindingManager = aDocument->BindingManager();
     112               0 :   for (nsIContent *bindingParent = aChild->GetBindingParent();
     113                 :        bindingParent;
     114               0 :        bindingParent = bindingParent->GetBindingParent()) {
     115               0 :     nsXBLBinding* binding = bindingManager->GetBinding(bindingParent);
     116               0 :     if (!binding) {
     117               0 :       continue;
     118                 :     }
     119                 : 
     120               0 :     if (binding->PrototypeBinding()->CompareBindingURI(aChildBindingURI)) {
     121               0 :       ++bindingRecursion;
     122               0 :       if (bindingRecursion < NS_MAX_XBL_BINDING_RECURSION) {
     123               0 :         continue;
     124                 :       }
     125               0 :       nsCAutoString spec;
     126               0 :       aChildBindingURI->GetSpec(spec);
     127               0 :       NS_ConvertUTF8toUTF16 bindingURI(spec);
     128               0 :       const PRUnichar* params[] = { bindingURI.get() };
     129                 :       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     130                 :                                       "XBL", aDocument,
     131                 :                                       nsContentUtils::eXBL_PROPERTIES,
     132                 :                                       "TooDeepBindingRecursion",
     133               0 :                                       params, ArrayLength(params));
     134               0 :       return true;
     135                 :     }
     136                 :   }
     137                 : 
     138               0 :   return false;
     139                 : }
     140                 : 
     141                 : // Individual binding requests.
     142                 : class nsXBLBindingRequest
     143                 : {
     144                 : public:
     145                 :   nsCOMPtr<nsIURI> mBindingURI;
     146                 :   nsCOMPtr<nsIContent> mBoundElement;
     147                 : 
     148                 :   static nsXBLBindingRequest*
     149               0 :   Create(nsFixedSizeAllocator& aPool, nsIURI* aURI, nsIContent* aBoundElement) {
     150               0 :     void* place = aPool.Alloc(sizeof(nsXBLBindingRequest));
     151               0 :     return place ? ::new (place) nsXBLBindingRequest(aURI, aBoundElement) : nsnull;
     152                 :   }
     153                 : 
     154                 :   static void
     155               0 :   Destroy(nsFixedSizeAllocator& aPool, nsXBLBindingRequest* aRequest) {
     156               0 :     aRequest->~nsXBLBindingRequest();
     157               0 :     aPool.Free(aRequest, sizeof(*aRequest));
     158               0 :   }
     159                 : 
     160               0 :   void DocumentLoaded(nsIDocument* aBindingDoc)
     161                 :   {
     162                 :     // We only need the document here to cause frame construction, so
     163                 :     // we need the current doc, not the owner doc.
     164               0 :     nsIDocument* doc = mBoundElement->GetCurrentDoc();
     165               0 :     if (!doc)
     166               0 :       return;
     167                 : 
     168                 :     // Get the binding.
     169               0 :     bool ready = false;
     170               0 :     gXBLService->BindingReady(mBoundElement, mBindingURI, &ready);
     171                 : 
     172               0 :     if (!ready)
     173               0 :       return;
     174                 : 
     175                 :     // If |mBoundElement| is (in addition to having binding |mBinding|)
     176                 :     // also a descendant of another element with binding |mBinding|,
     177                 :     // then we might have just constructed it due to the
     178                 :     // notification of its parent.  (We can know about both if the
     179                 :     // binding loads were triggered from the DOM rather than frame
     180                 :     // construction.)  So we have to check both whether the element
     181                 :     // has a primary frame and whether it's in the undisplayed map
     182                 :     // before sending a ContentInserted notification, or bad things
     183                 :     // will happen.
     184               0 :     nsIPresShell *shell = doc->GetShell();
     185               0 :     if (shell) {
     186               0 :       nsIFrame* childFrame = mBoundElement->GetPrimaryFrame();
     187               0 :       if (!childFrame) {
     188                 :         // Check to see if it's in the undisplayed content map.
     189                 :         nsStyleContext* sc =
     190               0 :           shell->FrameManager()->GetUndisplayedContent(mBoundElement);
     191                 : 
     192               0 :         if (!sc) {
     193               0 :           shell->RecreateFramesFor(mBoundElement);
     194                 :         }
     195                 :       }
     196                 :     }
     197                 :   }
     198                 : 
     199                 :   static nsIXBLService* gXBLService;
     200                 :   static int gRefCnt;
     201                 : 
     202                 : protected:
     203               0 :   nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement)
     204                 :     : mBindingURI(aURI),
     205               0 :       mBoundElement(aBoundElement)
     206                 :   {
     207               0 :     gRefCnt++;
     208               0 :     if (gRefCnt == 1) {
     209               0 :       CallGetService("@mozilla.org/xbl;1", &gXBLService);
     210                 :     }
     211               0 :   }
     212                 : 
     213               0 :   ~nsXBLBindingRequest()
     214               0 :   {
     215               0 :     gRefCnt--;
     216               0 :     if (gRefCnt == 0) {
     217               0 :       NS_IF_RELEASE(gXBLService);
     218                 :     }
     219               0 :   }
     220                 : 
     221                 : private:
     222                 :   // Hide so that only Create() and Destroy() can be used to
     223                 :   // allocate and deallocate from the heap
     224                 :   static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     225                 :   static void operator delete(void*, size_t) {}
     226                 : };
     227                 : 
     228                 : static const size_t kBucketSizes[] = {
     229                 :   sizeof(nsXBLBindingRequest)
     230                 : };
     231                 : 
     232                 : static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
     233                 : static const PRInt32 kNumElements = 64;
     234                 : static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLBindingRequest))) * kNumElements;
     235                 : 
     236                 : nsIXBLService* nsXBLBindingRequest::gXBLService = nsnull;
     237                 : int nsXBLBindingRequest::gRefCnt = 0;
     238                 : 
     239                 : // nsXBLStreamListener, a helper class used for 
     240                 : // asynchronous parsing of URLs
     241                 : /* Header file */
     242                 : class nsXBLStreamListener : public nsIStreamListener, public nsIDOMEventListener
     243                 : {
     244                 : public:
     245                 :   NS_DECL_ISUPPORTS
     246                 :   NS_DECL_NSISTREAMLISTENER
     247                 :   NS_DECL_NSIREQUESTOBSERVER
     248                 :   NS_DECL_NSIDOMEVENTLISTENER
     249                 : 
     250                 :   nsXBLStreamListener(nsXBLService* aXBLService,
     251                 :                       nsIDocument* aBoundDocument,
     252                 :                       nsIXMLContentSink* aSink,
     253                 :                       nsIDocument* aBindingDocument);
     254                 :   ~nsXBLStreamListener();
     255                 : 
     256               0 :   void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); }
     257                 :   bool HasRequest(nsIURI* aURI, nsIContent* aBoundElement);
     258                 : 
     259                 : private:
     260                 :   nsXBLService* mXBLService; // [WEAK]
     261                 : 
     262                 :   nsCOMPtr<nsIStreamListener> mInner;
     263                 :   nsAutoTArray<nsXBLBindingRequest*, 8> mBindingRequests;
     264                 :   
     265                 :   nsCOMPtr<nsIWeakReference> mBoundDocument;
     266                 :   nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest
     267                 :   nsCOMPtr<nsIDocument> mBindingDocument; // Only set until OnStartRequest
     268                 : };
     269                 : 
     270                 : /* Implementation file */
     271               0 : NS_IMPL_ISUPPORTS3(nsXBLStreamListener,
     272                 :                    nsIStreamListener,
     273                 :                    nsIRequestObserver,
     274                 :                    nsIDOMEventListener)
     275                 : 
     276               0 : nsXBLStreamListener::nsXBLStreamListener(nsXBLService* aXBLService,
     277                 :                                          nsIDocument* aBoundDocument,
     278                 :                                          nsIXMLContentSink* aSink,
     279                 :                                          nsIDocument* aBindingDocument)
     280               0 : : mSink(aSink), mBindingDocument(aBindingDocument)
     281                 : {
     282                 :   /* member initializers and constructor code */
     283               0 :   mXBLService = aXBLService;
     284               0 :   mBoundDocument = do_GetWeakReference(aBoundDocument);
     285               0 : }
     286                 : 
     287               0 : nsXBLStreamListener::~nsXBLStreamListener()
     288                 : {
     289               0 :   for (PRUint32 i = 0; i < mBindingRequests.Length(); i++) {
     290               0 :     nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
     291               0 :     nsXBLBindingRequest::Destroy(mXBLService->mPool, req);
     292                 :   }
     293               0 : }
     294                 : 
     295                 : NS_IMETHODIMP
     296               0 : nsXBLStreamListener::OnDataAvailable(nsIRequest *request, nsISupports* aCtxt, nsIInputStream* aInStr, 
     297                 :                                      PRUint32 aSourceOffset, PRUint32 aCount)
     298                 : {
     299               0 :   if (mInner)
     300               0 :     return mInner->OnDataAvailable(request, aCtxt, aInStr, aSourceOffset, aCount);
     301               0 :   return NS_ERROR_FAILURE;
     302                 : }
     303                 : 
     304                 : NS_IMETHODIMP
     305               0 : nsXBLStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aCtxt)
     306                 : {
     307                 :   // Make sure we don't hold on to the sink and binding document past this point
     308               0 :   nsCOMPtr<nsIXMLContentSink> sink;
     309               0 :   mSink.swap(sink);
     310               0 :   nsCOMPtr<nsIDocument> doc;
     311               0 :   mBindingDocument.swap(doc);
     312                 : 
     313               0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     314               0 :   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
     315                 : 
     316               0 :   nsCOMPtr<nsILoadGroup> group;
     317               0 :   request->GetLoadGroup(getter_AddRefs(group));
     318                 : 
     319               0 :   nsresult rv = doc->StartDocumentLoad("loadAsInteractiveData",
     320                 :                                        channel,
     321                 :                                        group,
     322                 :                                        nsnull,
     323               0 :                                        getter_AddRefs(mInner),
     324                 :                                        true,
     325               0 :                                        sink);
     326               0 :   NS_ENSURE_SUCCESS(rv, rv);
     327                 : 
     328                 :   // Make sure to add ourselves as a listener after StartDocumentLoad,
     329                 :   // since that resets the event listners on the document.
     330               0 :   nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(doc));
     331               0 :   target->AddEventListener(NS_LITERAL_STRING("load"), this, false);
     332                 :   
     333               0 :   return mInner->OnStartRequest(request, aCtxt);
     334                 : }
     335                 : 
     336                 : NS_IMETHODIMP 
     337               0 : nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aCtxt, nsresult aStatus)
     338                 : {
     339               0 :   nsresult rv = NS_OK;
     340               0 :   if (mInner) {
     341               0 :      rv = mInner->OnStopRequest(request, aCtxt, aStatus);
     342                 :   }
     343                 : 
     344                 :   // Don't hold onto the inner listener; holding onto it can create a cycle
     345                 :   // with the document
     346               0 :   mInner = nsnull;
     347                 : 
     348               0 :   return rv;
     349                 : }
     350                 : 
     351                 : bool
     352               0 : nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt)
     353                 : {
     354                 :   // XXX Could be more efficient.
     355               0 :   PRUint32 count = mBindingRequests.Length();
     356               0 :   for (PRUint32 i = 0; i < count; i++) {
     357               0 :     nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
     358                 :     bool eq;
     359               0 :     if (req->mBoundElement == aElt &&
     360               0 :         NS_SUCCEEDED(req->mBindingURI->Equals(aURI, &eq)) && eq)
     361               0 :       return true;
     362                 :   }
     363                 : 
     364               0 :   return false;
     365                 : }
     366                 : 
     367                 : nsresult
     368               0 : nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent)
     369                 : {
     370               0 :   nsresult rv = NS_OK;
     371                 :   PRUint32 i;
     372               0 :   PRUint32 count = mBindingRequests.Length();
     373                 : 
     374                 :   // Get the binding document; note that we don't hold onto it in this object
     375                 :   // to avoid creating a cycle
     376               0 :   nsCOMPtr<nsIDOMEventTarget> target;
     377               0 :   aEvent->GetCurrentTarget(getter_AddRefs(target));
     378               0 :   nsCOMPtr<nsIDocument> bindingDocument = do_QueryInterface(target);
     379               0 :   NS_ASSERTION(bindingDocument, "Event not targeted at document?!");
     380                 : 
     381                 :   // See if we're still alive.
     382               0 :   nsCOMPtr<nsIDocument> doc(do_QueryReferent(mBoundDocument));
     383               0 :   if (!doc) {
     384               0 :     NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n");
     385                 :   }
     386                 :   else {
     387                 :     // We have to do a flush prior to notification of the document load.
     388                 :     // This has to happen since the HTML content sink can be holding on
     389                 :     // to notifications related to our children (e.g., if you bind to the
     390                 :     // <body> tag) that result in duplication of content.  
     391                 :     // We need to get the sink's notifications flushed and then make the binding
     392                 :     // ready.
     393               0 :     if (count > 0) {
     394               0 :       nsXBLBindingRequest* req = mBindingRequests.ElementAt(0);
     395               0 :       nsIDocument* document = req->mBoundElement->GetCurrentDoc();
     396               0 :       if (document)
     397               0 :         document->FlushPendingNotifications(Flush_ContentAndNotify);
     398                 :     }
     399                 : 
     400                 :     // Remove ourselves from the set of pending docs.
     401               0 :     nsBindingManager *bindingManager = doc->BindingManager();
     402               0 :     nsIURI* documentURI = bindingDocument->GetDocumentURI();
     403               0 :     bindingManager->RemoveLoadingDocListener(documentURI);
     404                 : 
     405               0 :     if (!bindingDocument->GetRootElement()) {
     406                 :       // FIXME: How about an error console warning?
     407               0 :       NS_WARNING("*** XBL doc with no root element! Something went horribly wrong! ***");
     408               0 :       return NS_ERROR_FAILURE;
     409                 :     }
     410                 : 
     411                 :     // Put our doc info in the doc table.
     412               0 :     nsBindingManager *xblDocBindingManager = bindingDocument->BindingManager();
     413                 :     nsRefPtr<nsXBLDocumentInfo> info =
     414               0 :       xblDocBindingManager->GetXBLDocumentInfo(documentURI);
     415               0 :     xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
     416               0 :     if (!info) {
     417               0 :       if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
     418               0 :         NS_WARNING("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?");
     419                 :       }
     420                 :       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     421                 :                                       "XBL", nsnull,
     422                 :                                       nsContentUtils::eXBL_PROPERTIES,
     423                 :                                       "MalformedXBL",
     424               0 :                                       nsnull, 0, documentURI);
     425               0 :       return NS_ERROR_FAILURE;
     426                 :     }
     427                 : 
     428                 :     // If the doc is a chrome URI, then we put it into the XUL cache.
     429                 : #ifdef MOZ_XUL
     430               0 :     if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
     431               0 :       nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
     432               0 :       if (cache && cache->IsEnabled())
     433               0 :         cache->PutXBLDocumentInfo(info);
     434                 :     }
     435                 : #endif
     436                 :   
     437               0 :     bindingManager->PutXBLDocumentInfo(info);
     438                 : 
     439                 :     // Notify all pending requests that their bindings are
     440                 :     // ready and can be installed.
     441               0 :     for (i = 0; i < count; i++) {
     442               0 :       nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
     443               0 :       req->DocumentLoaded(bindingDocument);
     444                 :     }
     445                 :   }
     446                 : 
     447               0 :   target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
     448                 : 
     449               0 :   return rv;
     450                 : }
     451                 : 
     452                 : // Implementation /////////////////////////////////////////////////////////////////
     453                 : 
     454                 : // Static member variable initialization
     455                 : PRUint32 nsXBLService::gRefCnt = 0;
     456                 : bool nsXBLService::gAllowDataURIs = false;
     457                 : 
     458                 : nsHashtable* nsXBLService::gClassTable = nsnull;
     459                 : 
     460                 : JSCList  nsXBLService::gClassLRUList = JS_INIT_STATIC_CLIST(&nsXBLService::gClassLRUList);
     461                 : PRUint32 nsXBLService::gClassLRUListLength = 0;
     462                 : PRUint32 nsXBLService::gClassLRUListQuota = 64;
     463                 : 
     464                 : // Implement our nsISupports methods
     465               0 : NS_IMPL_ISUPPORTS3(nsXBLService, nsIXBLService, nsIObserver, nsISupportsWeakReference)
     466                 : 
     467                 : // Constructors/Destructors
     468               0 : nsXBLService::nsXBLService(void)
     469                 : {
     470               0 :   mPool.Init("XBL Binding Requests", kBucketSizes, kNumBuckets, kInitialSize);
     471                 : 
     472               0 :   gRefCnt++;
     473               0 :   if (gRefCnt == 1) {
     474               0 :     gClassTable = new nsHashtable();
     475                 :   }
     476                 : 
     477               0 :   Preferences::AddBoolVarCache(&gAllowDataURIs, "layout.debug.enable_data_xbl");
     478               0 : }
     479                 : 
     480               0 : nsXBLService::~nsXBLService(void)
     481                 : {
     482               0 :   gRefCnt--;
     483               0 :   if (gRefCnt == 0) {
     484                 :     // Walk the LRU list removing and deleting the nsXBLJSClasses.
     485               0 :     FlushMemory();
     486                 : 
     487                 :     // Any straggling nsXBLJSClass instances held by unfinalized JS objects
     488                 :     // created for bindings will be deleted when those objects are finalized
     489                 :     // (and not put on gClassLRUList, because length >= quota).
     490               0 :     gClassLRUListLength = gClassLRUListQuota = 0;
     491                 : 
     492                 :     // At this point, the only hash table entries should be for referenced
     493                 :     // XBL class structs held by unfinalized JS binding objects.
     494               0 :     delete gClassTable;
     495               0 :     gClassTable = nsnull;
     496                 :   }
     497               0 : }
     498                 : 
     499                 : // static
     500                 : bool
     501               0 : nsXBLService::IsChromeOrResourceURI(nsIURI* aURI)
     502                 : {
     503               0 :   bool isChrome = false;
     504               0 :   bool isResource = false;
     505               0 :   if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && 
     506               0 :       NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
     507               0 :       return (isChrome || isResource);
     508               0 :   return false;
     509                 : }
     510                 : 
     511                 : 
     512                 : // This function loads a particular XBL file and installs all of the bindings
     513                 : // onto the element.
     514                 : NS_IMETHODIMP
     515               0 : nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
     516                 :                            nsIPrincipal* aOriginPrincipal, bool aAugmentFlag,
     517                 :                            nsXBLBinding** aBinding, bool* aResolveStyle) 
     518                 : {
     519               0 :   NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
     520                 :   
     521               0 :   *aBinding = nsnull;
     522               0 :   *aResolveStyle = false;
     523                 : 
     524                 :   nsresult rv;
     525                 : 
     526               0 :   nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
     527                 : 
     528               0 :   nsCAutoString urlspec;
     529               0 :   if (nsContentUtils::GetWrapperSafeScriptFilename(document, aURL, urlspec)) {
     530                 :     // Block an attempt to load a binding that has special wrapper
     531                 :     // automation needs.
     532                 : 
     533               0 :     return NS_OK;
     534                 :   }
     535                 : 
     536               0 :   nsBindingManager *bindingManager = document->BindingManager();
     537                 :   
     538               0 :   nsXBLBinding *binding = bindingManager->GetBinding(aContent);
     539               0 :   if (binding && !aAugmentFlag) {
     540               0 :     nsXBLBinding *styleBinding = binding->GetFirstStyleBinding();
     541               0 :     if (styleBinding) {
     542               0 :       if (binding->MarkedForDeath()) {
     543               0 :         FlushStyleBindings(aContent);
     544               0 :         binding = nsnull;
     545                 :       }
     546                 :       else {
     547                 :         // See if the URIs match.
     548               0 :         if (styleBinding->PrototypeBinding()->CompareBindingURI(aURL))
     549               0 :           return NS_OK;
     550               0 :         FlushStyleBindings(aContent);
     551               0 :         binding = nsnull;
     552                 :       }
     553                 :     }
     554                 :   }
     555                 : 
     556                 :   bool ready;
     557               0 :   nsRefPtr<nsXBLBinding> newBinding;
     558               0 :   if (NS_FAILED(rv = GetBinding(aContent, aURL, false, aOriginPrincipal,
     559                 :                                 &ready, getter_AddRefs(newBinding)))) {
     560               0 :     return rv;
     561                 :   }
     562                 : 
     563               0 :   if (!newBinding) {
     564                 : #ifdef DEBUG
     565               0 :     nsCAutoString spec;
     566               0 :     aURL->GetSpec(spec);
     567               0 :     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);
     568               0 :     NS_ERROR(str.get());
     569                 : #endif
     570               0 :     return NS_OK;
     571                 :   }
     572                 : 
     573               0 :   if (::IsAncestorBinding(document, aURL, aContent)) {
     574               0 :     return NS_ERROR_ILLEGAL_VALUE;
     575                 :   }
     576                 : 
     577               0 :   if (aAugmentFlag) {
     578                 :     nsXBLBinding *baseBinding;
     579               0 :     nsXBLBinding *nextBinding = newBinding;
     580               0 :     do {
     581               0 :       baseBinding = nextBinding;
     582               0 :       nextBinding = baseBinding->GetBaseBinding();
     583               0 :       baseBinding->SetIsStyleBinding(false);
     584                 :     } while (nextBinding);
     585                 : 
     586                 :     // XXX Handle adjusting the prototype chain! We need to somehow indicate to
     587                 :     // InstallImplementation that the whole chain should just be whacked and rebuilt.
     588                 :     // We are becoming the new binding.
     589               0 :     baseBinding->SetBaseBinding(binding);
     590               0 :     bindingManager->SetBinding(aContent, newBinding);
     591                 :   }
     592                 :   else {
     593                 :     // We loaded a style binding.  It goes on the end.
     594               0 :     if (binding) {
     595                 :       // Get the last binding that is in the append layer.
     596               0 :       binding->RootBinding()->SetBaseBinding(newBinding);
     597                 :     }
     598                 :     else {
     599                 :       // Install the binding on the content node.
     600               0 :       bindingManager->SetBinding(aContent, newBinding);
     601                 :     }
     602                 :   }
     603                 : 
     604                 :   {
     605               0 :     nsAutoScriptBlocker scriptBlocker;
     606                 : 
     607                 :     // Set the binding's bound element.
     608               0 :     newBinding->SetBoundElement(aContent);
     609                 : 
     610                 :     // Tell the binding to build the anonymous content.
     611               0 :     newBinding->GenerateAnonymousContent();
     612                 : 
     613                 :     // Tell the binding to install event handlers
     614               0 :     newBinding->InstallEventHandlers();
     615                 : 
     616                 :     // Set up our properties
     617               0 :     rv = newBinding->InstallImplementation();
     618               0 :     NS_ENSURE_SUCCESS(rv, rv);
     619                 : 
     620                 :     // Figure out if we have any scoped sheets.  If so, we do a second resolve.
     621               0 :     *aResolveStyle = newBinding->HasStyleSheets();
     622                 :   
     623               0 :     newBinding.swap(*aBinding);
     624                 :   }
     625                 : 
     626               0 :   return NS_OK; 
     627                 : }
     628                 : 
     629                 : nsresult
     630               0 : nsXBLService::FlushStyleBindings(nsIContent* aContent)
     631                 : {
     632               0 :   nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
     633                 : 
     634               0 :   nsBindingManager *bindingManager = document->BindingManager();
     635                 :   
     636               0 :   nsXBLBinding *binding = bindingManager->GetBinding(aContent);
     637                 :   
     638               0 :   if (binding) {
     639               0 :     nsXBLBinding *styleBinding = binding->GetFirstStyleBinding();
     640                 : 
     641               0 :     if (styleBinding) {
     642                 :       // Clear out the script references.
     643               0 :       styleBinding->ChangeDocument(document, nsnull);
     644                 :     }
     645                 : 
     646               0 :     if (styleBinding == binding) 
     647               0 :       bindingManager->SetBinding(aContent, nsnull); // Flush old style bindings
     648                 :   }
     649                 :    
     650               0 :   return NS_OK;
     651                 : }
     652                 : 
     653                 : NS_IMETHODIMP
     654               0 : nsXBLService::ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID,
     655                 :                          nsIAtom** aResult)
     656                 : {
     657               0 :   nsIDocument* document = aContent->OwnerDoc();
     658               0 :   *aResult = document->BindingManager()->ResolveTag(aContent, aNameSpaceID);
     659               0 :   NS_IF_ADDREF(*aResult);
     660                 : 
     661               0 :   return NS_OK;
     662                 : }
     663                 : 
     664                 : 
     665                 : //
     666                 : // AttachGlobalKeyHandler
     667                 : //
     668                 : // Creates a new key handler and prepares to listen to key events on the given
     669                 : // event receiver (either a document or an content node). If the receiver is content,
     670                 : // then extra work needs to be done to hook it up to the document (XXX WHY??)
     671                 : //
     672                 : NS_IMETHODIMP
     673               0 : nsXBLService::AttachGlobalKeyHandler(nsIDOMEventTarget* aTarget)
     674                 : {
     675                 :   // check if the receiver is a content node (not a document), and hook
     676                 :   // it to the document if that is the case.
     677               0 :   nsCOMPtr<nsIDOMEventTarget> piTarget = aTarget;
     678               0 :   nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
     679               0 :   if (contentNode) {
     680                 :     // Only attach if we're really in a document
     681               0 :     nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc();
     682               0 :     if (doc)
     683               0 :       piTarget = doc; // We're a XUL keyset. Attach to our document.
     684                 :   }
     685                 : 
     686               0 :   nsEventListenerManager* manager = piTarget->GetListenerManager(true);
     687                 :     
     688               0 :   if (!piTarget || !manager)
     689               0 :     return NS_ERROR_FAILURE;
     690                 : 
     691                 :   // the listener already exists, so skip this
     692               0 :   if (contentNode && contentNode->GetProperty(nsGkAtoms::listener))
     693               0 :     return NS_OK;
     694                 :     
     695               0 :   nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(contentNode));
     696                 : 
     697                 :   // Create the key handler
     698                 :   nsXBLWindowKeyHandler* handler;
     699               0 :   NS_NewXBLWindowKeyHandler(elt, piTarget, &handler); // This addRef's
     700               0 :   if (!handler)
     701               0 :     return NS_ERROR_FAILURE;
     702                 : 
     703                 :   // listen to these events
     704               0 :   manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
     705                 :                                   NS_EVENT_FLAG_BUBBLE |
     706               0 :                                   NS_EVENT_FLAG_SYSTEM_EVENT);
     707               0 :   manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
     708                 :                                   NS_EVENT_FLAG_BUBBLE |
     709               0 :                                   NS_EVENT_FLAG_SYSTEM_EVENT);
     710               0 :   manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
     711                 :                                   NS_EVENT_FLAG_BUBBLE |
     712               0 :                                   NS_EVENT_FLAG_SYSTEM_EVENT);
     713                 : 
     714               0 :   if (contentNode)
     715               0 :     return contentNode->SetProperty(nsGkAtoms::listener, handler,
     716               0 :                                     nsPropertyTable::SupportsDtorFunc, true);
     717                 : 
     718                 :   // release the handler. The reference will be maintained by the event target,
     719                 :   // and, if there is a content node, the property.
     720               0 :   NS_RELEASE(handler);
     721               0 :   return NS_OK;
     722                 : }
     723                 : 
     724                 : //
     725                 : // DetachGlobalKeyHandler
     726                 : //
     727                 : // Removes a key handler added by DeatchGlobalKeyHandler.
     728                 : //
     729                 : NS_IMETHODIMP
     730               0 : nsXBLService::DetachGlobalKeyHandler(nsIDOMEventTarget* aTarget)
     731                 : {
     732               0 :   nsCOMPtr<nsIDOMEventTarget> piTarget = aTarget;
     733               0 :   nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
     734               0 :   if (!contentNode) // detaching is only supported for content nodes
     735               0 :     return NS_ERROR_FAILURE;
     736                 : 
     737                 :   // Only attach if we're really in a document
     738               0 :   nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc();
     739               0 :   if (doc)
     740               0 :     piTarget = do_QueryInterface(doc);
     741                 : 
     742               0 :   nsEventListenerManager* manager = piTarget->GetListenerManager(true);
     743                 :     
     744               0 :   if (!piTarget || !manager)
     745               0 :     return NS_ERROR_FAILURE;
     746                 : 
     747                 :   nsIDOMEventListener* handler =
     748               0 :     static_cast<nsIDOMEventListener*>(contentNode->GetProperty(nsGkAtoms::listener));
     749               0 :   if (!handler)
     750               0 :     return NS_ERROR_FAILURE;
     751                 : 
     752               0 :   manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
     753                 :                                      NS_EVENT_FLAG_BUBBLE |
     754               0 :                                      NS_EVENT_FLAG_SYSTEM_EVENT);
     755               0 :   manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
     756                 :                                      NS_EVENT_FLAG_BUBBLE |
     757               0 :                                      NS_EVENT_FLAG_SYSTEM_EVENT);
     758               0 :   manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
     759                 :                                      NS_EVENT_FLAG_BUBBLE |
     760               0 :                                      NS_EVENT_FLAG_SYSTEM_EVENT);
     761                 : 
     762               0 :   contentNode->DeleteProperty(nsGkAtoms::listener);
     763                 : 
     764               0 :   return NS_OK;
     765                 : }
     766                 : 
     767                 : NS_IMETHODIMP
     768               0 : nsXBLService::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
     769                 : {
     770               0 :   if (nsCRT::strcmp(aTopic, "memory-pressure") == 0)
     771               0 :     FlushMemory();
     772                 : 
     773               0 :   return NS_OK;
     774                 : }
     775                 : 
     776                 : nsresult
     777               0 : nsXBLService::FlushMemory()
     778                 : {
     779               0 :   while (!JS_CLIST_IS_EMPTY(&gClassLRUList)) {
     780               0 :     JSCList* lru = gClassLRUList.next;
     781               0 :     nsXBLJSClass* c = static_cast<nsXBLJSClass*>(lru);
     782                 : 
     783               0 :     JS_REMOVE_AND_INIT_LINK(lru);
     784               0 :     delete c;
     785               0 :     gClassLRUListLength--;
     786                 :   }
     787               0 :   return NS_OK;
     788                 : }
     789                 : 
     790                 : // Internal helper methods ////////////////////////////////////////////////////////////////
     791                 : 
     792               0 : NS_IMETHODIMP nsXBLService::BindingReady(nsIContent* aBoundElement, 
     793                 :                                          nsIURI* aURI, 
     794                 :                                          bool* aIsReady)
     795                 : {
     796                 :   // Don't do a security check here; we know this binding is set to go.
     797               0 :   return GetBinding(aBoundElement, aURI, true, nsnull, aIsReady, nsnull);
     798                 : }
     799                 : 
     800                 : nsresult
     801               0 : nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI, 
     802                 :                          bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
     803                 :                          bool* aIsReady, nsXBLBinding** aResult)
     804                 : {
     805                 :   // More than 6 binding URIs are rare, see bug 55070 comment 18.
     806               0 :   nsAutoTArray<nsIURI*, 6> uris;
     807                 :   return GetBinding(aBoundElement, aURI, aPeekOnly, aOriginPrincipal, aIsReady,
     808               0 :                     aResult, uris);
     809                 : }
     810                 : 
     811                 : nsresult
     812               0 : nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI, 
     813                 :                          bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
     814                 :                          bool* aIsReady, nsXBLBinding** aResult,
     815                 :                          nsTArray<nsIURI*>& aDontExtendURIs)
     816                 : {
     817               0 :   NS_ASSERTION(aPeekOnly || aResult,
     818                 :                "Must have non-null out param if not just peeking to see "
     819                 :                "whether the binding is ready");
     820                 :   
     821               0 :   if (aResult)
     822               0 :     *aResult = nsnull;
     823                 : 
     824               0 :   if (!aURI)
     825               0 :     return NS_ERROR_FAILURE;
     826                 : 
     827               0 :   nsCAutoString ref;
     828               0 :   aURI->GetRef(ref);
     829                 : 
     830               0 :   nsCOMPtr<nsIDocument> boundDocument = aBoundElement->OwnerDoc();
     831                 : 
     832               0 :   nsRefPtr<nsXBLDocumentInfo> docInfo;
     833                 :   nsresult rv = LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI,
     834                 :                                         aOriginPrincipal,
     835               0 :                                         false, getter_AddRefs(docInfo));
     836               0 :   NS_ENSURE_SUCCESS(rv, rv);
     837                 :   
     838               0 :   if (!docInfo)
     839               0 :     return NS_ERROR_FAILURE;
     840                 : 
     841               0 :   nsXBLPrototypeBinding* protoBinding = docInfo->GetPrototypeBinding(ref);
     842                 : 
     843               0 :   NS_WARN_IF_FALSE(protoBinding, "Unable to locate an XBL binding");
     844               0 :   if (!protoBinding)
     845               0 :     return NS_ERROR_FAILURE;
     846                 : 
     847               0 :   NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(protoBinding->BindingURI()),
     848                 :                  NS_ERROR_OUT_OF_MEMORY);
     849               0 :   nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
     850               0 :   if (altBindingURI) {
     851               0 :     NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(altBindingURI),
     852                 :                    NS_ERROR_OUT_OF_MEMORY);
     853                 :   }
     854                 : 
     855                 :   // Our prototype binding must have all its resources loaded.
     856               0 :   bool ready = protoBinding->LoadResources();
     857               0 :   if (!ready) {
     858                 :     // Add our bound element to the protos list of elts that should
     859                 :     // be notified when the stylesheets and scripts finish loading.
     860               0 :     protoBinding->AddResourceListener(aBoundElement);
     861               0 :     return NS_ERROR_FAILURE; // The binding isn't ready yet.
     862                 :   }
     863                 : 
     864               0 :   rv = protoBinding->ResolveBaseBinding();
     865               0 :   NS_ENSURE_SUCCESS(rv, rv);
     866                 : 
     867                 :   nsIURI* baseBindingURI;
     868               0 :   nsXBLPrototypeBinding* baseProto = protoBinding->GetBasePrototype();
     869               0 :   if (baseProto) {
     870               0 :     baseBindingURI = baseProto->BindingURI();
     871                 :   }
     872                 :   else {
     873               0 :     baseBindingURI = protoBinding->GetBaseBindingURI();
     874               0 :     if (baseBindingURI) {
     875               0 :       PRUint32 count = aDontExtendURIs.Length();
     876               0 :       for (PRUint32 index = 0; index < count; ++index) {
     877                 :         bool equal;
     878               0 :         rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal);
     879               0 :         NS_ENSURE_SUCCESS(rv, rv);
     880               0 :         if (equal) {
     881               0 :           nsCAutoString spec, basespec;
     882               0 :           protoBinding->BindingURI()->GetSpec(spec);
     883               0 :           NS_ConvertUTF8toUTF16 protoSpec(spec);
     884               0 :           baseBindingURI->GetSpec(basespec);
     885               0 :           NS_ConvertUTF8toUTF16 baseSpecUTF16(basespec);
     886               0 :           const PRUnichar* params[] = { protoSpec.get(), baseSpecUTF16.get() };
     887                 :           nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     888                 :                                           "XBL", nsnull,
     889                 :                                           nsContentUtils::eXBL_PROPERTIES,
     890                 :                                           "CircularExtendsBinding",
     891                 :                                           params, ArrayLength(params),
     892               0 :                                           boundDocument->GetDocumentURI());
     893               0 :           return NS_ERROR_ILLEGAL_VALUE;
     894                 :         }
     895                 :       }
     896                 :     }
     897                 :   }
     898                 : 
     899               0 :   nsRefPtr<nsXBLBinding> baseBinding;
     900               0 :   if (baseBindingURI) {
     901               0 :     nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement();
     902                 :     rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly,
     903               0 :                     child->NodePrincipal(), aIsReady,
     904               0 :                     getter_AddRefs(baseBinding), aDontExtendURIs);
     905               0 :     if (NS_FAILED(rv))
     906               0 :       return rv; // We aren't ready yet.
     907                 :   }
     908                 : 
     909               0 :   *aIsReady = true;
     910                 : 
     911               0 :   if (!aPeekOnly) {
     912                 :     // Make a new binding
     913               0 :     nsXBLBinding *newBinding = new nsXBLBinding(protoBinding);
     914               0 :     NS_ENSURE_TRUE(newBinding, NS_ERROR_OUT_OF_MEMORY);
     915                 : 
     916               0 :     if (baseBinding) {
     917               0 :       if (!baseProto) {
     918               0 :         protoBinding->SetBasePrototype(baseBinding->PrototypeBinding());
     919                 :       }
     920               0 :        newBinding->SetBaseBinding(baseBinding);
     921                 :     }
     922                 : 
     923               0 :     NS_ADDREF(*aResult = newBinding);
     924                 :   }
     925                 : 
     926               0 :   return NS_OK;
     927                 : }
     928                 : 
     929               0 : static bool SchemeIs(nsIURI* aURI, const char* aScheme)
     930                 : {
     931               0 :   nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
     932               0 :   NS_ENSURE_TRUE(baseURI, false);
     933                 : 
     934               0 :   bool isScheme = false;
     935               0 :   return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
     936                 : }
     937                 : 
     938                 : static bool
     939               0 : IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal)
     940                 : {
     941               0 :   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     942               0 :     return true;
     943                 :   }
     944                 :   
     945               0 :   nsCOMPtr<nsIURI> uri;
     946               0 :   aPrincipal->GetURI(getter_AddRefs(uri));
     947               0 :   NS_ENSURE_TRUE(uri, false);
     948                 :   
     949               0 :   bool isChrome = false;
     950               0 :   return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome;
     951                 : }
     952                 : 
     953                 : NS_IMETHODIMP
     954               0 : nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
     955                 :                                       nsIDocument* aBoundDocument,
     956                 :                                       nsIURI* aBindingURI,
     957                 :                                       nsIPrincipal* aOriginPrincipal,
     958                 :                                       bool aForceSyncLoad,
     959                 :                                       nsXBLDocumentInfo** aResult)
     960                 : {
     961               0 :   NS_PRECONDITION(aBindingURI, "Must have a binding URI");
     962               0 :   NS_PRECONDITION(!aOriginPrincipal || aBoundDocument,
     963                 :                   "If we're doing a security check, we better have a document!");
     964                 :   
     965                 :   nsresult rv;
     966               0 :   if (aOriginPrincipal) {
     967                 :     // Security check - Enforce same-origin policy, except to chrome.
     968                 :     // We have to be careful to not pass aContent as the context here. 
     969                 :     // Otherwise, if there is a JS-implemented content policy, we will attempt
     970                 :     // to wrap the content node, which will try to load XBL bindings for it, if
     971                 :     // any. Since we're not done loading this binding yet, that will reenter
     972                 :     // this method and we'll end up creating a binding and then immediately
     973                 :     // clobbering it in our table.  That makes things very confused, leading to
     974                 :     // misbehavior and crashes.
     975                 :     rv = nsContentUtils::
     976                 :       CheckSecurityBeforeLoad(aBindingURI, aOriginPrincipal,
     977                 :                               nsIScriptSecurityManager::ALLOW_CHROME,
     978                 :                               gAllowDataURIs,
     979                 :                               nsIContentPolicy::TYPE_XBL,
     980               0 :                               aBoundDocument);
     981               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
     982                 : 
     983               0 :     if (!IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
     984                 :       // Also make sure that we're same-origin with the bound document
     985                 :       // except if the stylesheet has the system principal.
     986               0 :       if (!(gAllowDataURIs && SchemeIs(aBindingURI, "data")) &&
     987               0 :           !SchemeIs(aBindingURI, "chrome")) {
     988               0 :         rv = aBoundDocument->NodePrincipal()->CheckMayLoad(aBindingURI,
     989               0 :                                                            true);
     990               0 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
     991                 :       }
     992                 : 
     993                 :       // Finally check if this document is allowed to use XBL at all.
     994               0 :       NS_ENSURE_TRUE(aBoundDocument->AllowXULXBL(),
     995                 :                      NS_ERROR_XBL_BLOCKED);
     996                 :     }
     997                 :   }
     998                 : 
     999               0 :   *aResult = nsnull;
    1000               0 :   nsRefPtr<nsXBLDocumentInfo> info;
    1001                 : 
    1002               0 :   nsCOMPtr<nsIURI> documentURI;
    1003               0 :   rv = aBindingURI->CloneIgnoringRef(getter_AddRefs(documentURI));
    1004               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1005                 : 
    1006                 : #ifdef MOZ_XUL
    1007                 :   // We've got a file.  Check our XBL document cache.
    1008               0 :   nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
    1009               0 :   bool useXULCache = cache && cache->IsEnabled(); 
    1010                 : 
    1011               0 :   if (useXULCache) {
    1012                 :     // The first line of defense is the chrome cache.  
    1013                 :     // This cache crosses the entire product, so that any XBL bindings that are
    1014                 :     // part of chrome will be reused across all XUL documents.
    1015               0 :     info = cache->GetXBLDocumentInfo(documentURI); 
    1016                 :   }
    1017                 : #endif
    1018                 : 
    1019               0 :   if (!info) {
    1020                 :     // The second line of defense is the binding manager's document table.
    1021               0 :     nsBindingManager *bindingManager = nsnull;
    1022                 : 
    1023               0 :     if (aBoundDocument) {
    1024               0 :       bindingManager = aBoundDocument->BindingManager();
    1025               0 :       info = bindingManager->GetXBLDocumentInfo(documentURI);
    1026                 :     }
    1027                 : 
    1028               0 :     nsINodeInfo *ni = nsnull;
    1029               0 :     if (aBoundElement)
    1030               0 :       ni = aBoundElement->NodeInfo();
    1031                 : 
    1032               0 :     if (!info && bindingManager &&
    1033               0 :         (!ni || !(ni->Equals(nsGkAtoms::scrollbar, kNameSpaceID_XUL) ||
    1034               0 :                   ni->Equals(nsGkAtoms::thumb, kNameSpaceID_XUL) ||
    1035               0 :                   ((ni->Equals(nsGkAtoms::input) ||
    1036               0 :                     ni->Equals(nsGkAtoms::select)) &&
    1037               0 :                    aBoundElement->IsHTML()))) && !aForceSyncLoad) {
    1038                 :       // The third line of defense is to investigate whether or not the
    1039                 :       // document is currently being loaded asynchronously.  If so, there's no
    1040                 :       // document yet, but we need to glom on our request so that it will be
    1041                 :       // processed whenever the doc does finish loading.
    1042               0 :       nsCOMPtr<nsIStreamListener> listener;
    1043               0 :       if (bindingManager)
    1044               0 :         listener = bindingManager->GetLoadingDocListener(documentURI);
    1045               0 :       if (listener) {
    1046                 :         nsXBLStreamListener* xblListener =
    1047               0 :           static_cast<nsXBLStreamListener*>(listener.get());
    1048                 :         // Create a new load observer.
    1049               0 :         if (!xblListener->HasRequest(aBindingURI, aBoundElement)) {
    1050               0 :           nsXBLBindingRequest* req = nsXBLBindingRequest::Create(mPool, aBindingURI, aBoundElement);
    1051               0 :           xblListener->AddRequest(req);
    1052                 :         }
    1053               0 :         return NS_OK;
    1054                 :       }
    1055                 :     }
    1056                 : 
    1057                 : #ifdef MOZ_XUL
    1058                 :     // Next, look in the startup cache
    1059               0 :     bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI);
    1060               0 :     if (!info && useStartupCache) {
    1061               0 :       rv = nsXBLDocumentInfo::ReadPrototypeBindings(documentURI, getter_AddRefs(info));
    1062               0 :       if (NS_SUCCEEDED(rv)) {
    1063               0 :         cache->PutXBLDocumentInfo(info);
    1064                 : 
    1065               0 :         if (bindingManager) {
    1066                 :           // Cache it in our binding manager's document table.
    1067               0 :           bindingManager->PutXBLDocumentInfo(info);
    1068                 :         }
    1069                 :       }
    1070                 :     }
    1071                 : #endif
    1072                 : 
    1073               0 :     if (!info) {
    1074                 :       // Finally, if all lines of defense fail, we go and fetch the binding
    1075                 :       // document.
    1076                 :       
    1077                 :       // Always load chrome synchronously
    1078                 :       bool chrome;
    1079               0 :       if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome)
    1080               0 :         aForceSyncLoad = true;
    1081                 : 
    1082               0 :       nsCOMPtr<nsIDocument> document;
    1083                 :       FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
    1084               0 :                            aBindingURI, aForceSyncLoad, getter_AddRefs(document));
    1085                 : 
    1086               0 :       if (document) {
    1087               0 :         nsBindingManager *xblDocBindingManager = document->BindingManager();
    1088               0 :         info = xblDocBindingManager->GetXBLDocumentInfo(documentURI);
    1089               0 :         if (!info) {
    1090               0 :           NS_ERROR("An XBL file is malformed.  Did you forget the XBL namespace on the bindings tag?");
    1091               0 :           return NS_ERROR_FAILURE;
    1092                 :         }
    1093               0 :         xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
    1094                 : 
    1095                 :         // If the doc is a chrome URI, then we put it into the XUL cache.
    1096                 : #ifdef MOZ_XUL
    1097               0 :         if (useStartupCache) {
    1098               0 :           cache->PutXBLDocumentInfo(info);
    1099                 : 
    1100                 :           // now write the bindings into the startup cache
    1101               0 :           info->WritePrototypeBindings();
    1102                 :         }
    1103                 : #endif
    1104                 :         
    1105               0 :         if (bindingManager) {
    1106                 :           // Also put it in our binding manager's document table.
    1107               0 :           bindingManager->PutXBLDocumentInfo(info);
    1108                 :         }
    1109                 :       }
    1110                 :     }
    1111                 :   }
    1112                 : 
    1113               0 :   if (!info)
    1114               0 :     return NS_OK;
    1115                 :  
    1116               0 :   *aResult = info;
    1117               0 :   NS_IF_ADDREF(*aResult);
    1118                 : 
    1119               0 :   return NS_OK;
    1120                 : }
    1121                 : 
    1122                 : nsresult
    1123               0 : nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
    1124                 :                                    nsIURI* aDocumentURI, nsIURI* aBindingURI, 
    1125                 :                                    bool aForceSyncLoad, nsIDocument** aResult)
    1126                 : {
    1127                 :   NS_TIME_FUNCTION;
    1128                 : 
    1129               0 :   nsresult rv = NS_OK;
    1130                 :   // Initialize our out pointer to nsnull
    1131               0 :   *aResult = nsnull;
    1132                 : 
    1133                 :   // Now we have to synchronously load the binding file.
    1134                 :   // Create an XML content sink and a parser. 
    1135               0 :   nsCOMPtr<nsILoadGroup> loadGroup;
    1136               0 :   if (aBoundDocument)
    1137               0 :     loadGroup = aBoundDocument->GetDocumentLoadGroup();
    1138                 : 
    1139                 :   // We really shouldn't have to force a sync load for anything here... could
    1140                 :   // we get away with not doing that?  Not sure.
    1141               0 :   if (IsChromeOrResourceURI(aDocumentURI))
    1142               0 :     aForceSyncLoad = true;
    1143                 : 
    1144                 :   // Create document and contentsink and set them up.
    1145               0 :   nsCOMPtr<nsIDocument> doc;
    1146               0 :   rv = NS_NewXMLDocument(getter_AddRefs(doc));
    1147               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1148                 : 
    1149               0 :   nsCOMPtr<nsIXMLContentSink> xblSink;
    1150               0 :   rv = NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nsnull);
    1151               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1152                 : 
    1153                 :   // Open channel
    1154               0 :   nsCOMPtr<nsIChannel> channel;
    1155               0 :   rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nsnull, loadGroup);
    1156               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1157                 : 
    1158               0 :   nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::GetSameOriginChecker();
    1159               0 :   NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY);
    1160                 : 
    1161               0 :   channel->SetNotificationCallbacks(sameOriginChecker);
    1162                 : 
    1163               0 :   if (!aForceSyncLoad) {
    1164                 :     // We can be asynchronous
    1165                 :     nsXBLStreamListener* xblListener =
    1166               0 :       new nsXBLStreamListener(this, aBoundDocument, xblSink, doc);
    1167               0 :     NS_ENSURE_TRUE(xblListener,NS_ERROR_OUT_OF_MEMORY);
    1168                 : 
    1169                 :     // Add ourselves to the list of loading docs.
    1170                 :     nsBindingManager *bindingManager;
    1171               0 :     if (aBoundDocument)
    1172               0 :       bindingManager = aBoundDocument->BindingManager();
    1173                 :     else
    1174               0 :       bindingManager = nsnull;
    1175                 : 
    1176               0 :     if (bindingManager)
    1177               0 :       bindingManager->PutLoadingDocListener(aDocumentURI, xblListener);
    1178                 : 
    1179                 :     // Add our request.
    1180                 :     nsXBLBindingRequest* req = nsXBLBindingRequest::Create(mPool,
    1181                 :                                                            aBindingURI,
    1182               0 :                                                            aBoundElement);
    1183               0 :     xblListener->AddRequest(req);
    1184                 : 
    1185                 :     // Now kick off the async read.
    1186               0 :     rv = channel->AsyncOpen(xblListener, nsnull);
    1187               0 :     if (NS_FAILED(rv)) {
    1188                 :       // Well, we won't be getting a load.  Make sure to clean up our stuff!
    1189               0 :       if (bindingManager) {
    1190               0 :         bindingManager->RemoveLoadingDocListener(aDocumentURI);
    1191                 :       }
    1192                 :     }
    1193               0 :     return NS_OK;
    1194                 :   }
    1195                 : 
    1196               0 :   nsCOMPtr<nsIStreamListener> listener;
    1197               0 :   rv = doc->StartDocumentLoad("loadAsInteractiveData",
    1198                 :                               channel,
    1199                 :                               loadGroup,
    1200                 :                               nsnull,
    1201               0 :                               getter_AddRefs(listener),
    1202                 :                               true,
    1203               0 :                               xblSink);
    1204               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1205                 : 
    1206                 :   // Now do a blocking synchronous parse of the file.
    1207               0 :   nsCOMPtr<nsIInputStream> in;
    1208               0 :   rv = channel->Open(getter_AddRefs(in));
    1209               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1210                 : 
    1211               0 :   rv = nsSyncLoadService::PushSyncStreamToListener(in, listener, channel);
    1212               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1213                 : 
    1214               0 :   doc.swap(*aResult);
    1215                 : 
    1216               0 :   return NS_OK;
    1217                 : }
    1218                 : 
    1219                 : // Creation Routine ///////////////////////////////////////////////////////////////////////
    1220                 : 
    1221                 : nsresult NS_NewXBLService(nsIXBLService** aResult);
    1222                 : 
    1223                 : nsresult
    1224               0 : NS_NewXBLService(nsIXBLService** aResult)
    1225                 : {
    1226               0 :   nsXBLService* result = new nsXBLService;
    1227               0 :   if (! result)
    1228               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1229                 : 
    1230               0 :   NS_ADDREF(*aResult = result);
    1231                 : 
    1232                 :   // Register the first (and only) nsXBLService as a memory pressure observer
    1233                 :   // so it can flush the LRU list in low-memory situations.
    1234               0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1235               0 :   if (os)
    1236               0 :     os->AddObserver(result, "memory-pressure", true);
    1237                 : 
    1238               0 :   return NS_OK;
    1239                 : }
    1240                 : 

Generated by: LCOV version 1.7