Back to index

lightning-sunbird  0.9+nobinonly
nsXBLResourceLoader.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  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsICSSStyleSheet.h"
00040 #include "nsIStyleRuleProcessor.h"
00041 #include "nsIDocument.h"
00042 #include "nsIContent.h"
00043 #include "nsIPresShell.h"
00044 #include "nsIXBLService.h"
00045 #include "nsIServiceManager.h"
00046 #include "nsXBLResourceLoader.h"
00047 #include "nsXBLPrototypeResources.h"
00048 #include "nsIDocumentObserver.h"
00049 #include "imgILoader.h"
00050 #include "imgIRequest.h"
00051 #include "nsICSSLoader.h"
00052 #include "nsIXBLDocumentInfo.h"
00053 #include "nsIURI.h"
00054 #include "nsNetUtil.h"
00055 #include "nsXBLAtoms.h"
00056 #include "nsFrameManager.h"
00057 #include "nsStyleContext.h"
00058 #include "nsXBLPrototypeBinding.h"
00059 #include "nsCSSRuleProcessor.h"
00060 #include "nsContentUtils.h"
00061 
00062 NS_IMPL_ISUPPORTS1(nsXBLResourceLoader, nsICSSLoaderObserver)
00063 
00064 nsXBLResourceLoader::nsXBLResourceLoader(nsXBLPrototypeBinding* aBinding,
00065                                          nsXBLPrototypeResources* aResources)
00066 :mBinding(aBinding),
00067  mResources(aResources),
00068  mResourceList(nsnull),
00069  mLastResource(nsnull),
00070  mLoadingResources(PR_FALSE),
00071  mInLoadResourcesFunc(PR_FALSE),
00072  mPendingSheets(0)
00073 {
00074 }
00075 
00076 nsXBLResourceLoader::~nsXBLResourceLoader()
00077 {
00078   delete mResourceList;
00079 }
00080 
00081 void
00082 nsXBLResourceLoader::LoadResources(PRBool* aResult)
00083 {
00084   mInLoadResourcesFunc = PR_TRUE;
00085 
00086   if (mLoadingResources) {
00087     *aResult = (mPendingSheets == 0);
00088     mInLoadResourcesFunc = PR_FALSE;
00089     return;
00090   }
00091 
00092   mLoadingResources = PR_TRUE;
00093   *aResult = PR_TRUE;
00094 
00095   // Declare our loaders.
00096   nsCOMPtr<nsIDocument> doc;
00097   mBinding->XBLDocumentInfo()->GetDocument(getter_AddRefs(doc));
00098 
00099   nsICSSLoader* cssLoader = doc->CSSLoader();
00100   nsIURI *docURL = doc->GetDocumentURI();
00101 
00102   nsCOMPtr<nsIURI> url;
00103 
00104   for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
00105     if (curr->mSrc.IsEmpty())
00106       continue;
00107 
00108     if (NS_FAILED(NS_NewURI(getter_AddRefs(url), curr->mSrc,
00109                             doc->GetDocumentCharacterSet().get(), docURL)))
00110       continue;
00111 
00112     if (curr->mType == nsXBLAtoms::image) {
00113       if (!nsContentUtils::CanLoadImage(url, doc, doc)) {
00114         // We're not permitted to load this image, move on...
00115         continue;
00116       }
00117 
00118       // Now kick off the image load...
00119       // Passing NULL for pretty much everything -- cause we don't care!
00120       // XXX: initialDocumentURI is NULL! 
00121       nsCOMPtr<imgIRequest> req;
00122       nsContentUtils::LoadImage(url, doc, docURL, nsnull,
00123                                 nsIRequest::LOAD_BACKGROUND,
00124                                 getter_AddRefs(req));
00125     }
00126     else if (curr->mType == nsXBLAtoms::stylesheet) {
00127       // Kick off the load of the stylesheet.
00128 
00129       // Always load chrome synchronously
00130       PRBool chrome;
00131       nsresult rv;
00132       if (NS_SUCCEEDED(url->SchemeIs("chrome", &chrome)) && chrome)
00133       {
00134         nsCOMPtr<nsICSSStyleSheet> sheet;
00135         rv = cssLoader->LoadAgentSheet(url, getter_AddRefs(sheet));
00136         NS_ASSERTION(NS_SUCCEEDED(rv), "Load failed!!!");
00137         if (NS_SUCCEEDED(rv))
00138         {
00139           rv = StyleSheetLoaded(sheet, PR_TRUE);
00140           NS_ASSERTION(NS_SUCCEEDED(rv), "Processing the style sheet failed!!!");
00141         }
00142       }
00143       else
00144       {
00145         PRBool doneLoading;
00146         NS_NAMED_LITERAL_STRING(empty, "");
00147         rv = cssLoader->LoadStyleLink(nsnull, url, empty, empty,
00148                                       nsnull, doneLoading, this);
00149         NS_ASSERTION(NS_SUCCEEDED(rv), "Load failed!!!");
00150 
00151         if (!doneLoading)
00152           mPendingSheets++;
00153       }
00154     }
00155   }
00156 
00157   *aResult = (mPendingSheets == 0);
00158   mInLoadResourcesFunc = PR_FALSE;
00159   
00160   // Destroy our resource list.
00161   delete mResourceList;
00162   mResourceList = nsnull;
00163 }
00164 
00165 // nsICSSLoaderObserver
00166 NS_IMETHODIMP
00167 nsXBLResourceLoader::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify)
00168 {
00169   if (!mResources) {
00170     // Our resources got destroyed -- just bail out
00171     return NS_OK;
00172   }
00173    
00174   mResources->mStyleSheetList.AppendObject(aSheet);
00175 
00176   if (!mInLoadResourcesFunc)
00177     mPendingSheets--;
00178   
00179   if (mPendingSheets == 0) {
00180     // All stylesheets are loaded.  
00181     mResources->mRuleProcessor =
00182       new nsCSSRuleProcessor(mResources->mStyleSheetList);
00183 
00184     // XXX Check for mPendingScripts when scripts also come online.
00185     if (!mInLoadResourcesFunc)
00186       NotifyBoundElements();
00187   }
00188   return NS_OK;
00189 }
00190 
00191 void 
00192 nsXBLResourceLoader::AddResource(nsIAtom* aResourceType, const nsAString& aSrc)
00193 {
00194   nsXBLResource* res = new nsXBLResource(aResourceType, aSrc);
00195   if (!res)
00196     return;
00197 
00198   if (!mResourceList)
00199     mResourceList = res;
00200   else
00201     mLastResource->mNext = res;
00202 
00203   mLastResource = res;
00204 }
00205 
00206 void
00207 nsXBLResourceLoader::AddResourceListener(nsIContent* aBoundElement) 
00208 {
00209   if (!mBoundElements) {
00210     NS_NewISupportsArray(getter_AddRefs(mBoundElements));
00211     if (!mBoundElements)
00212       return;
00213   }
00214 
00215   mBoundElements->AppendElement(aBoundElement);
00216 }
00217 
00218 void
00219 nsXBLResourceLoader::NotifyBoundElements()
00220 {
00221   nsCOMPtr<nsIXBLService> xblService(do_GetService("@mozilla.org/xbl;1"));
00222   nsIURI* bindingURI = mBinding->BindingURI();
00223 
00224   PRUint32 eltCount;
00225   mBoundElements->Count(&eltCount);
00226   for (PRUint32 j = 0; j < eltCount; j++) {
00227     nsCOMPtr<nsIContent> content(do_QueryElementAt(mBoundElements, j));
00228     
00229     PRBool ready = PR_FALSE;
00230     xblService->BindingReady(content, bindingURI, &ready);
00231 
00232     if (ready) {
00233       // We need the document to flush out frame construction and
00234       // such, so we want to use the current document.
00235       nsIDocument* doc = content->GetCurrentDoc();
00236     
00237       if (doc) {
00238         // Flush first to make sure we can get the frame for content
00239         doc->FlushPendingNotifications(Flush_Frames);
00240 
00241         // If |content| is (in addition to having binding |mBinding|)
00242         // also a descendant of another element with binding |mBinding|,
00243         // then we might have just constructed it due to the
00244         // notification of its parent.  (We can know about both if the
00245         // binding loads were triggered from the DOM rather than frame
00246         // construction.)  So we have to check both whether the element
00247         // has a primary frame and whether it's in the undisplayed map
00248         // before sending a ContentInserted notification, or bad things
00249         // will happen.
00250         nsIPresShell *shell = doc->GetShellAt(0);
00251         if (shell) {
00252           nsIFrame* childFrame;
00253           shell->GetPrimaryFrameFor(content, &childFrame);
00254           if (!childFrame) {
00255             // Check to see if it's in the undisplayed content map.
00256             nsStyleContext* sc =
00257               shell->FrameManager()->GetUndisplayedContent(content);
00258 
00259             if (!sc) {
00260               shell->RecreateFramesFor(content);
00261             }
00262           }
00263         }
00264 
00265         // Flush again
00266         // XXXbz why is this needed?
00267         doc->FlushPendingNotifications(Flush_ContentAndNotify);
00268       }
00269     }
00270   }
00271 
00272   // Clear out the whole array.
00273   mBoundElements = nsnull;
00274 
00275   // Delete ourselves.
00276   NS_RELEASE(mResources->mLoader);
00277 }