Work on 48150 and XBL performance (async and arenas).

This commit is contained in:
hyatt%netscape.com 2000-08-14 04:04:18 +00:00
Родитель e98e347d11
Коммит 2e86033263
20 изменённых файлов: 500 добавлений и 180 удалений

Просмотреть файл

@ -74,6 +74,7 @@
#include "nsLayoutCID.h"
#include "nsGfxCIID.h"
#include "nsIImageManager.h"
#include "nsIBindingManager.h"
#include "prio.h"
static char kChromePrefix[] = "chrome://";
@ -1044,6 +1045,11 @@ NS_IMETHODIMP nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
if (!document)
return NS_OK;
// Annihilate all XBL bindings.
nsCOMPtr<nsIBindingManager> bindingManager;
document->GetBindingManager(getter_AddRefs(bindingManager));
bindingManager->FlushChromeBindings();
nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(domDocument);
if (xulDoc) {
// Deal with the backstop sheets first.

Просмотреть файл

@ -74,6 +74,7 @@ public:
NS_IMETHOD RemoveLoadingDocListener(const nsCString& aURL)=0;
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult) = 0;
NS_IMETHOD FlushChromeBindings() = 0;
};
#endif // nsIBinding_Manager_h__

Просмотреть файл

@ -91,6 +91,9 @@ public:
NS_IMETHOD WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData)=0;
NS_IMETHOD SetAllowScripts(PRBool aFlag)=0;
NS_IMETHOD MarkForDeath()=0;
NS_IMETHOD MarkedForDeath(PRBool* aResult)=0;
};
extern nsresult

Просмотреть файл

@ -59,6 +59,9 @@ public:
// This method loads a binding doc and then builds the specific binding required.
NS_IMETHOD GetBinding(nsIContent* aBoundElement, const nsCString& aURLStr, nsIXBLBinding** aResult) = 0;
// Indicates whether or not a binding is fully loaded.
NS_IMETHOD BindingReady(nsIContent* aBoundElement, const nsCString& aURLStr, PRBool* aIsReady) = 0;
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement,

Просмотреть файл

@ -178,7 +178,8 @@ public:
NS_IMETHOD RemoveLoadingDocListener(const nsCString& aURL);
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD FlushChromeBindings();
// nsIStyleRuleSupplier
NS_IMETHOD UseDocumentRules(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD WalkRules(nsIStyleSet* aStyleSet,
@ -252,8 +253,13 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding )
mBindingTable = new nsSupportsHashtable;
nsISupportsKey key(aContent);
nsCOMPtr<nsISupports> old = getter_AddRefs(mBindingTable->Get(&key));
if (old && aBinding)
NS_ERROR("Binding already installed!");
if (aBinding) {
mBindingTable->Put (&key, aBinding);
mBindingTable->Put(&key, aBinding);
}
else
mBindingTable->Remove(&key);
@ -393,7 +399,7 @@ nsBindingManager::ProcessAttachedQueue()
for (PRUint32 i = 0; i < count; i++) {
nsCOMPtr<nsIXBLBinding> binding;
mAttachedQueue->GetElementAt(0, getter_AddRefs(binding));
mAttachedQueue->RemoveElementAt(0);
mAttachedQueue->RemoveElementAt(0);
binding->ExecuteAttachedHandler();
}
@ -468,6 +474,23 @@ nsBindingManager::RemoveLoadingDocListener(const nsCString& aURL)
return NS_OK;
}
PRBool PR_CALLBACK MarkForDeath(nsHashKey* aKey, void* aData, void* aClosure)
{
nsIXBLBinding* binding = (nsIXBLBinding*)aData;
nsCAutoString docURI;
binding->GetDocURI(docURI);
if (!docURI.CompareWithConversion("chrome", PR_FALSE, 6))
binding->MarkForDeath();
return PR_TRUE;
}
NS_IMETHODIMP
nsBindingManager::FlushChromeBindings()
{
mBindingTable->Enumerate(MarkForDeath);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::InheritsStyle(nsIContent* aContent, PRBool* aResult)
{

Просмотреть файл

@ -252,11 +252,14 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
mIsStyleBinding(PR_TRUE),
mAllowScripts(PR_TRUE),
mInheritStyle(PR_TRUE),
mMarkedForDeath(PR_FALSE),
mAttributeTable(nsnull),
mInsertionPointTable(nsnull)
{
NS_INIT_REFCNT();
gRefCnt++;
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 1) {
kContentAtom = NS_NewAtom("content");
kInterfaceAtom = NS_NewAtom("interface");
@ -303,6 +306,8 @@ nsXBLBinding::~nsXBLBinding(void)
delete mInsertionPointTable;
gRefCnt--;
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 0) {
NS_RELEASE(kContentAtom);
NS_RELEASE(kInterfaceAtom);
@ -354,6 +359,11 @@ nsXBLBinding::GetBaseBinding(nsIXBLBinding** aResult)
NS_IMETHODIMP
nsXBLBinding::SetBaseBinding(nsIXBLBinding* aBinding)
{
if (mNextBinding) {
NS_ERROR("Base XBL binding is already defined!");
return NS_OK;
}
mNextBinding = aBinding; // Comptr handles rel/add
return NS_OK;
}
@ -1454,8 +1464,6 @@ nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
NS_IMETHODIMP
nsXBLBinding::ConstructAttributeTable(nsIContent* aElement)
{
// XXX This function still needs to deal with the
// ability to map one attribute to another.
nsAutoString inherits;
aElement->GetAttribute(kNameSpaceID_None, kInheritsAtom, inherits);
if (!inherits.IsEmpty()) {
@ -1745,7 +1753,19 @@ nsXBLBinding::GetFirstStyleBinding(nsIXBLBinding** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::MarkForDeath()
{
mMarkedForDeath = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::MarkedForDeath(PRBool* aResult)
{
*aResult = mMarkedForDeath;
return NS_OK;
}
// Creation Routine ///////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -85,6 +85,9 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD SetAllowScripts(PRBool aFlag) { mAllowScripts = aFlag; return NS_OK; };
NS_IMETHOD MarkForDeath();
NS_IMETHOD MarkedForDeath(PRBool* aResult);
public:
nsXBLBinding(const nsCString& aDocURI, const nsCString& aRef);
virtual ~nsXBLBinding();
@ -172,9 +175,10 @@ protected:
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
PRBool mIsStyleBinding;
PRBool mAllowScripts;
PRBool mInheritStyle;
PRPackedBool mIsStyleBinding;
PRPackedBool mAllowScripts;
PRPackedBool mInheritStyle;
PRPackedBool mMarkedForDeath;
nsSupportsHashtable* mAttributeTable; // A table for attribute entries.
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points.

Просмотреть файл

@ -25,6 +25,7 @@
#include "nsCOMPtr.h"
#include "nsXBLService.h"
#include "nsIInputStream.h"
#include "nsINameSpace.h"
#include "nsINameSpaceManager.h"
#include "nsHashtable.h"
#include "nsIURI.h"
@ -37,6 +38,7 @@
#include "nsNetUtil.h"
#include "plstr.h"
#include "nsIContent.h"
#include "nsIXMLContent.h"
#include "nsIDOMElement.h"
#include "nsIDocument.h"
#include "nsIXMLContentSink.h"
@ -52,6 +54,9 @@
#include "nsIChromeRegistry.h"
#include "nsIPref.h"
#include "nsIPresShell.h"
#include "nsIDocumentObserver.h"
#include "nsIXULContentUtils.h"
#include "nsIXULPrototypeCache.h"
#include "nsIDOMLoadListener.h"
@ -104,55 +109,56 @@ struct nsXBLBindingRequest
}
}
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
return aAllocator.Alloc(aSize);
}
static void operator delete(void* aPtr, size_t aSize) {
nsFixedSizeAllocator::Free(aPtr, aSize);
}
void DocumentLoaded(nsIDocument* aBindingDoc)
{
// Get the binding.
nsCOMPtr<nsIXBLBinding> newBinding;
gXBLService->GetBinding(mBoundElement, mBindingURL, getter_AddRefs(newBinding));
// XXX Deal with layered bindings.
// XXX Deal with cross-site inheritance (e.g., http://a/a.xml inheriting from http://b/b.xml)
// Install the binding on the content node.
nsCOMPtr<nsIDocument> doc;
mBoundElement->GetDocument(*getter_AddRefs(doc));
if (!doc)
return;
nsCOMPtr<nsIBindingManager> bindingManager;
doc->GetBindingManager(getter_AddRefs(bindingManager));
bindingManager->SetBinding(mBoundElement, newBinding);
// Set the binding's bound element.
newBinding->SetBoundElement(mBoundElement);
// Get the binding.
PRBool ready = PR_FALSE;
gXBLService->BindingReady(mBoundElement, mBindingURL, &ready);
// Tell the binding to build the anonymous content.
newBinding->GenerateAnonymousContent(mBoundElement);
// Tell the binding to install event handlers
nsCOMPtr<nsIXBLBinding> attachReq;
newBinding->InstallEventHandlers(mBoundElement, getter_AddRefs(attachReq));
// Set up our properties
newBinding->InstallProperties(mBoundElement);
if (attachReq) {
attachReq->ExecuteAttachedHandler();
}
if (!ready)
return;
// XXX Deal with layered bindings.
// Now do a ContentInserted notification to cause the frames to get installed finally,
nsCOMPtr<nsIContent> parent;
mBoundElement->GetParent(*getter_AddRefs(parent));
PRInt32 index = 0;
if (parent)
parent->IndexOf(mBoundElement, index);
if (index == -1)
return;
doc->ContentInserted(parent, mBoundElement, index);
nsCOMPtr<nsIPresShell> shell = getter_AddRefs(doc->GetShellAt(0));
if (shell) {
nsCOMPtr<nsIDocumentObserver> obs(do_QueryInterface(shell));
obs->ContentRemoved(doc, parent, mBoundElement, index);
obs->ContentInserted(doc, parent, mBoundElement, index);
}
}
static nsIXBLService* gXBLService;
static int gRefCnt;
};
static const size_t kBucketSizes[] = {
sizeof(nsXBLBindingRequest)
};
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
static const PRInt32 kNumElements = 64;
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLBindingRequest))) * kNumElements;
nsIXBLService* nsXBLBindingRequest::gXBLService = nsnull;
int nsXBLBindingRequest::gRefCnt = 0;
@ -180,12 +186,13 @@ public:
virtual ~nsXBLStreamListener();
void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); };
PRBool HasRequest(const nsCString& aURI, nsIContent* aBoundElement);
private:
nsCOMPtr<nsIStreamListener> mInner;
nsVoidArray mBindingRequests;
nsCOMPtr<nsIDocument> mDocument;
nsIDocument* mDocument;
nsCOMPtr<nsIDocument> mBindingDocument;
};
@ -264,17 +271,34 @@ nsXBLStreamListener::OnStopRequest(nsIChannel* aChannel, nsISupports* aCtxt, nsr
rv = mInner->OnStopRequest(aChannel, aCtxt, aStatus, aStatusArg);
}
if (NS_FAILED(rv)) {
if (NS_FAILED(rv) || NS_FAILED(aStatus)) {
PRUint32 count = mBindingRequests.Count();
for (PRUint32 i = 0; i < count; i++) {
nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
delete req;
}
mDocument = nsnull;
mBindingDocument = nsnull;
}
return rv;
}
PRBool
nsXBLStreamListener::HasRequest(const nsCString& aURI, nsIContent* aElt)
{
// XXX Could be more efficient.
PRUint32 count = mBindingRequests.Count();
for (PRUint32 i = 0; i < count; i++) {
nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
if (req->mBindingURL.Equals(aURI) && req->mBoundElement.get() == aElt)
return PR_TRUE;
}
return PR_FALSE;
}
nsresult
nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
{
@ -312,8 +336,9 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
info->SetScriptAccess(allow);
}
}
bindingManager->PutXBLDocumentInfo(info);
if (!cached)
bindingManager->PutXBLDocumentInfo(info);
// Notify all pending requests that their bindings are
// ready and can be installed.
@ -328,9 +353,12 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
delete req;
}
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mDocument));
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mBindingDocument));
rec->RemoveEventListener(NS_ConvertASCIItoUCS2("load"), (nsIDOMLoadListener*)this, PR_FALSE);
mDocument = nsnull;
mBindingDocument = nsnull;
return rv;
}
@ -406,7 +434,7 @@ PRUint32 nsXBLService::gClassLRUListLength = 0;
PRUint32 nsXBLService::gClassLRUListQuota = 64;
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
nsIAtom* nsXBLService::kHasChildrenAtom = nsnull;
nsIAtom* nsXBLService::kScrollbarAtom = nsnull;
// Enabled by default. Must be over-ridden to disable
PRBool nsXBLService::gDisableChromeCache = PR_FALSE;
@ -421,6 +449,8 @@ NS_IMPL_ISUPPORTS2(nsXBLService, nsIXBLService, nsIMemoryPressureObserver)
nsXBLService::nsXBLService(void)
{
NS_INIT_REFCNT();
mPool.Init("XBL Binding Requests", kBucketSizes, kNumBuckets, kInitialSize);
gRefCnt++;
if (gRefCnt == 1) {
@ -442,8 +472,8 @@ nsXBLService::nsXBLService(void)
// Create our atoms
kExtendsAtom = NS_NewAtom("extends");
kHasChildrenAtom = NS_NewAtom("haschildren");
kScrollbarAtom = NS_NewAtom("scrollbar");
// Find out if the XUL cache is on or off
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv);
if (NS_SUCCEEDED(rv))
@ -476,8 +506,8 @@ nsXBLService::~nsXBLService(void)
// Release our atoms
NS_RELEASE(kExtendsAtom);
NS_RELEASE(kHasChildrenAtom);
NS_RELEASE(kScrollbarAtom);
// Walk the LRU list removing and deleting the nsXBLJSClasses.
FlushMemory(REASON_HEAP_MINIMIZE, 0);
@ -526,15 +556,23 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aA
nsCOMPtr<nsIXBLBinding> styleBinding;
binding->GetFirstStyleBinding(getter_AddRefs(styleBinding));
if (styleBinding) {
// See if the URIs match.
nsCAutoString uri;
styleBinding->GetBindingURI(uri);
if (uri.EqualsWithConversion(aURL))
return NS_OK;
else {
PRBool marked = PR_FALSE;
binding->MarkedForDeath(&marked);
if (marked) {
FlushStyleBindings(aContent);
binding = nsnull;
}
else {
// See if the URIs match.
nsCAutoString uri;
styleBinding->GetBindingURI(uri);
if (uri.EqualsWithConversion(aURL))
return NS_OK;
else {
FlushStyleBindings(aContent);
binding = nsnull;
}
}
}
}
@ -736,9 +774,29 @@ nsXBLService::FlushMemory(PRUint32 reason, size_t requestedAmount)
// Internal helper methods ////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsXBLService::GetBinding(nsIContent* aBoundElement, const nsCString& aURLStr, nsIXBLBinding** aResult)
NS_IMETHODIMP nsXBLService::GetBinding(nsIContent* aBoundElement,
const nsCString& aURLStr,
nsIXBLBinding** aResult)
{
*aResult = nsnull;
PRBool dummy;
return GetBindingInternal(aBoundElement, aURLStr, PR_FALSE, &dummy, aResult);
}
NS_IMETHODIMP nsXBLService::BindingReady(nsIContent* aBoundElement,
const nsCString& aURLStr,
PRBool* aIsReady)
{
return GetBindingInternal(aBoundElement, aURLStr, PR_TRUE, aIsReady, nsnull);
}
NS_IMETHODIMP nsXBLService::GetBindingInternal(nsIContent* aBoundElement,
const nsCString& aURLStr,
PRBool aPeekOnly,
PRBool* aIsReady,
nsIXBLBinding** aResult)
{
if (aResult)
*aResult = nsnull;
if (aURLStr.IsEmpty())
return NS_ERROR_FAILURE;
@ -781,32 +839,53 @@ NS_IMETHODIMP nsXBLService::GetBinding(nsIContent* aBoundElement, const nsCStrin
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, value);
// If no ref is specified just use this.
if ((bindingName.IsEmpty()) || (bindingName == value)) {
// Make a new binding
NS_NewXBLBinding(uri, ref, aResult);
// Initialize its bound element.
(*aResult)->SetBindingElement(child);
(*aResult)->SetAllowScripts(allowScripts);
if ((bindingName.IsEmpty()) || (bindingName == value)) {
// Check for the presence of an extends attribute
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, value);
if (!value.IsEmpty()) {
// See if we are extending a builtin tag.
nsCOMPtr<nsIAtom> tag;
PRInt32 dummy;
(*aResult)->GetBaseTag(&dummy, getter_AddRefs(tag));
if (!tag) {
// We have a base class binding. Load it right now.
nsCOMPtr<nsIXBLBinding> baseBinding;
nsCAutoString urlCString; urlCString.AssignWithConversion(value);
GetBinding(aBoundElement, urlCString, getter_AddRefs(baseBinding));
if (!baseBinding)
return NS_OK; // At least we got the derived class binding loaded.
(*aResult)->SetBaseBinding(baseBinding);
nsAutoString extends;
nsCOMPtr<nsIXBLBinding> baseBinding;
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
value = extends;
if (!extends.IsEmpty()) {
nsAutoString prefix;
PRInt32 offset = extends.FindChar(':');
if (-1 != offset) {
extends.Left(prefix, offset);
extends.Cut(0, offset+1);
}
if (prefix.Length() > 0) {
// Look up the prefix.
nsCOMPtr<nsIAtom> prefixAtom = getter_AddRefs(NS_NewAtom(prefix));
nsCOMPtr<nsINameSpace> nameSpace;
nsCOMPtr<nsIXMLContent> xmlContent(do_QueryInterface(child));
if (xmlContent) {
xmlContent->GetContainingNameSpace(*getter_AddRefs(nameSpace));
if (nameSpace) {
nsCOMPtr<nsINameSpace> tagSpace;
nameSpace->FindNameSpace(prefixAtom, *getter_AddRefs(tagSpace));
if (!tagSpace) {
// We have a base class binding. Load it right now.
nsCAutoString urlCString; urlCString.AssignWithConversion(value);
GetBindingInternal(aBoundElement, urlCString, aPeekOnly, aIsReady, getter_AddRefs(baseBinding));
if (!*aIsReady)
return NS_ERROR_FAILURE; // Binding not yet ready or an error occurred.
}
}
}
}
}
*aIsReady = PR_TRUE;
if (!aPeekOnly) {
// Make a new binding
NS_NewXBLBinding(uri, ref, aResult);
// Initialize its bound element.
(*aResult)->SetBindingElement(child);
(*aResult)->SetAllowScripts(allowScripts);
if (baseBinding)
(*aResult)->SetBaseBinding(baseBinding);
}
break;
}
}
@ -839,7 +918,9 @@ nsXBLService::GetBindingDocumentInfo(nsIContent* aBoundElement, const nsCString&
boundDocument->GetBindingManager(getter_AddRefs(bindingManager));
bindingManager->GetXBLDocumentInfo(aURLStr, getter_AddRefs(info));
if (!info) {
nsCOMPtr<nsIAtom> tagName;
aBoundElement->GetTag(*getter_AddRefs(tagName));
if (!info && (tagName.get() != kScrollbarAtom)) {
// The third line of defense is to investigate whether or not the
// document is currently being loaded asynchronously. If so, there's no
// document yet, but we need to glom on our request so that it will be
@ -847,14 +928,16 @@ nsXBLService::GetBindingDocumentInfo(nsIContent* aBoundElement, const nsCString&
nsCOMPtr<nsIStreamListener> listener;
bindingManager->GetLoadingDocListener(aURLStr, getter_AddRefs(listener));
if (listener) {
nsIStreamListener* ilist = listener.get();
nsXBLStreamListener* xblListener = NS_STATIC_CAST(nsXBLStreamListener*, ilist);
// Create a new load observer.
nsCAutoString bindingURI(aURLStr);
bindingURI += "#";
bindingURI += aRef;
nsXBLBindingRequest* req = new nsXBLBindingRequest(aRef, aBoundElement);
nsIStreamListener* ilist = listener.get();
nsXBLStreamListener* xblListener = NS_STATIC_CAST(nsXBLStreamListener*, ilist);
xblListener->AddRequest(req);
if (!xblListener->HasRequest(bindingURI, aBoundElement)) {
nsXBLBindingRequest* req = new (mPool) nsXBLBindingRequest(bindingURI, aBoundElement);
xblListener->AddRequest(req);
}
return NS_OK;
}
}
@ -947,11 +1030,12 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIURI* aURI, cons
return rv;
}
if (!IsChromeURI(aURI)) {
nsCOMPtr<nsIAtom> tagName;
aBoundElement->GetTag(*getter_AddRefs(tagName));
if (tagName != kScrollbarAtom) {
// We can be asynchronous
nsXBLStreamListener* xblListener = new nsXBLStreamListener(listener, boundDoc, doc);
NS_ADDREF(xblListener);
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(doc));
rec->AddEventListener(NS_ConvertASCIItoUCS2("load"), (nsIDOMLoadListener*)xblListener, PR_FALSE);
@ -968,7 +1052,7 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIURI* aURI, cons
nsCAutoString bindingURI(uri);
bindingURI += "#";
bindingURI += aRef;
nsXBLBindingRequest* req = new nsXBLBindingRequest(bindingURI, aBoundElement);
nsXBLBindingRequest* req = new (mPool) nsXBLBindingRequest(bindingURI, aBoundElement);
xblListener->AddRequest(req);
// Now kick off the async read.

Просмотреть файл

@ -28,6 +28,7 @@
#include "nsIMemory.h"
#include "jsapi.h" // nsXBLJSClass derives from JSClass
#include "jsclist.h" // nsXBLJSClass derives from JSCList
#include "nsFixedSizeAllocator.h"
class nsIXBLBinding;
class nsIXBLDocumentInfo;
@ -54,6 +55,9 @@ class nsXBLService : public nsIXBLService, public nsIMemoryPressureObserver
// This method loads a binding doc and then builds the specific binding required.
NS_IMETHOD GetBinding(nsIContent* aBoundElement, const nsCString& aURLStr, nsIXBLBinding** aResult);
// Indicates whether or not a binding is fully loaded.
NS_IMETHOD BindingReady(nsIContent* aBoundElement, const nsCString& aURLStr, PRBool* aIsReady);
// This function clears out the bindings on a given content node.
NS_IMETHOD FlushStyleBindings(nsIContent* aContent);
@ -80,6 +84,11 @@ public:
// This method synchronously loads and parses an XBL file.
NS_IMETHOD FetchBindingDocument(nsIContent* aBoundElement, nsIURI* aURI, const nsCString& aRef, nsIDocument** aResult);
// This method loads a binding doc and then builds the specific binding required. It
// can also peek without building.
NS_IMETHOD GetBindingInternal(nsIContent* aBoundElement, const nsCString& aURLStr,
PRBool aPeekFlag, PRBool* aIsReady, nsIXBLBinding** aResult);
// This method walks a binding document and removes any text nodes
// that contain only whitespace.
static nsresult StripWhitespaceNodes(nsIContent* aContent);
@ -104,7 +113,10 @@ public:
// XBL Atoms
static nsIAtom* kExtendsAtom;
static nsIAtom* kHasChildrenAtom;
static nsIAtom* kScrollbarAtom;
nsFixedSizeAllocator mPool;
};
class nsXBLJSClass : public JSCList, public JSClass

Просмотреть файл

@ -5235,8 +5235,10 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
// Load the bindings.
nsCOMPtr<nsIXBLBinding> binding;
xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
if (NS_FAILED(rv))
return NS_OK;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsISupportsArray> anonymousItems;
nsCOMPtr<nsIContent> childElement;
@ -5467,8 +5469,10 @@ nsCSSFrameConstructor::CreateAnonymousTableCellFrames(nsIPresShell* aPres
// Load the bindings.
nsCOMPtr<nsIXBLBinding> binding;
xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
if (NS_FAILED(rv))
return NS_OK;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsIContent> childElement;
nsCOMPtr<nsISupportsArray> anonymousItems;

Просмотреть файл

@ -5235,8 +5235,10 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
// Load the bindings.
nsCOMPtr<nsIXBLBinding> binding;
xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
if (NS_FAILED(rv))
return NS_OK;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsISupportsArray> anonymousItems;
nsCOMPtr<nsIContent> childElement;
@ -5467,8 +5469,10 @@ nsCSSFrameConstructor::CreateAnonymousTableCellFrames(nsIPresShell* aPres
// Load the bindings.
nsCOMPtr<nsIXBLBinding> binding;
xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding));
if (NS_FAILED(rv))
return NS_OK;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsIContent> childElement;
nsCOMPtr<nsISupportsArray> anonymousItems;

Просмотреть файл

@ -74,6 +74,7 @@ public:
NS_IMETHOD RemoveLoadingDocListener(const nsCString& aURL)=0;
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult) = 0;
NS_IMETHOD FlushChromeBindings() = 0;
};
#endif // nsIBinding_Manager_h__

Просмотреть файл

@ -91,6 +91,9 @@ public:
NS_IMETHOD WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData)=0;
NS_IMETHOD SetAllowScripts(PRBool aFlag)=0;
NS_IMETHOD MarkForDeath()=0;
NS_IMETHOD MarkedForDeath(PRBool* aResult)=0;
};
extern nsresult

Просмотреть файл

@ -59,6 +59,9 @@ public:
// This method loads a binding doc and then builds the specific binding required.
NS_IMETHOD GetBinding(nsIContent* aBoundElement, const nsCString& aURLStr, nsIXBLBinding** aResult) = 0;
// Indicates whether or not a binding is fully loaded.
NS_IMETHOD BindingReady(nsIContent* aBoundElement, const nsCString& aURLStr, PRBool* aIsReady) = 0;
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement,

Просмотреть файл

@ -178,7 +178,8 @@ public:
NS_IMETHOD RemoveLoadingDocListener(const nsCString& aURL);
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD FlushChromeBindings();
// nsIStyleRuleSupplier
NS_IMETHOD UseDocumentRules(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD WalkRules(nsIStyleSet* aStyleSet,
@ -252,8 +253,13 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding )
mBindingTable = new nsSupportsHashtable;
nsISupportsKey key(aContent);
nsCOMPtr<nsISupports> old = getter_AddRefs(mBindingTable->Get(&key));
if (old && aBinding)
NS_ERROR("Binding already installed!");
if (aBinding) {
mBindingTable->Put (&key, aBinding);
mBindingTable->Put(&key, aBinding);
}
else
mBindingTable->Remove(&key);
@ -393,7 +399,7 @@ nsBindingManager::ProcessAttachedQueue()
for (PRUint32 i = 0; i < count; i++) {
nsCOMPtr<nsIXBLBinding> binding;
mAttachedQueue->GetElementAt(0, getter_AddRefs(binding));
mAttachedQueue->RemoveElementAt(0);
mAttachedQueue->RemoveElementAt(0);
binding->ExecuteAttachedHandler();
}
@ -468,6 +474,23 @@ nsBindingManager::RemoveLoadingDocListener(const nsCString& aURL)
return NS_OK;
}
PRBool PR_CALLBACK MarkForDeath(nsHashKey* aKey, void* aData, void* aClosure)
{
nsIXBLBinding* binding = (nsIXBLBinding*)aData;
nsCAutoString docURI;
binding->GetDocURI(docURI);
if (!docURI.CompareWithConversion("chrome", PR_FALSE, 6))
binding->MarkForDeath();
return PR_TRUE;
}
NS_IMETHODIMP
nsBindingManager::FlushChromeBindings()
{
mBindingTable->Enumerate(MarkForDeath);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::InheritsStyle(nsIContent* aContent, PRBool* aResult)
{

Просмотреть файл

@ -252,11 +252,14 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
mIsStyleBinding(PR_TRUE),
mAllowScripts(PR_TRUE),
mInheritStyle(PR_TRUE),
mMarkedForDeath(PR_FALSE),
mAttributeTable(nsnull),
mInsertionPointTable(nsnull)
{
NS_INIT_REFCNT();
gRefCnt++;
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 1) {
kContentAtom = NS_NewAtom("content");
kInterfaceAtom = NS_NewAtom("interface");
@ -303,6 +306,8 @@ nsXBLBinding::~nsXBLBinding(void)
delete mInsertionPointTable;
gRefCnt--;
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 0) {
NS_RELEASE(kContentAtom);
NS_RELEASE(kInterfaceAtom);
@ -354,6 +359,11 @@ nsXBLBinding::GetBaseBinding(nsIXBLBinding** aResult)
NS_IMETHODIMP
nsXBLBinding::SetBaseBinding(nsIXBLBinding* aBinding)
{
if (mNextBinding) {
NS_ERROR("Base XBL binding is already defined!");
return NS_OK;
}
mNextBinding = aBinding; // Comptr handles rel/add
return NS_OK;
}
@ -1454,8 +1464,6 @@ nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
NS_IMETHODIMP
nsXBLBinding::ConstructAttributeTable(nsIContent* aElement)
{
// XXX This function still needs to deal with the
// ability to map one attribute to another.
nsAutoString inherits;
aElement->GetAttribute(kNameSpaceID_None, kInheritsAtom, inherits);
if (!inherits.IsEmpty()) {
@ -1745,7 +1753,19 @@ nsXBLBinding::GetFirstStyleBinding(nsIXBLBinding** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::MarkForDeath()
{
mMarkedForDeath = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::MarkedForDeath(PRBool* aResult)
{
*aResult = mMarkedForDeath;
return NS_OK;
}
// Creation Routine ///////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -85,6 +85,9 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD SetAllowScripts(PRBool aFlag) { mAllowScripts = aFlag; return NS_OK; };
NS_IMETHOD MarkForDeath();
NS_IMETHOD MarkedForDeath(PRBool* aResult);
public:
nsXBLBinding(const nsCString& aDocURI, const nsCString& aRef);
virtual ~nsXBLBinding();
@ -172,9 +175,10 @@ protected:
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
PRBool mIsStyleBinding;
PRBool mAllowScripts;
PRBool mInheritStyle;
PRPackedBool mIsStyleBinding;
PRPackedBool mAllowScripts;
PRPackedBool mInheritStyle;
PRPackedBool mMarkedForDeath;
nsSupportsHashtable* mAttributeTable; // A table for attribute entries.
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points.

Просмотреть файл

@ -25,6 +25,7 @@
#include "nsCOMPtr.h"
#include "nsXBLService.h"
#include "nsIInputStream.h"
#include "nsINameSpace.h"
#include "nsINameSpaceManager.h"
#include "nsHashtable.h"
#include "nsIURI.h"
@ -37,6 +38,7 @@
#include "nsNetUtil.h"
#include "plstr.h"
#include "nsIContent.h"
#include "nsIXMLContent.h"
#include "nsIDOMElement.h"
#include "nsIDocument.h"
#include "nsIXMLContentSink.h"
@ -52,6 +54,9 @@
#include "nsIChromeRegistry.h"
#include "nsIPref.h"
#include "nsIPresShell.h"
#include "nsIDocumentObserver.h"
#include "nsIXULContentUtils.h"
#include "nsIXULPrototypeCache.h"
#include "nsIDOMLoadListener.h"
@ -104,55 +109,56 @@ struct nsXBLBindingRequest
}
}
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
return aAllocator.Alloc(aSize);
}
static void operator delete(void* aPtr, size_t aSize) {
nsFixedSizeAllocator::Free(aPtr, aSize);
}
void DocumentLoaded(nsIDocument* aBindingDoc)
{
// Get the binding.
nsCOMPtr<nsIXBLBinding> newBinding;
gXBLService->GetBinding(mBoundElement, mBindingURL, getter_AddRefs(newBinding));
// XXX Deal with layered bindings.
// XXX Deal with cross-site inheritance (e.g., http://a/a.xml inheriting from http://b/b.xml)
// Install the binding on the content node.
nsCOMPtr<nsIDocument> doc;
mBoundElement->GetDocument(*getter_AddRefs(doc));
if (!doc)
return;
nsCOMPtr<nsIBindingManager> bindingManager;
doc->GetBindingManager(getter_AddRefs(bindingManager));
bindingManager->SetBinding(mBoundElement, newBinding);
// Set the binding's bound element.
newBinding->SetBoundElement(mBoundElement);
// Get the binding.
PRBool ready = PR_FALSE;
gXBLService->BindingReady(mBoundElement, mBindingURL, &ready);
// Tell the binding to build the anonymous content.
newBinding->GenerateAnonymousContent(mBoundElement);
// Tell the binding to install event handlers
nsCOMPtr<nsIXBLBinding> attachReq;
newBinding->InstallEventHandlers(mBoundElement, getter_AddRefs(attachReq));
// Set up our properties
newBinding->InstallProperties(mBoundElement);
if (attachReq) {
attachReq->ExecuteAttachedHandler();
}
if (!ready)
return;
// XXX Deal with layered bindings.
// Now do a ContentInserted notification to cause the frames to get installed finally,
nsCOMPtr<nsIContent> parent;
mBoundElement->GetParent(*getter_AddRefs(parent));
PRInt32 index = 0;
if (parent)
parent->IndexOf(mBoundElement, index);
if (index == -1)
return;
doc->ContentInserted(parent, mBoundElement, index);
nsCOMPtr<nsIPresShell> shell = getter_AddRefs(doc->GetShellAt(0));
if (shell) {
nsCOMPtr<nsIDocumentObserver> obs(do_QueryInterface(shell));
obs->ContentRemoved(doc, parent, mBoundElement, index);
obs->ContentInserted(doc, parent, mBoundElement, index);
}
}
static nsIXBLService* gXBLService;
static int gRefCnt;
};
static const size_t kBucketSizes[] = {
sizeof(nsXBLBindingRequest)
};
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
static const PRInt32 kNumElements = 64;
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLBindingRequest))) * kNumElements;
nsIXBLService* nsXBLBindingRequest::gXBLService = nsnull;
int nsXBLBindingRequest::gRefCnt = 0;
@ -180,12 +186,13 @@ public:
virtual ~nsXBLStreamListener();
void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); };
PRBool HasRequest(const nsCString& aURI, nsIContent* aBoundElement);
private:
nsCOMPtr<nsIStreamListener> mInner;
nsVoidArray mBindingRequests;
nsCOMPtr<nsIDocument> mDocument;
nsIDocument* mDocument;
nsCOMPtr<nsIDocument> mBindingDocument;
};
@ -264,17 +271,34 @@ nsXBLStreamListener::OnStopRequest(nsIChannel* aChannel, nsISupports* aCtxt, nsr
rv = mInner->OnStopRequest(aChannel, aCtxt, aStatus, aStatusArg);
}
if (NS_FAILED(rv)) {
if (NS_FAILED(rv) || NS_FAILED(aStatus)) {
PRUint32 count = mBindingRequests.Count();
for (PRUint32 i = 0; i < count; i++) {
nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
delete req;
}
mDocument = nsnull;
mBindingDocument = nsnull;
}
return rv;
}
PRBool
nsXBLStreamListener::HasRequest(const nsCString& aURI, nsIContent* aElt)
{
// XXX Could be more efficient.
PRUint32 count = mBindingRequests.Count();
for (PRUint32 i = 0; i < count; i++) {
nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
if (req->mBindingURL.Equals(aURI) && req->mBoundElement.get() == aElt)
return PR_TRUE;
}
return PR_FALSE;
}
nsresult
nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
{
@ -312,8 +336,9 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
info->SetScriptAccess(allow);
}
}
bindingManager->PutXBLDocumentInfo(info);
if (!cached)
bindingManager->PutXBLDocumentInfo(info);
// Notify all pending requests that their bindings are
// ready and can be installed.
@ -328,9 +353,12 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
delete req;
}
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mDocument));
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mBindingDocument));
rec->RemoveEventListener(NS_ConvertASCIItoUCS2("load"), (nsIDOMLoadListener*)this, PR_FALSE);
mDocument = nsnull;
mBindingDocument = nsnull;
return rv;
}
@ -406,7 +434,7 @@ PRUint32 nsXBLService::gClassLRUListLength = 0;
PRUint32 nsXBLService::gClassLRUListQuota = 64;
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
nsIAtom* nsXBLService::kHasChildrenAtom = nsnull;
nsIAtom* nsXBLService::kScrollbarAtom = nsnull;
// Enabled by default. Must be over-ridden to disable
PRBool nsXBLService::gDisableChromeCache = PR_FALSE;
@ -421,6 +449,8 @@ NS_IMPL_ISUPPORTS2(nsXBLService, nsIXBLService, nsIMemoryPressureObserver)
nsXBLService::nsXBLService(void)
{
NS_INIT_REFCNT();
mPool.Init("XBL Binding Requests", kBucketSizes, kNumBuckets, kInitialSize);
gRefCnt++;
if (gRefCnt == 1) {
@ -442,8 +472,8 @@ nsXBLService::nsXBLService(void)
// Create our atoms
kExtendsAtom = NS_NewAtom("extends");
kHasChildrenAtom = NS_NewAtom("haschildren");
kScrollbarAtom = NS_NewAtom("scrollbar");
// Find out if the XUL cache is on or off
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv);
if (NS_SUCCEEDED(rv))
@ -476,8 +506,8 @@ nsXBLService::~nsXBLService(void)
// Release our atoms
NS_RELEASE(kExtendsAtom);
NS_RELEASE(kHasChildrenAtom);
NS_RELEASE(kScrollbarAtom);
// Walk the LRU list removing and deleting the nsXBLJSClasses.
FlushMemory(REASON_HEAP_MINIMIZE, 0);
@ -526,15 +556,23 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aA
nsCOMPtr<nsIXBLBinding> styleBinding;
binding->GetFirstStyleBinding(getter_AddRefs(styleBinding));
if (styleBinding) {
// See if the URIs match.
nsCAutoString uri;
styleBinding->GetBindingURI(uri);
if (uri.EqualsWithConversion(aURL))
return NS_OK;
else {
PRBool marked = PR_FALSE;
binding->MarkedForDeath(&marked);
if (marked) {
FlushStyleBindings(aContent);
binding = nsnull;
}
else {
// See if the URIs match.
nsCAutoString uri;
styleBinding->GetBindingURI(uri);
if (uri.EqualsWithConversion(aURL))
return NS_OK;
else {
FlushStyleBindings(aContent);
binding = nsnull;
}
}
}
}
@ -736,9 +774,29 @@ nsXBLService::FlushMemory(PRUint32 reason, size_t requestedAmount)
// Internal helper methods ////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsXBLService::GetBinding(nsIContent* aBoundElement, const nsCString& aURLStr, nsIXBLBinding** aResult)
NS_IMETHODIMP nsXBLService::GetBinding(nsIContent* aBoundElement,
const nsCString& aURLStr,
nsIXBLBinding** aResult)
{
*aResult = nsnull;
PRBool dummy;
return GetBindingInternal(aBoundElement, aURLStr, PR_FALSE, &dummy, aResult);
}
NS_IMETHODIMP nsXBLService::BindingReady(nsIContent* aBoundElement,
const nsCString& aURLStr,
PRBool* aIsReady)
{
return GetBindingInternal(aBoundElement, aURLStr, PR_TRUE, aIsReady, nsnull);
}
NS_IMETHODIMP nsXBLService::GetBindingInternal(nsIContent* aBoundElement,
const nsCString& aURLStr,
PRBool aPeekOnly,
PRBool* aIsReady,
nsIXBLBinding** aResult)
{
if (aResult)
*aResult = nsnull;
if (aURLStr.IsEmpty())
return NS_ERROR_FAILURE;
@ -781,32 +839,53 @@ NS_IMETHODIMP nsXBLService::GetBinding(nsIContent* aBoundElement, const nsCStrin
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, value);
// If no ref is specified just use this.
if ((bindingName.IsEmpty()) || (bindingName == value)) {
// Make a new binding
NS_NewXBLBinding(uri, ref, aResult);
// Initialize its bound element.
(*aResult)->SetBindingElement(child);
(*aResult)->SetAllowScripts(allowScripts);
if ((bindingName.IsEmpty()) || (bindingName == value)) {
// Check for the presence of an extends attribute
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, value);
if (!value.IsEmpty()) {
// See if we are extending a builtin tag.
nsCOMPtr<nsIAtom> tag;
PRInt32 dummy;
(*aResult)->GetBaseTag(&dummy, getter_AddRefs(tag));
if (!tag) {
// We have a base class binding. Load it right now.
nsCOMPtr<nsIXBLBinding> baseBinding;
nsCAutoString urlCString; urlCString.AssignWithConversion(value);
GetBinding(aBoundElement, urlCString, getter_AddRefs(baseBinding));
if (!baseBinding)
return NS_OK; // At least we got the derived class binding loaded.
(*aResult)->SetBaseBinding(baseBinding);
nsAutoString extends;
nsCOMPtr<nsIXBLBinding> baseBinding;
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
value = extends;
if (!extends.IsEmpty()) {
nsAutoString prefix;
PRInt32 offset = extends.FindChar(':');
if (-1 != offset) {
extends.Left(prefix, offset);
extends.Cut(0, offset+1);
}
if (prefix.Length() > 0) {
// Look up the prefix.
nsCOMPtr<nsIAtom> prefixAtom = getter_AddRefs(NS_NewAtom(prefix));
nsCOMPtr<nsINameSpace> nameSpace;
nsCOMPtr<nsIXMLContent> xmlContent(do_QueryInterface(child));
if (xmlContent) {
xmlContent->GetContainingNameSpace(*getter_AddRefs(nameSpace));
if (nameSpace) {
nsCOMPtr<nsINameSpace> tagSpace;
nameSpace->FindNameSpace(prefixAtom, *getter_AddRefs(tagSpace));
if (!tagSpace) {
// We have a base class binding. Load it right now.
nsCAutoString urlCString; urlCString.AssignWithConversion(value);
GetBindingInternal(aBoundElement, urlCString, aPeekOnly, aIsReady, getter_AddRefs(baseBinding));
if (!*aIsReady)
return NS_ERROR_FAILURE; // Binding not yet ready or an error occurred.
}
}
}
}
}
*aIsReady = PR_TRUE;
if (!aPeekOnly) {
// Make a new binding
NS_NewXBLBinding(uri, ref, aResult);
// Initialize its bound element.
(*aResult)->SetBindingElement(child);
(*aResult)->SetAllowScripts(allowScripts);
if (baseBinding)
(*aResult)->SetBaseBinding(baseBinding);
}
break;
}
}
@ -839,7 +918,9 @@ nsXBLService::GetBindingDocumentInfo(nsIContent* aBoundElement, const nsCString&
boundDocument->GetBindingManager(getter_AddRefs(bindingManager));
bindingManager->GetXBLDocumentInfo(aURLStr, getter_AddRefs(info));
if (!info) {
nsCOMPtr<nsIAtom> tagName;
aBoundElement->GetTag(*getter_AddRefs(tagName));
if (!info && (tagName.get() != kScrollbarAtom)) {
// The third line of defense is to investigate whether or not the
// document is currently being loaded asynchronously. If so, there's no
// document yet, but we need to glom on our request so that it will be
@ -847,14 +928,16 @@ nsXBLService::GetBindingDocumentInfo(nsIContent* aBoundElement, const nsCString&
nsCOMPtr<nsIStreamListener> listener;
bindingManager->GetLoadingDocListener(aURLStr, getter_AddRefs(listener));
if (listener) {
nsIStreamListener* ilist = listener.get();
nsXBLStreamListener* xblListener = NS_STATIC_CAST(nsXBLStreamListener*, ilist);
// Create a new load observer.
nsCAutoString bindingURI(aURLStr);
bindingURI += "#";
bindingURI += aRef;
nsXBLBindingRequest* req = new nsXBLBindingRequest(aRef, aBoundElement);
nsIStreamListener* ilist = listener.get();
nsXBLStreamListener* xblListener = NS_STATIC_CAST(nsXBLStreamListener*, ilist);
xblListener->AddRequest(req);
if (!xblListener->HasRequest(bindingURI, aBoundElement)) {
nsXBLBindingRequest* req = new (mPool) nsXBLBindingRequest(bindingURI, aBoundElement);
xblListener->AddRequest(req);
}
return NS_OK;
}
}
@ -947,11 +1030,12 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIURI* aURI, cons
return rv;
}
if (!IsChromeURI(aURI)) {
nsCOMPtr<nsIAtom> tagName;
aBoundElement->GetTag(*getter_AddRefs(tagName));
if (tagName != kScrollbarAtom) {
// We can be asynchronous
nsXBLStreamListener* xblListener = new nsXBLStreamListener(listener, boundDoc, doc);
NS_ADDREF(xblListener);
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(doc));
rec->AddEventListener(NS_ConvertASCIItoUCS2("load"), (nsIDOMLoadListener*)xblListener, PR_FALSE);
@ -968,7 +1052,7 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIURI* aURI, cons
nsCAutoString bindingURI(uri);
bindingURI += "#";
bindingURI += aRef;
nsXBLBindingRequest* req = new nsXBLBindingRequest(bindingURI, aBoundElement);
nsXBLBindingRequest* req = new (mPool) nsXBLBindingRequest(bindingURI, aBoundElement);
xblListener->AddRequest(req);
// Now kick off the async read.

Просмотреть файл

@ -28,6 +28,7 @@
#include "nsIMemory.h"
#include "jsapi.h" // nsXBLJSClass derives from JSClass
#include "jsclist.h" // nsXBLJSClass derives from JSCList
#include "nsFixedSizeAllocator.h"
class nsIXBLBinding;
class nsIXBLDocumentInfo;
@ -54,6 +55,9 @@ class nsXBLService : public nsIXBLService, public nsIMemoryPressureObserver
// This method loads a binding doc and then builds the specific binding required.
NS_IMETHOD GetBinding(nsIContent* aBoundElement, const nsCString& aURLStr, nsIXBLBinding** aResult);
// Indicates whether or not a binding is fully loaded.
NS_IMETHOD BindingReady(nsIContent* aBoundElement, const nsCString& aURLStr, PRBool* aIsReady);
// This function clears out the bindings on a given content node.
NS_IMETHOD FlushStyleBindings(nsIContent* aContent);
@ -80,6 +84,11 @@ public:
// This method synchronously loads and parses an XBL file.
NS_IMETHOD FetchBindingDocument(nsIContent* aBoundElement, nsIURI* aURI, const nsCString& aRef, nsIDocument** aResult);
// This method loads a binding doc and then builds the specific binding required. It
// can also peek without building.
NS_IMETHOD GetBindingInternal(nsIContent* aBoundElement, const nsCString& aURLStr,
PRBool aPeekFlag, PRBool* aIsReady, nsIXBLBinding** aResult);
// This method walks a binding document and removes any text nodes
// that contain only whitespace.
static nsresult StripWhitespaceNodes(nsIContent* aContent);
@ -104,7 +113,10 @@ public:
// XBL Atoms
static nsIAtom* kExtendsAtom;
static nsIAtom* kHasChildrenAtom;
static nsIAtom* kScrollbarAtom;
nsFixedSizeAllocator mPool;
};
class nsXBLJSClass : public JSCList, public JSClass

Просмотреть файл

@ -74,6 +74,7 @@
#include "nsLayoutCID.h"
#include "nsGfxCIID.h"
#include "nsIImageManager.h"
#include "nsIBindingManager.h"
#include "prio.h"
static char kChromePrefix[] = "chrome://";
@ -1044,6 +1045,11 @@ NS_IMETHODIMP nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
if (!document)
return NS_OK;
// Annihilate all XBL bindings.
nsCOMPtr<nsIBindingManager> bindingManager;
document->GetBindingManager(getter_AddRefs(bindingManager));
bindingManager->FlushChromeBindings();
nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(domDocument);
if (xulDoc) {
// Deal with the backstop sheets first.