mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Work on 48150 and XBL performance (async and arenas).
This commit is contained in:
parent
75afe2361d
commit
a489c05fae
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user