mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Fix for 53417. r=brendan, a=brendan
This commit is contained in:
parent
8e3f2ce2da
commit
bc40a1821f
@ -79,7 +79,7 @@ CSS_PROP(background-position, background_position, VISUAL)
|
||||
CSS_PROP(background-repeat, background_repeat, VISUAL)
|
||||
CSS_PROP(-x-background-x-position, background_x_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-x-background-y-position, background_y_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, REFLOW) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, FRAMECHANGE) // XXX bug 3935
|
||||
CSS_PROP(border, border, REFLOW)
|
||||
CSS_PROP(border-bottom, border_bottom, REFLOW)
|
||||
CSS_PROP(border-bottom-color, border_bottom_color, VISUAL)
|
||||
|
@ -79,7 +79,7 @@ CSS_PROP(background-position, background_position, VISUAL)
|
||||
CSS_PROP(background-repeat, background_repeat, VISUAL)
|
||||
CSS_PROP(-x-background-x-position, background_x_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-x-background-y-position, background_y_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, REFLOW) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, FRAMECHANGE) // XXX bug 3935
|
||||
CSS_PROP(border, border, REFLOW)
|
||||
CSS_PROP(border-bottom, border_bottom, REFLOW)
|
||||
CSS_PROP(border-bottom-color, border_bottom_color, VISUAL)
|
||||
|
@ -33,6 +33,7 @@ EXPORTS = \
|
||||
nsIXBLBinding.h \
|
||||
nsIXBLBindingAttachedHandler.h \
|
||||
nsIXBLDocumentInfo.h \
|
||||
nsIXBLPrototypeBinding.h \
|
||||
nsIXBLPrototypeHandler.h \
|
||||
nsIXBLService.h \
|
||||
$(NULL)
|
||||
|
@ -2,6 +2,6 @@ nsIBindingManager.h
|
||||
nsIXBLBinding.h
|
||||
nsIXBLBindingAttachedHandler.h
|
||||
nsIXBLDocumentInfo.h
|
||||
nsIXBLPrototypeBinding.h
|
||||
nsIXBLPrototypeHandler.h
|
||||
nsIXBLService.h
|
||||
|
||||
|
@ -26,6 +26,7 @@ EXPORTS = \
|
||||
nsIXBLBinding.h \
|
||||
nsIXBLBindingAttachedHandler.h \
|
||||
nsIXBLDocumentInfo.h \
|
||||
nsIXBLPrototypeBinding.h \
|
||||
nsIXBLPrototypeHandler.h \
|
||||
nsIXBLService.h \
|
||||
$(NULL)
|
||||
|
@ -38,6 +38,7 @@
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIScriptContext;
|
||||
class nsIXBLPrototypeBinding;
|
||||
|
||||
// {DDDBAD20-C8DF-11d3-97FB-00400553EEF0}
|
||||
#define NS_IXBLBINDING_IID \
|
||||
@ -48,6 +49,9 @@ class nsIXBLBinding : public nsISupports
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLBINDING_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetPrototypeBinding(nsIXBLPrototypeBinding** aResult)=0;
|
||||
NS_IMETHOD SetPrototypeBinding(nsIXBLPrototypeBinding* aProtoBinding)=0;
|
||||
|
||||
NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult) = 0;
|
||||
NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding) = 0;
|
||||
|
||||
@ -92,13 +96,11 @@ public:
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult)=0;
|
||||
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
|
||||
NS_NewXBLBinding(const nsCString& aDocURI, const nsCString& aID, nsIXBLBinding** aResult);
|
||||
NS_NewXBLBinding(nsIXBLPrototypeBinding* aProtoBinding, nsIXBLBinding** aResult);
|
||||
|
||||
#endif // nsIXBLBinding_h__
|
||||
|
@ -39,6 +39,7 @@ class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIScriptContext;
|
||||
class nsIXBLPrototypeHandler;
|
||||
class nsIXBLPrototypeBinding;
|
||||
|
||||
// {5C4D9674-A2CF-4ddf-9F65-E1806C34D28D}
|
||||
#define NS_IXBLDOCUMENTINFO_IID \
|
||||
@ -55,8 +56,10 @@ public:
|
||||
NS_IMETHOD GetScriptAccess(PRBool* aResult)=0;
|
||||
NS_IMETHOD SetScriptAccess(PRBool aAccess)=0;
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler** aResult)=0;
|
||||
NS_IMETHOD SetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler* aHandler)=0;
|
||||
NS_IMETHOD GetDocumentURI(nsCString& aDocURI)=0;
|
||||
|
||||
NS_IMETHOD GetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding** aResult)=0;
|
||||
NS_IMETHOD SetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding* aBinding)=0;
|
||||
};
|
||||
|
||||
extern nsresult
|
||||
|
88
content/xbl/public/nsIXBLPrototypeBinding.h
Normal file
88
content/xbl/public/nsIXBLPrototypeBinding.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsIXBLPrototypeBinding_h__
|
||||
#define nsIXBLPrototypeBinding_h__
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIXBLDocumentInfo;
|
||||
class nsIXBLPrototypeHandler;
|
||||
|
||||
// {34D700F5-C1A2-4408-A0B1-DD8F891DD1FE}
|
||||
#define NS_IXBLPROTOTYPEBINDING_IID \
|
||||
{ 0x34d700f5, 0xc1a2, 0x4408, { 0xa0, 0xb1, 0xdd, 0x8f, 0x89, 0x1d, 0xd1, 0xfe } }
|
||||
|
||||
class nsIXBLPrototypeBinding : public nsISupports
|
||||
{
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLPROTOTYPEBINDING_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetBindingElement(nsIContent** aResult)=0;
|
||||
NS_IMETHOD SetBindingElement(nsIContent* aElement)=0;
|
||||
|
||||
NS_IMETHOD GetBindingURI(nsCString& aResult)=0;
|
||||
NS_IMETHOD GetDocURI(nsCString& aResult)=0;
|
||||
NS_IMETHOD GetID(nsCString& aResult)=0;
|
||||
|
||||
NS_IMETHOD GetAllowScripts(PRBool* aResult)=0;
|
||||
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult)=0;
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(nsIXBLPrototypeHandler** aHandler)=0;
|
||||
NS_IMETHOD SetPrototypeHandler(nsIXBLPrototypeHandler* aHandler)=0;
|
||||
|
||||
NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag,
|
||||
nsIContent* aChangedElement, nsIContent* aAnonymousContent)=0;
|
||||
|
||||
NS_IMETHOD SetBasePrototype(nsIXBLPrototypeBinding* aBinding)=0;
|
||||
NS_IMETHOD GetBasePrototype(nsIXBLPrototypeBinding** aResult)=0;
|
||||
|
||||
NS_IMETHOD HasBasePrototype(PRBool* aResult)=0;
|
||||
NS_IMETHOD SetHasBasePrototype(PRBool aHasBase)=0;
|
||||
|
||||
NS_IMETHOD GetXBLDocumentInfo(nsIContent* aBoundElement, nsIXBLDocumentInfo** aResult)=0;
|
||||
|
||||
NS_IMETHOD SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)=0;
|
||||
|
||||
NS_IMETHOD HasInsertionPoints(PRBool* aResult)=0;
|
||||
|
||||
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent* aChild, nsIContent** aResult)=0;
|
||||
|
||||
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent** aResult, PRBool* aMultipleInsertionPoints)=0;
|
||||
|
||||
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag)=0;
|
||||
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)=0;
|
||||
};
|
||||
|
||||
extern nsresult
|
||||
NS_NewXBLPrototypeBinding(const nsCString& aRef,
|
||||
nsIContent* aElement, nsIXBLDocumentInfo* aInfo,
|
||||
nsIXBLPrototypeBinding** aResult);
|
||||
|
||||
#endif // nsIXBLPrototypeBinding_h__
|
@ -28,6 +28,7 @@ DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
CPPSRCS= \
|
||||
nsXBLBinding.cpp \
|
||||
nsXBLPrototypeBinding.cpp \
|
||||
nsXBLService.cpp \
|
||||
nsXBLEventHandler.cpp \
|
||||
nsXBLWindowKeyHandler.cpp \
|
||||
@ -46,6 +47,7 @@ CPPSRCS= \
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsXBLBinding.obj \
|
||||
.\$(OBJDIR)\nsXBLPrototypeBinding.obj \
|
||||
.\$(OBJDIR)\nsXBLEventHandler.obj \
|
||||
.\$(OBJDIR)\nsXBLWindowKeyHandler.obj \
|
||||
.\$(OBJDIR)\nsXBLKeyHandler.obj \
|
||||
|
@ -58,19 +58,20 @@
|
||||
|
||||
#include "nsIStyleRuleProcessor.h"
|
||||
#include "nsIStyleSet.h"
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIWeakReference.h"
|
||||
|
||||
// Static IIDs/CIDs. Try to minimize these.
|
||||
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
|
||||
static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
|
||||
static NS_DEFINE_CID(kParserCID, NS_PARSER_IID); // XXX What's up with this???
|
||||
|
||||
class nsXBLDocumentInfo : public nsIXBLDocumentInfo
|
||||
class nsXBLDocumentInfo : public nsIXBLDocumentInfo, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsXBLDocumentInfo(nsIDocument* aDocument);
|
||||
nsXBLDocumentInfo(const char* aDocURI, nsIDocument* aDocument);
|
||||
virtual ~nsXBLDocumentInfo();
|
||||
|
||||
NS_IMETHOD GetDocument(nsIDocument** aResult) { *aResult = mDocument; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
@ -79,32 +80,36 @@ public:
|
||||
NS_IMETHOD GetScriptAccess(PRBool* aResult) { *aResult = mScriptAccess; return NS_OK; };
|
||||
NS_IMETHOD SetScriptAccess(PRBool aAccess) { mScriptAccess = aAccess; return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler** aResult);
|
||||
NS_IMETHOD SetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler* aHandler);
|
||||
NS_IMETHOD GetDocumentURI(nsCString& aDocURI) { aDocURI = mDocURI; return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding** aResult);
|
||||
NS_IMETHOD SetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding* aBinding);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCString mDocURI;
|
||||
nsCOMPtr<nsISupportsArray> mRuleProcessors;
|
||||
PRBool mScriptAccess;
|
||||
nsSupportsHashtable* mHandlerTable;
|
||||
nsSupportsHashtable* mBindingTable;
|
||||
};
|
||||
|
||||
/* Implementation file */
|
||||
NS_IMPL_ISUPPORTS1(nsXBLDocumentInfo, nsIXBLDocumentInfo)
|
||||
NS_IMPL_ISUPPORTS2(nsXBLDocumentInfo, nsIXBLDocumentInfo, nsISupportsWeakReference)
|
||||
|
||||
nsXBLDocumentInfo::nsXBLDocumentInfo(nsIDocument* aDocument)
|
||||
nsXBLDocumentInfo::nsXBLDocumentInfo(const char* aDocURI, nsIDocument* aDocument)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
/* member initializers and constructor code */
|
||||
mDocURI = aDocURI;
|
||||
mDocument = aDocument;
|
||||
mScriptAccess = PR_TRUE;
|
||||
mHandlerTable = nsnull;
|
||||
mBindingTable = nsnull;
|
||||
}
|
||||
|
||||
nsXBLDocumentInfo::~nsXBLDocumentInfo()
|
||||
{
|
||||
/* destructor code */
|
||||
delete mHandlerTable;
|
||||
delete mBindingTable;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -144,33 +149,39 @@ nsXBLDocumentInfo::GetRuleProcessors(nsISupportsArray** aResult)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLDocumentInfo::GetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler** aResult)
|
||||
nsXBLDocumentInfo::GetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
if (!mHandlerTable)
|
||||
if (!mBindingTable)
|
||||
return NS_OK;
|
||||
|
||||
nsCStringKey key(aRef);
|
||||
*aResult = NS_STATIC_CAST(nsIXBLPrototypeHandler*, mHandlerTable->Get(&key)); // Addref happens here.
|
||||
*aResult = NS_STATIC_CAST(nsIXBLPrototypeBinding*, mBindingTable->Get(&key)); // Addref happens here.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLDocumentInfo::SetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler* aHandler)
|
||||
nsXBLDocumentInfo::SetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding* aBinding)
|
||||
{
|
||||
if (!mHandlerTable)
|
||||
mHandlerTable = new nsSupportsHashtable();
|
||||
if (!mBindingTable)
|
||||
mBindingTable = new nsSupportsHashtable();
|
||||
|
||||
nsCStringKey key(aRef);
|
||||
mHandlerTable->Put(&key, aHandler);
|
||||
mBindingTable->Put(&key, aBinding);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_NewXBLDocumentInfo(nsIDocument* aDocument, nsIXBLDocumentInfo** aResult)
|
||||
{
|
||||
*aResult = new nsXBLDocumentInfo(aDocument);
|
||||
nsCOMPtr<nsIURI> url = getter_AddRefs(aDocument->GetDocumentURL());
|
||||
|
||||
nsXPIDLCString str;
|
||||
url->GetSpec(getter_Copies(str));
|
||||
|
||||
*aResult = new nsXBLDocumentInfo((const char*)str, aDocument);
|
||||
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -683,10 +694,7 @@ nsBindingManager::RemoveLoadingDocListener(const nsCString& aURL)
|
||||
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();
|
||||
binding->MarkForDeath();
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -85,51 +85,6 @@
|
||||
static char kNameSpaceSeparator = ':';
|
||||
|
||||
// Helper classes
|
||||
// {A2892B81-CED9-11d3-97FB-00400553EEF0}
|
||||
#define NS_IXBLATTR_IID \
|
||||
{ 0xa2892b81, 0xced9, 0x11d3, { 0x97, 0xfb, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } }
|
||||
|
||||
class nsIXBLAttributeEntry : public nsISupports {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLATTR_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetAttribute(nsIAtom** aResult) = 0;
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) = 0;
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) = 0;
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) = 0;
|
||||
};
|
||||
|
||||
|
||||
class nsXBLAttributeEntry : public nsIXBLAttributeEntry {
|
||||
public:
|
||||
NS_IMETHOD GetAttribute(nsIAtom** aResult) { *aResult = mAttribute; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) { *aResult = mElement; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) { NS_IF_ADDREF(*aResult = mNext); return NS_OK; }
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) { mNext = aEntry; return NS_OK; }
|
||||
|
||||
nsIContent* mElement;
|
||||
nsCOMPtr<nsIAtom> mAttribute;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> mNext;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
nsXBLAttributeEntry(nsIAtom* aAtom, nsIContent* aContent) {
|
||||
NS_INIT_REFCNT(); mAttribute = aAtom; mElement = aContent;
|
||||
};
|
||||
|
||||
virtual ~nsXBLAttributeEntry() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
|
||||
|
||||
/***********************************************************************/
|
||||
//
|
||||
@ -193,10 +148,7 @@ nsIAtom* nsXBLBinding::kInheritsAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kEventAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kPhaseAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kExtendsAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kChildrenAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kValueAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kActionAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kHTMLAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kMethodAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kParameterAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kBodyAtom = nsnull;
|
||||
@ -210,19 +162,6 @@ nsIAtom* nsXBLBinding::kReadOnlyAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kAttachToAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kBindingAttachedAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kBindingDetachedAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kInheritStyleAtom = nsnull;
|
||||
|
||||
nsIXBLService* nsXBLBinding::gXBLService = nsnull;
|
||||
|
||||
nsFixedSizeAllocator nsXBLBinding::kPool;
|
||||
|
||||
static const size_t kBucketSizes[] = {
|
||||
sizeof(nsXBLAttributeEntry)
|
||||
};
|
||||
|
||||
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
|
||||
static const PRInt32 kNumElements = 128;
|
||||
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
|
||||
|
||||
nsXBLBinding::EventHandlerMapEntry
|
||||
nsXBLBinding::kEventHandlerMap[] = {
|
||||
@ -283,22 +222,17 @@ nsXBLBinding::kEventHandlerMap[] = {
|
||||
NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
|
||||
|
||||
// Constructors/Destructors
|
||||
nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
: mDocURI(aDocURI), mID(aID), mFirstHandler(nsnull),
|
||||
nsXBLBinding::nsXBLBinding(nsIXBLPrototypeBinding* aBinding)
|
||||
: mFirstHandler(nsnull),
|
||||
mIsStyleBinding(PR_TRUE),
|
||||
mAllowScripts(PR_TRUE),
|
||||
mInheritStyle(PR_TRUE),
|
||||
mMarkedForDeath(PR_FALSE),
|
||||
mAttributeTable(nsnull),
|
||||
mInsertionPointTable(nsnull)
|
||||
mMarkedForDeath(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mPrototypeBinding = aBinding;
|
||||
gRefCnt++;
|
||||
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
|
||||
|
||||
if (gRefCnt == 1) {
|
||||
kPool.Init("XBL Attribute Entries", kBucketSizes, kNumBuckets, kInitialSize);
|
||||
|
||||
kXULTemplateAtom = NS_NewAtom("template");
|
||||
kXULObservesAtom = NS_NewAtom("observes");
|
||||
|
||||
@ -311,9 +245,6 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
kEventAtom = NS_NewAtom("event");
|
||||
kPhaseAtom = NS_NewAtom("phase");
|
||||
kExtendsAtom = NS_NewAtom("extends");
|
||||
kChildrenAtom = NS_NewAtom("children");
|
||||
kHTMLAtom = NS_NewAtom("html");
|
||||
kValueAtom = NS_NewAtom("value");
|
||||
kActionAtom = NS_NewAtom("action");
|
||||
kMethodAtom = NS_NewAtom("method");
|
||||
kParameterAtom = NS_NewAtom("parameter");
|
||||
@ -328,11 +259,6 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
kAttachToAtom = NS_NewAtom("attachto");
|
||||
kBindingAttachedAtom = NS_NewAtom("bindingattached");
|
||||
kBindingDetachedAtom = NS_NewAtom("bindingdetached");
|
||||
kInheritStyleAtom = NS_NewAtom("inheritstyle");
|
||||
|
||||
nsServiceManager::GetService("@mozilla.org/xbl;1",
|
||||
NS_GET_IID(nsIXBLService),
|
||||
(nsISupports**) &gXBLService);
|
||||
|
||||
EventHandlerMapEntry* entry = kEventHandlerMap;
|
||||
while (entry->mAttributeName) {
|
||||
@ -345,9 +271,6 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
|
||||
nsXBLBinding::~nsXBLBinding(void)
|
||||
{
|
||||
delete mAttributeTable;
|
||||
delete mInsertionPointTable;
|
||||
|
||||
gRefCnt--;
|
||||
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
|
||||
|
||||
@ -364,9 +287,6 @@ nsXBLBinding::~nsXBLBinding(void)
|
||||
NS_RELEASE(kEventAtom);
|
||||
NS_RELEASE(kPhaseAtom);
|
||||
NS_RELEASE(kExtendsAtom);
|
||||
NS_RELEASE(kChildrenAtom);
|
||||
NS_RELEASE(kHTMLAtom);
|
||||
NS_RELEASE(kValueAtom);
|
||||
NS_RELEASE(kActionAtom);
|
||||
NS_RELEASE(kMethodAtom);
|
||||
NS_RELEASE(kParameterAtom);
|
||||
@ -380,10 +300,6 @@ nsXBLBinding::~nsXBLBinding(void)
|
||||
NS_RELEASE(kReadOnlyAtom);
|
||||
NS_RELEASE(kAttachToAtom);
|
||||
NS_RELEASE(kBindingAttachedAtom);
|
||||
NS_RELEASE(kInheritStyleAtom);
|
||||
|
||||
nsServiceManager::ReleaseService("@mozilla.org/xbl;1", gXBLService);
|
||||
gXBLService = nsnull;
|
||||
|
||||
EventHandlerMapEntry* entry = kEventHandlerMap;
|
||||
while (entry->mAttributeName) {
|
||||
@ -448,32 +364,34 @@ nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
|
||||
child->SetBindingParent(mBoundElement);
|
||||
}
|
||||
|
||||
// (3) We need to insert entries into our attribute table for any elements
|
||||
// that are inheriting attributes. This table allows us to quickly determine
|
||||
// which elements in our anonymous content need to be updated when attributes change.
|
||||
ConstructAttributeTable(aParent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetPrototypeBinding(nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = mPrototypeBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::SetPrototypeBinding(nsIXBLPrototypeBinding* aProtoBinding)
|
||||
{
|
||||
mPrototypeBinding = aProtoBinding;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetBindingElement(nsIContent** aResult)
|
||||
{
|
||||
*aResult = mBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetBindingElement(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::SetBindingElement(nsIContent* aElement)
|
||||
{
|
||||
mBinding = aElement;
|
||||
nsAutoString inheritStyle;
|
||||
mBinding->GetAttribute(kNameSpaceID_None, kInheritStyleAtom, inheritStyle);
|
||||
if (inheritStyle == NS_LITERAL_STRING("false"))
|
||||
mInheritStyle = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->SetBindingElement(aElement);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -499,7 +417,7 @@ nsXBLBinding::HasStyleSheets(PRBool* aResolveStyle)
|
||||
// Find out if we need to re-resolve style. We'll need to do this
|
||||
// if we have additional stylesheets in our binding document.
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
gXBLService->GetXBLDocumentInfo(mDocURI, mBoundElement, getter_AddRefs(info));
|
||||
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
||||
if (!info)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsISupportsArray> rules;
|
||||
@ -528,87 +446,86 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
|
||||
else return NS_OK;
|
||||
}
|
||||
|
||||
// Plan to build the content by default.
|
||||
PRBool buildContent = PR_TRUE;
|
||||
// Find out if we're really building kids or if we're just
|
||||
// using the attribute-setting shorthand hack.
|
||||
PRInt32 contentCount;
|
||||
content->ChildCount(contentCount);
|
||||
|
||||
// See if there's an includes attribute.
|
||||
nsAutoString includes;
|
||||
content->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if ( includes != NS_LITERAL_STRING("*")) {
|
||||
PRInt32 childCount;
|
||||
aBoundElement->ChildCount(childCount);
|
||||
if (childCount > 0) {
|
||||
// We'll only build content if all the explicit children are
|
||||
// in the includes list.
|
||||
// Walk the children and ensure that all of them
|
||||
// are in the includes array.
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aBoundElement->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (!IsInExcludesList(tag, includes)) {
|
||||
// XXX HACK! Ignore <template> and <observes>
|
||||
if (tag.get() != kXULTemplateAtom &&
|
||||
tag.get() != kXULObservesAtom) {
|
||||
buildContent = PR_FALSE;
|
||||
break;
|
||||
// Plan to build the content by default.
|
||||
PRBool hasContent = (contentCount > 0);
|
||||
PRBool hasInsertionPoints;
|
||||
mPrototypeBinding->HasInsertionPoints(&hasInsertionPoints);
|
||||
|
||||
if (hasContent && !hasInsertionPoints) {
|
||||
// See if there's an includes attribute.
|
||||
nsAutoString includes;
|
||||
content->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if (includes != NS_LITERAL_STRING("*")) {
|
||||
PRInt32 childCount;
|
||||
aBoundElement->ChildCount(childCount);
|
||||
if (childCount > 0) {
|
||||
// We'll only build content if all the explicit children are
|
||||
// in the includes list.
|
||||
// Walk the children and ensure that all of them
|
||||
// are in the includes array.
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aBoundElement->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (!IsInExcludesList(tag, includes)) {
|
||||
// XXX HACK! Ignore <template> and <observes>
|
||||
if (tag.get() != kXULTemplateAtom &&
|
||||
tag.get() != kXULObservesAtom) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> childrenElement;
|
||||
// see if we have a <children/> element
|
||||
GetNestedChild(kChildrenAtom, content, getter_AddRefs(childrenElement));
|
||||
if (childrenElement)
|
||||
buildContent = PR_TRUE;
|
||||
|
||||
if (buildContent) {
|
||||
if (hasContent) {
|
||||
nsCOMPtr<nsIContent> clonedContent;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(content));
|
||||
|
||||
nsCOMPtr<nsIDOMNode> clonedNode;
|
||||
domElement->CloneNode(PR_TRUE, getter_AddRefs(clonedNode));
|
||||
|
||||
nsCOMPtr<nsIContent> clonedContent = do_QueryInterface(clonedNode);
|
||||
clonedContent = do_QueryInterface(clonedNode);
|
||||
SetAnonymousContent(clonedContent);
|
||||
}
|
||||
|
||||
// Always check the content element for potential attributes.
|
||||
PRInt32 length;
|
||||
clonedContent->GetAttributeCount(length);
|
||||
// Always check the content element for potential attributes.
|
||||
// This shorthand hack always happens, even when we didn't
|
||||
// build anonymous content.
|
||||
PRInt32 length;
|
||||
content->GetAttributeCount(length);
|
||||
|
||||
PRInt32 namespaceID;
|
||||
nsCOMPtr<nsIAtom> name;
|
||||
nsCOMPtr<nsIAtom> prefix;
|
||||
PRInt32 namespaceID;
|
||||
nsCOMPtr<nsIAtom> name;
|
||||
nsCOMPtr<nsIAtom> prefix;
|
||||
|
||||
for (PRInt32 i = 0; i < length; ++i)
|
||||
{
|
||||
clonedContent->GetAttributeNameAt(0, namespaceID, *getter_AddRefs(name), *getter_AddRefs(prefix));
|
||||
for (PRInt32 i = 0; i < length; ++i) {
|
||||
content->GetAttributeNameAt(0, namespaceID, *getter_AddRefs(name), *getter_AddRefs(prefix));
|
||||
|
||||
if (name.get() != kIncludesAtom) {
|
||||
nsAutoString value;
|
||||
mBoundElement->GetAttribute(namespaceID, name, value);
|
||||
if (value.IsEmpty()) {
|
||||
nsAutoString value2;
|
||||
clonedContent->GetAttribute(namespaceID, name, value2);
|
||||
mBoundElement->SetAttribute(namespaceID, name, value2, PR_FALSE);
|
||||
}
|
||||
if (name.get() != kIncludesAtom) {
|
||||
nsAutoString value;
|
||||
mBoundElement->GetAttribute(namespaceID, name, value);
|
||||
if (value.IsEmpty()) {
|
||||
nsAutoString value2;
|
||||
content->GetAttribute(namespaceID, name, value2);
|
||||
mBoundElement->SetAttribute(namespaceID, name, value2, PR_FALSE);
|
||||
}
|
||||
|
||||
// Conserve space by wiping the attributes off the clone.
|
||||
clonedContent->UnsetAttribute(namespaceID, name, PR_FALSE);
|
||||
}
|
||||
|
||||
if (childrenElement)
|
||||
BuildInsertionTable();
|
||||
// Conserve space by wiping the attributes off the clone.
|
||||
if (mContent)
|
||||
mContent->UnsetAttribute(namespaceID, name, PR_FALSE);
|
||||
}
|
||||
|
||||
/* XXX Handle selective decision to build anonymous content.
|
||||
if (mNextBinding) {
|
||||
return mNextBinding->GenerateAnonymousContent(aBoundElement);
|
||||
}
|
||||
*/
|
||||
if (mContent)
|
||||
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -620,12 +537,12 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement, nsIXBLBinding** aB
|
||||
if (AllowScripts()) {
|
||||
// Fetch the handlers prototypes for this binding.
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
gXBLService->GetXBLDocumentInfo(mDocURI, mBoundElement, getter_AddRefs(info));
|
||||
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
||||
if (!info)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> handlerChain;
|
||||
info->GetPrototypeHandler(mID, getter_AddRefs(handlerChain));
|
||||
mPrototypeBinding->GetPrototypeHandler(getter_AddRefs(handlerChain));
|
||||
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> curr = handlerChain;
|
||||
nsXBLEventHandler* currHandler = nsnull;
|
||||
@ -1058,116 +975,20 @@ nsXBLBinding::GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult)
|
||||
{
|
||||
if (mNextBinding)
|
||||
return mNextBinding->GetBaseTag(aNameSpaceID, aResult);
|
||||
|
||||
// XXX Cache the value as a "base" attribute so that we don't do this
|
||||
// check over and over each time the bound element occurs.
|
||||
|
||||
// We are the base binding. Obtain the extends attribute.
|
||||
nsAutoString extends;
|
||||
mBinding->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
|
||||
|
||||
if (!extends.IsEmpty()) {
|
||||
// Obtain the namespace prefix.
|
||||
nsAutoString prefix;
|
||||
PRInt32 offset = extends.FindChar(kNameSpaceSeparator);
|
||||
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(mBinding));
|
||||
if (xmlContent) {
|
||||
xmlContent->GetContainingNameSpace(*getter_AddRefs(nameSpace));
|
||||
|
||||
if (nameSpace) {
|
||||
nsCOMPtr<nsINameSpace> tagSpace;
|
||||
nameSpace->FindNameSpace(prefixAtom, *getter_AddRefs(tagSpace));
|
||||
if (tagSpace) {
|
||||
// Score! Return the tag.
|
||||
tagSpace->GetNameSpaceID(*aNameSpaceID);
|
||||
*aResult = NS_NewAtom(extends); // The addref happens here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag)
|
||||
{
|
||||
// XXX check to see if we inherit anonymous content from a base binding
|
||||
// if (mNextBinding)
|
||||
// mNextBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag);
|
||||
|
||||
if (!mAttributeTable)
|
||||
// XXX Change if we ever allow multiple bindings in a chain to contribute anonymous content
|
||||
if (!mContent) {
|
||||
if (mNextBinding)
|
||||
return mNextBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag);
|
||||
return NS_OK;
|
||||
|
||||
nsISupportsKey key(aAttribute);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> xblAttr = do_QueryInterface(supports);
|
||||
if (!xblAttr)
|
||||
return NS_OK;
|
||||
|
||||
// Iterate over the elements in the array.
|
||||
|
||||
while (xblAttr) {
|
||||
nsCOMPtr<nsIContent> element;
|
||||
nsCOMPtr<nsIAtom> setAttr;
|
||||
xblAttr->GetElement(getter_AddRefs(element));
|
||||
xblAttr->GetAttribute(getter_AddRefs(setAttr));
|
||||
|
||||
if (aRemoveFlag)
|
||||
element->UnsetAttribute(aNameSpaceID, setAttr, PR_TRUE);
|
||||
else {
|
||||
nsAutoString value;
|
||||
nsresult result = mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
|
||||
if (attrPresent)
|
||||
element->SetAttribute(aNameSpaceID, setAttr, value, PR_TRUE);
|
||||
}
|
||||
|
||||
// See if we're the <html> tag in XUL, and see if value is being
|
||||
// set or unset on us.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
element->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == kHTMLAtom) && (setAttr.get() == kValueAtom)) {
|
||||
// Flush out all our kids.
|
||||
PRInt32 childCount;
|
||||
element->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++)
|
||||
element->RemoveChildAt(0, PR_TRUE);
|
||||
|
||||
if (!aRemoveFlag) {
|
||||
// Construct a new text node and insert it.
|
||||
nsAutoString value;
|
||||
mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
if (!value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
mBoundElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(element));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = xblAttr;
|
||||
tmpAttr->GetNext(getter_AddRefs(xblAttr));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag, mBoundElement, mContent);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1254,7 +1075,7 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||
GetAnonymousContent(getter_AddRefs(anonymous));
|
||||
if (anonymous) {
|
||||
if (mIsStyleBinding)
|
||||
anonymous->SetDocument(nsnull, PR_TRUE, AllowScripts()); // Kill it.
|
||||
anonymous->SetDocument(nsnull, PR_TRUE, PR_TRUE); // Kill it.
|
||||
else anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around.
|
||||
}
|
||||
}
|
||||
@ -1265,32 +1086,32 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetBindingURI(nsCString& aResult)
|
||||
{
|
||||
aResult = mDocURI;
|
||||
aResult += "#";
|
||||
aResult += mID;
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetBindingURI(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetDocURI(nsCString& aResult)
|
||||
{
|
||||
aResult = mDocURI;
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetDocURI(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetID(nsCString& aResult)
|
||||
{
|
||||
aResult = mID;
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetID(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::InheritsStyle(PRBool* aResult)
|
||||
{
|
||||
// XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
|
||||
// Most derived binding with anonymous content determines style inheritance for now.
|
||||
|
||||
// XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
|
||||
if (mContent)
|
||||
*aResult = mInheritStyle;
|
||||
else if (mNextBinding)
|
||||
return mPrototypeBinding->InheritsStyle(aResult);
|
||||
|
||||
if (mNextBinding)
|
||||
return mNextBinding->InheritsStyle(aResult);
|
||||
|
||||
return NS_OK;
|
||||
@ -1307,7 +1128,7 @@ nsXBLBinding::WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData)
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
gXBLService->GetXBLDocumentInfo(mDocURI, mBoundElement, getter_AddRefs(info));
|
||||
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
||||
if (!info)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsISupportsArray> rules;
|
||||
@ -1422,12 +1243,15 @@ nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
|
||||
void
|
||||
nsXBLBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIContent> binding;
|
||||
mPrototypeBinding->GetBindingElement(getter_AddRefs(binding));
|
||||
|
||||
*aResult = nsnull;
|
||||
PRInt32 childCount;
|
||||
mBinding->ChildCount(childCount);
|
||||
binding->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
mBinding->ChildAt(i, *getter_AddRefs(child));
|
||||
binding->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
@ -1440,114 +1264,6 @@ nsXBLBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
PRInt32 childCount;
|
||||
aContent->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aContent->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
*aResult = aContent; // We return the parent of the correct child.
|
||||
NS_ADDREF(*aResult);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
GetNestedChild(aTag, child, aResult);
|
||||
if (*aResult)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList)
|
||||
{
|
||||
PRInt32 childCount;
|
||||
aContent->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aContent->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get())
|
||||
aList->AppendElement(child);
|
||||
else
|
||||
GetNestedChildren(aTag, child, aList);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::BuildInsertionTable()
|
||||
{
|
||||
if (!mInsertionPointTable)
|
||||
mInsertionPointTable = new nsSupportsHashtable;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> childrenElements;
|
||||
NS_NewISupportsArray(getter_AddRefs(childrenElements));
|
||||
GetNestedChildren(kChildrenAtom, mContent, childrenElements);
|
||||
|
||||
PRUint32 count;
|
||||
childrenElements->Count(&count);
|
||||
PRUint32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
nsAutoString includes;
|
||||
child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if (includes.IsEmpty()) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
}
|
||||
else {
|
||||
// The user specified at least one attribute.
|
||||
char* str = includes.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichar's
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, "| ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this string.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
|
||||
nsISupportsKey key(atom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove the <children> elements.
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
PRInt32 index;
|
||||
parent->IndexOf(child, index);
|
||||
parent->RemoveChildAt(index, PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
|
||||
{
|
||||
@ -1578,113 +1294,6 @@ nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::ConstructAttributeTable(nsIContent* aElement)
|
||||
{
|
||||
nsAutoString inherits;
|
||||
aElement->GetAttribute(kNameSpaceID_None, kInheritsAtom, inherits);
|
||||
if (!inherits.IsEmpty()) {
|
||||
if (!mAttributeTable) {
|
||||
mAttributeTable = new nsSupportsHashtable(4);
|
||||
}
|
||||
|
||||
// The user specified at least one attribute.
|
||||
char* str = inherits.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichar's
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, ", ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this attribute.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
nsCOMPtr<nsIAtom> attribute;
|
||||
|
||||
// Figure out if this token contains a :.
|
||||
nsAutoString attrTok; attrTok.AssignWithConversion(token);
|
||||
PRInt32 index = attrTok.Find("=", PR_TRUE);
|
||||
if (index != -1) {
|
||||
// This attribute maps to something different.
|
||||
nsAutoString left, right;
|
||||
attrTok.Left(left, index);
|
||||
attrTok.Right(right, attrTok.Length()-index-1);
|
||||
|
||||
atom = getter_AddRefs(NS_NewAtom(right.GetUnicode()));
|
||||
attribute = getter_AddRefs(NS_NewAtom(left.GetUnicode()));
|
||||
}
|
||||
else {
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
attribute = atom;
|
||||
}
|
||||
|
||||
// Create an XBL attribute entry.
|
||||
nsXBLAttributeEntry* xblAttr = new (kPool) nsXBLAttributeEntry(attribute, aElement);
|
||||
|
||||
// Now we should see if some element within our anonymous
|
||||
// content is already observing this attribute.
|
||||
nsISupportsKey key(atom);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> entry = do_QueryInterface(supports);
|
||||
if (!entry) {
|
||||
// Put it in the table.
|
||||
mAttributeTable->Put(&key, xblAttr);
|
||||
} else {
|
||||
nsCOMPtr<nsIXBLAttributeEntry> attr = entry;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = entry;
|
||||
do {
|
||||
attr = tmpAttr;
|
||||
attr->GetNext(getter_AddRefs(tmpAttr));
|
||||
} while (tmpAttr);
|
||||
attr->SetNext(xblAttr);
|
||||
}
|
||||
|
||||
// Now make sure that this attribute is initially set.
|
||||
// XXX How to deal with NAMESPACES!!!?
|
||||
nsAutoString value;
|
||||
nsresult result = mBoundElement->GetAttribute(kNameSpaceID_None, atom, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
|
||||
if (attrPresent) {
|
||||
aElement->SetAttribute(kNameSpaceID_None, attribute, value, PR_FALSE);
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
aElement->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == kHTMLAtom) && (attribute.get() == kValueAtom) && !value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
mBoundElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(aElement));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove the inherits attribute from the cloned element. It is used
|
||||
// on the template only, and we don't need it anymore.
|
||||
aElement->UnsetAttribute(kNameSpaceID_None, kInheritsAtom, PR_FALSE);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
|
||||
// Recur into our children.
|
||||
PRInt32 childCount;
|
||||
aElement->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aElement->ChildAt(i, *getter_AddRefs(child));
|
||||
ConstructAttributeTable(child);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound)
|
||||
{
|
||||
@ -1771,28 +1380,19 @@ nsXBLBinding::GetTextData(nsIContent *aParent, nsString& aResult)
|
||||
PRBool
|
||||
nsXBLBinding::AllowScripts()
|
||||
{
|
||||
return mAllowScripts;
|
||||
PRBool result;
|
||||
mPrototypeBinding->GetAllowScripts(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
if (mInsertionPointTable) {
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
aChild->GetTag(*getter_AddRefs(tag));
|
||||
nsISupportsKey key(tag);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
if (!content) {
|
||||
nsISupportsKey key2(kChildrenAtom);
|
||||
content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2)));
|
||||
}
|
||||
if (!mContent)
|
||||
return NS_OK;
|
||||
|
||||
*aResult = content;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1800,18 +1400,10 @@ nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleIns
|
||||
{
|
||||
*aResult = nsnull;
|
||||
*aMultipleInsertionPoints = PR_FALSE;
|
||||
if (mInsertionPointTable) {
|
||||
if(mInsertionPointTable->Count() == 1) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
*aResult = content;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
else
|
||||
*aMultipleInsertionPoints = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
if (!mContent)
|
||||
return NS_OK;
|
||||
|
||||
return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aMultipleInsertionPoints);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1844,6 +1436,7 @@ NS_IMETHODIMP
|
||||
nsXBLBinding::MarkForDeath()
|
||||
{
|
||||
mMarkedForDeath = PR_TRUE;
|
||||
ExecuteDetachedHandler();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1857,12 +1450,11 @@ nsXBLBinding::MarkedForDeath(PRBool* aResult)
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
NS_NewXBLBinding(const nsCString& aDocURI, const nsCString& aRef, nsIXBLBinding** aResult)
|
||||
NS_NewXBLBinding(nsIXBLPrototypeBinding* aBinding, nsIXBLBinding** aResult)
|
||||
{
|
||||
*aResult = new nsXBLBinding(aDocURI, aRef);
|
||||
*aResult = new nsXBLBinding(aBinding);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLBinding.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIAtom;
|
||||
@ -42,6 +43,9 @@ class nsXBLBinding: public nsIXBLBinding
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIXBLBinding
|
||||
NS_IMETHOD GetPrototypeBinding(nsIXBLPrototypeBinding** aResult);
|
||||
NS_IMETHOD SetPrototypeBinding(nsIXBLPrototypeBinding* aProtoBinding);
|
||||
|
||||
NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult);
|
||||
NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding);
|
||||
|
||||
@ -86,13 +90,11 @@ class nsXBLBinding: public nsIXBLBinding
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult);
|
||||
NS_IMETHOD WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData);
|
||||
|
||||
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);
|
||||
nsXBLBinding(nsIXBLPrototypeBinding* aProtoBinding);
|
||||
virtual ~nsXBLBinding();
|
||||
|
||||
NS_IMETHOD AddScriptEventListener(nsIContent* aElement, nsIAtom* aName, const nsString& aValue, REFNSIID aIID);
|
||||
@ -125,17 +127,12 @@ public:
|
||||
static nsIAtom* kOnGetAtom;
|
||||
static nsIAtom* kGetterAtom;
|
||||
static nsIAtom* kSetterAtom;
|
||||
static nsIAtom* kHTMLAtom;
|
||||
static nsIAtom* kValueAtom;
|
||||
static nsIAtom* kActionAtom;
|
||||
static nsIAtom* kNameAtom;
|
||||
static nsIAtom* kReadOnlyAtom;
|
||||
static nsIAtom* kAttachToAtom;
|
||||
static nsIAtom* kBindingAttachedAtom;
|
||||
static nsIAtom* kBindingDetachedAtom;
|
||||
static nsIAtom* kInheritStyleAtom;
|
||||
|
||||
static nsIXBLService* gXBLService;
|
||||
|
||||
// Used to easily obtain the correct IID for an event.
|
||||
struct EventHandlerMapEntry {
|
||||
@ -148,8 +145,6 @@ public:
|
||||
|
||||
static PRBool IsSupportedHandler(const nsIID* aIID);
|
||||
|
||||
static nsFixedSizeAllocator kPool;
|
||||
|
||||
static void GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound);
|
||||
|
||||
// Internal member functions
|
||||
@ -159,21 +154,11 @@ protected:
|
||||
void** aScriptObject, void** aClassObject);
|
||||
|
||||
void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult);
|
||||
void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult);
|
||||
void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList);
|
||||
void BuildInsertionTable();
|
||||
void GetNestedChildren();
|
||||
PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList);
|
||||
|
||||
NS_IMETHOD ConstructAttributeTable(nsIContent* aElement);
|
||||
|
||||
|
||||
// MEMBER VARIABLES
|
||||
protected:
|
||||
nsCString mDocURI;
|
||||
nsCString mID;
|
||||
|
||||
nsCOMPtr<nsIContent> mBinding; // Strong. As long as we're around, the binding can't go away.
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> mPrototypeBinding; // Strong. As long as we're around, the binding can't go away.
|
||||
nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
|
||||
nsCOMPtr<nsIXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.
|
||||
|
||||
@ -183,10 +168,5 @@ protected:
|
||||
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
|
||||
|
||||
PRPackedBool mIsStyleBinding;
|
||||
PRPackedBool mAllowScripts;
|
||||
PRPackedBool mInheritStyle;
|
||||
PRPackedBool mMarkedForDeath;
|
||||
|
||||
nsSupportsHashtable* mAttributeTable; // A table for attribute entries.
|
||||
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points.
|
||||
};
|
||||
|
805
content/xbl/src/nsXBLPrototypeBinding.cpp
Normal file
805
content/xbl/src/nsXBLPrototypeBinding.cpp
Normal file
@ -0,0 +1,805 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIXBLDocumentInfo.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIDOMEventReceiver.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "plstr.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIXMLContent.h"
|
||||
#include "nsIXULContent.h"
|
||||
#include "nsIXMLContentSink.h"
|
||||
#include "nsLayoutCID.h"
|
||||
#include "nsXMLDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMText.h"
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsINameSpace.h"
|
||||
#include "nsXBLService.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
|
||||
// Helper Classes =====================================================================
|
||||
|
||||
// nsIXBLAttributeEntry and helpers. This class is used to efficiently handle
|
||||
// attribute changes in anonymous content.
|
||||
|
||||
// {A2892B81-CED9-11d3-97FB-00400553EEF0}
|
||||
#define NS_IXBLATTR_IID \
|
||||
{ 0xa2892b81, 0xced9, 0x11d3, { 0x97, 0xfb, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } }
|
||||
|
||||
class nsIXBLAttributeEntry : public nsISupports {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLATTR_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetSrcAttribute(nsIAtom** aResult) = 0;
|
||||
NS_IMETHOD GetDstAttribute(nsIAtom** aResult) = 0;
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) = 0;
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) = 0;
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) = 0;
|
||||
};
|
||||
|
||||
class nsXBLAttributeEntry : public nsIXBLAttributeEntry {
|
||||
public:
|
||||
NS_IMETHOD GetSrcAttribute(nsIAtom** aResult) { *aResult = mSrcAttribute; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
NS_IMETHOD GetDstAttribute(nsIAtom** aResult) { *aResult = mDstAttribute; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) { *aResult = mElement; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) { NS_IF_ADDREF(*aResult = mNext); return NS_OK; }
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) { mNext = aEntry; return NS_OK; }
|
||||
|
||||
nsIContent* mElement;
|
||||
|
||||
nsCOMPtr<nsIAtom> mSrcAttribute;
|
||||
nsCOMPtr<nsIAtom> mDstAttribute;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> mNext;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, nsIContent* aContent) {
|
||||
NS_INIT_REFCNT(); mSrcAttribute = aSrcAtom; mDstAttribute = aDstAtom; mElement = aContent;
|
||||
};
|
||||
|
||||
virtual ~nsXBLAttributeEntry() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// Static initialization
|
||||
PRUint32 nsXBLPrototypeBinding::gRefCnt = 0;
|
||||
nsIAtom* nsXBLPrototypeBinding::kInheritStyleAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kHandlersAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kChildrenAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kIncludesAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kContentAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kInheritsAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kHTMLAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kValueAtom = nsnull;
|
||||
|
||||
nsIXBLService* nsXBLPrototypeBinding::gXBLService = nsnull;
|
||||
nsFixedSizeAllocator nsXBLPrototypeBinding::kPool;
|
||||
|
||||
static const size_t kBucketSizes[] = {
|
||||
sizeof(nsXBLAttributeEntry)
|
||||
};
|
||||
|
||||
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
|
||||
static const PRInt32 kNumElements = 128;
|
||||
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
|
||||
|
||||
// Implementation /////////////////////////////////////////////////////////////////
|
||||
|
||||
// Implement our nsISupports methods
|
||||
NS_IMPL_ISUPPORTS1(nsXBLPrototypeBinding, nsIXBLPrototypeBinding)
|
||||
|
||||
// Constructors/Destructors
|
||||
nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsCString& aID, nsIContent* aElement,
|
||||
nsIXBLDocumentInfo* aInfo)
|
||||
: mID(aID),
|
||||
mInheritStyle(PR_TRUE),
|
||||
mHasBaseProto(PR_TRUE),
|
||||
mAttributeTable(nsnull),
|
||||
mInsertionPointTable(nsnull)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
mXBLDocInfoWeak = getter_AddRefs(NS_GetWeakReference(aInfo));
|
||||
|
||||
gRefCnt++;
|
||||
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
|
||||
|
||||
if (gRefCnt == 1) {
|
||||
kPool.Init("XBL Attribute Entries", kBucketSizes, kNumBuckets, kInitialSize);
|
||||
|
||||
kInheritStyleAtom = NS_NewAtom("inheritstyle");
|
||||
kHandlersAtom = NS_NewAtom("handlers");
|
||||
kChildrenAtom = NS_NewAtom("children");
|
||||
kContentAtom = NS_NewAtom("content");
|
||||
kIncludesAtom = NS_NewAtom("includes");
|
||||
kInheritsAtom = NS_NewAtom("inherits");
|
||||
kHTMLAtom = NS_NewAtom("html");
|
||||
kValueAtom = NS_NewAtom("value");
|
||||
|
||||
nsServiceManager::GetService("@mozilla.org/xbl;1",
|
||||
NS_GET_IID(nsIXBLService),
|
||||
(nsISupports**) &gXBLService);
|
||||
}
|
||||
|
||||
// These all use atoms, so we have to do these ops last to ensure
|
||||
// the atoms exist.
|
||||
SetBindingElement(aElement);
|
||||
|
||||
PRBool allowScripts;
|
||||
aInfo->GetScriptAccess(&allowScripts);
|
||||
if (allowScripts) {
|
||||
ConstructHandlers();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(content));
|
||||
if (content) {
|
||||
ConstructAttributeTable(content);
|
||||
ConstructInsertionTable(content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
|
||||
{
|
||||
delete mAttributeTable;
|
||||
delete mInsertionPointTable;
|
||||
gRefCnt--;
|
||||
if (gRefCnt == 0) {
|
||||
NS_RELEASE(kInheritStyleAtom);
|
||||
NS_RELEASE(kHandlersAtom);
|
||||
NS_RELEASE(kChildrenAtom);
|
||||
NS_RELEASE(kContentAtom);
|
||||
NS_RELEASE(kIncludesAtom);
|
||||
NS_RELEASE(kInheritsAtom);
|
||||
NS_RELEASE(kHTMLAtom);
|
||||
NS_RELEASE(kValueAtom);
|
||||
|
||||
nsServiceManager::ReleaseService("@mozilla.org/xbl;1", gXBLService);
|
||||
gXBLService = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
// nsIXBLPrototypeBinding Interface ////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBasePrototype(nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = mBaseBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetBasePrototype(nsIXBLPrototypeBinding* aBinding)
|
||||
{
|
||||
if (mBaseBinding.get() == aBinding)
|
||||
return NS_OK;
|
||||
|
||||
if (mBaseBinding) {
|
||||
NS_ERROR("Base XBL prototype binding is already defined!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mBaseBinding = aBinding; // Comptr handles rel/add
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBindingElement(nsIContent** aResult)
|
||||
{
|
||||
*aResult = mBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
|
||||
{
|
||||
mBinding = aElement;
|
||||
nsAutoString inheritStyle;
|
||||
mBinding->GetAttribute(kNameSpaceID_None, kInheritStyleAtom, inheritStyle);
|
||||
if (inheritStyle == NS_LITERAL_STRING("false"))
|
||||
mInheritStyle = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBindingURI(nsCString& aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
GetXBLDocumentInfo(nsnull, getter_AddRefs(info));
|
||||
|
||||
info->GetDocumentURI(aResult);
|
||||
aResult += "#";
|
||||
aResult += mID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetDocURI(nsCString& aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
GetXBLDocumentInfo(nsnull, getter_AddRefs(info));
|
||||
|
||||
info->GetDocumentURI(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetID(nsCString& aResult)
|
||||
{
|
||||
aResult = mID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetAllowScripts(PRBool* aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
GetXBLDocumentInfo(nsnull, getter_AddRefs(info));
|
||||
return info->GetScriptAccess(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::InheritsStyle(PRBool* aResult)
|
||||
{
|
||||
*aResult = mInheritStyle;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetXBLDocumentInfo(nsIContent* aBoundElement, nsIXBLDocumentInfo** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info(do_QueryReferent(mXBLDocInfoWeak));
|
||||
if (info) {
|
||||
*aResult = info;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
else *aResult=nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::HasBasePrototype(PRBool* aResult)
|
||||
{
|
||||
*aResult = mHasBaseProto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetHasBasePrototype(PRBool aHasBase)
|
||||
{
|
||||
mHasBaseProto = aHasBase;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetPrototypeHandler(nsIXBLPrototypeHandler** aResult)
|
||||
{
|
||||
*aResult = mPrototypeHandler;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetPrototypeHandler(nsIXBLPrototypeHandler* aHandler)
|
||||
{
|
||||
mPrototypeHandler = aHandler;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag,
|
||||
nsIContent* aChangedElement, nsIContent* aAnonymousContent)
|
||||
{
|
||||
if (!mAttributeTable)
|
||||
return NS_OK;
|
||||
|
||||
nsISupportsKey key(aAttribute);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> xblAttr = do_QueryInterface(supports);
|
||||
if (!xblAttr)
|
||||
return NS_OK;
|
||||
|
||||
// Iterate over the elements in the array.
|
||||
nsCOMPtr<nsIContent> content;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(content));
|
||||
while (xblAttr) {
|
||||
nsCOMPtr<nsIContent> element;
|
||||
nsCOMPtr<nsIAtom> dstAttr;
|
||||
xblAttr->GetElement(getter_AddRefs(element));
|
||||
|
||||
nsCOMPtr<nsIContent> realElement;
|
||||
LocateInstance(content, aAnonymousContent, element, getter_AddRefs(realElement));
|
||||
|
||||
xblAttr->GetDstAttribute(getter_AddRefs(dstAttr));
|
||||
|
||||
if (aRemoveFlag)
|
||||
realElement->UnsetAttribute(aNameSpaceID, dstAttr, PR_TRUE);
|
||||
else {
|
||||
nsAutoString value;
|
||||
nsresult result = aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
|
||||
if (attrPresent)
|
||||
realElement->SetAttribute(aNameSpaceID, dstAttr, value, PR_TRUE);
|
||||
}
|
||||
|
||||
// See if we're the <html> tag in XUL, and see if value is being
|
||||
// set or unset on us.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
realElement->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == kHTMLAtom) && (dstAttr.get() == kValueAtom)) {
|
||||
// Flush out all our kids.
|
||||
PRInt32 childCount;
|
||||
realElement->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++)
|
||||
realElement->RemoveChildAt(0, PR_TRUE);
|
||||
|
||||
if (!aRemoveFlag) {
|
||||
// Construct a new text node and insert it.
|
||||
nsAutoString value;
|
||||
aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
if (!value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aChangedElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(realElement));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = xblAttr;
|
||||
tmpAttr->GetNext(getter_AddRefs(xblAttr));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent* aChild, nsIContent** aResult)
|
||||
{
|
||||
if (mInsertionPointTable) {
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
aChild->GetTag(*getter_AddRefs(tag));
|
||||
nsISupportsKey key(tag);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
if (!content) {
|
||||
nsISupportsKey key2(kChildrenAtom);
|
||||
content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2)));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> realContent;
|
||||
nsCOMPtr<nsIContent> templContent;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
|
||||
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
|
||||
if (realContent)
|
||||
*aResult = realContent;
|
||||
else *aResult = aBoundElement;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
|
||||
nsIContent* aCopyRoot,
|
||||
nsIContent** aResult, PRBool* aMultipleInsertionPoints)
|
||||
{
|
||||
if (mInsertionPointTable) {
|
||||
if(mInsertionPointTable->Count() == 1) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
nsCOMPtr<nsIContent> realContent;
|
||||
nsCOMPtr<nsIContent> templContent;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
|
||||
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
|
||||
if (realContent)
|
||||
*aResult = realContent;
|
||||
else *aResult = aBoundElement;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
else
|
||||
*aMultipleInsertionPoints = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)
|
||||
{
|
||||
mBaseNameSpaceID = aNamespaceID;
|
||||
mBaseTag = aTag;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aResult)
|
||||
{
|
||||
if (mBaseTag) {
|
||||
*aResult = mBaseTag;
|
||||
NS_ADDREF(*aResult);
|
||||
*aNamespaceID = mBaseNameSpaceID;
|
||||
}
|
||||
else *aResult = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Internal helpers ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
PRInt32 childCount;
|
||||
mBinding->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
mBinding->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
*aResult = child;
|
||||
NS_ADDREF(*aResult);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::ConstructHandlers()
|
||||
{
|
||||
// See if this binding has a handler elt.
|
||||
nsCOMPtr<nsIContent> handlers;
|
||||
GetImmediateChild(kHandlersAtom, getter_AddRefs(handlers));
|
||||
if (handlers) {
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> firstHandler;
|
||||
nsXBLService::BuildHandlerChain(handlers, getter_AddRefs(firstHandler));
|
||||
SetPrototypeHandler(firstHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::LocateInstance(nsIContent* aTemplRoot, nsIContent* aCopyRoot,
|
||||
nsIContent* aTemplChild, nsIContent** aCopyResult)
|
||||
{
|
||||
// XXX We will get in trouble if the binding instantiation deviates from the template
|
||||
// in the prototype.
|
||||
if (aTemplChild == aTemplRoot) {
|
||||
*aCopyResult = nsnull;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> templParent;
|
||||
nsCOMPtr<nsIContent> copyParent;
|
||||
|
||||
aTemplChild->GetParent(*getter_AddRefs(templParent));
|
||||
|
||||
if (templParent.get() == aTemplRoot)
|
||||
copyParent = aCopyRoot;
|
||||
else
|
||||
LocateInstance(aTemplRoot, aCopyRoot, templParent, getter_AddRefs(copyParent));
|
||||
|
||||
PRInt32 index;
|
||||
templParent->IndexOf(aTemplChild, index);
|
||||
copyParent->ChildAt(index, *aCopyResult); // Addref happens here.
|
||||
}
|
||||
|
||||
struct nsXBLAttrChangeData
|
||||
{
|
||||
nsXBLPrototypeBinding* mProto;
|
||||
nsIContent* mBoundElement;
|
||||
nsIContent* mContent;
|
||||
|
||||
nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
|
||||
nsIContent* aElt, nsIContent* aContent)
|
||||
:mProto(aProto), mBoundElement(aElt), mContent(aContent) {};
|
||||
};
|
||||
|
||||
PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
|
||||
{
|
||||
// XXX How to deal with NAMESPACES!!!?
|
||||
nsIXBLAttributeEntry* entry = (nsIXBLAttributeEntry*)aData;
|
||||
nsXBLAttrChangeData* changeData = (nsXBLAttrChangeData*)aClosure;
|
||||
|
||||
nsCOMPtr<nsIAtom> src;
|
||||
entry->GetSrcAttribute(getter_AddRefs(src));
|
||||
|
||||
nsAutoString value;
|
||||
nsresult result = changeData->mBoundElement->GetAttribute(kNameSpaceID_None, src, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
if (attrPresent) {
|
||||
nsCOMPtr<nsIContent> content;
|
||||
changeData->mProto->GetImmediateChild(nsXBLPrototypeBinding::kContentAtom, getter_AddRefs(content));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> curr = entry;
|
||||
while (curr) {
|
||||
nsCOMPtr<nsIAtom> dst;
|
||||
nsCOMPtr<nsIContent> element;
|
||||
curr->GetDstAttribute(getter_AddRefs(dst));
|
||||
curr->GetElement(getter_AddRefs(element));
|
||||
|
||||
nsCOMPtr<nsIContent> realElement;
|
||||
changeData->mProto->LocateInstance(content, changeData->mContent, element, getter_AddRefs(realElement));
|
||||
if (realElement) {
|
||||
realElement->SetAttribute(kNameSpaceID_None, dst, value, PR_FALSE);
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
realElement->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == nsXBLPrototypeBinding::kHTMLAtom) && (dst.get() == nsXBLPrototypeBinding::kValueAtom) && !value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
changeData->mBoundElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(realElement));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> next = curr;
|
||||
curr->GetNext(getter_AddRefs(next));
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
|
||||
{
|
||||
if (mAttributeTable) {
|
||||
nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
|
||||
mAttributeTable->Enumerate(SetAttrs, (void*)&data);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
|
||||
{
|
||||
nsAutoString inherits;
|
||||
aElement->GetAttribute(kNameSpaceID_None, kInheritsAtom, inherits);
|
||||
if (!inherits.IsEmpty()) {
|
||||
if (!mAttributeTable) {
|
||||
mAttributeTable = new nsSupportsHashtable(4);
|
||||
}
|
||||
|
||||
// The user specified at least one attribute.
|
||||
char* str = inherits.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichars
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, ", ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this attribute.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
nsCOMPtr<nsIAtom> attribute;
|
||||
|
||||
// Figure out if this token contains a :.
|
||||
nsAutoString attrTok; attrTok.AssignWithConversion(token);
|
||||
PRInt32 index = attrTok.Find("=", PR_TRUE);
|
||||
if (index != -1) {
|
||||
// This attribute maps to something different.
|
||||
nsAutoString left, right;
|
||||
attrTok.Left(left, index);
|
||||
attrTok.Right(right, attrTok.Length()-index-1);
|
||||
|
||||
atom = getter_AddRefs(NS_NewAtom(right.GetUnicode()));
|
||||
attribute = getter_AddRefs(NS_NewAtom(left.GetUnicode()));
|
||||
}
|
||||
else {
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
attribute = atom;
|
||||
}
|
||||
|
||||
// Create an XBL attribute entry.
|
||||
nsXBLAttributeEntry* xblAttr = new (kPool) nsXBLAttributeEntry(atom, attribute, aElement);
|
||||
|
||||
// Now we should see if some element within our anonymous
|
||||
// content is already observing this attribute.
|
||||
nsISupportsKey key(atom);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> entry = do_QueryInterface(supports);
|
||||
if (!entry) {
|
||||
// Put it in the table.
|
||||
mAttributeTable->Put(&key, xblAttr);
|
||||
} else {
|
||||
nsCOMPtr<nsIXBLAttributeEntry> attr = entry;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = entry;
|
||||
do {
|
||||
attr = tmpAttr;
|
||||
attr->GetNext(getter_AddRefs(tmpAttr));
|
||||
} while (tmpAttr);
|
||||
attr->SetNext(xblAttr);
|
||||
}
|
||||
|
||||
// Now remove the inherits attribute from the element so that it doesn't
|
||||
// show up on clones of the element. It is used
|
||||
// by the template only, and we don't need it anymore.
|
||||
aElement->UnsetAttribute(kNameSpaceID_None, kInheritsAtom, PR_FALSE);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
|
||||
// Recur into our children.
|
||||
PRInt32 childCount;
|
||||
aElement->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aElement->ChildAt(i, *getter_AddRefs(child));
|
||||
ConstructAttributeTable(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
|
||||
{
|
||||
nsCOMPtr<nsISupportsArray> childrenElements;
|
||||
GetNestedChildren(kChildrenAtom, aContent, getter_AddRefs(childrenElements));
|
||||
|
||||
if (!childrenElements)
|
||||
return;
|
||||
|
||||
mInsertionPointTable = new nsSupportsHashtable;
|
||||
|
||||
PRUint32 count;
|
||||
childrenElements->Count(&count);
|
||||
PRUint32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
nsAutoString includes;
|
||||
child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if (includes.IsEmpty()) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
}
|
||||
else {
|
||||
// The user specified at least one attribute.
|
||||
char* str = includes.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichar's
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, "| ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this string.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
|
||||
nsISupportsKey key(atom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove the <children> elements.
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
PRInt32 index;
|
||||
parent->IndexOf(child, index);
|
||||
parent->RemoveChildAt(index, PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList)
|
||||
{
|
||||
PRInt32 childCount;
|
||||
aContent->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aContent->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
if (!*aList)
|
||||
NS_NewISupportsArray(aList); // Addref happens here.
|
||||
(*aList)->AppendElement(child);
|
||||
}
|
||||
else
|
||||
GetNestedChildren(aTag, child, aList);
|
||||
}
|
||||
}
|
||||
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
NS_NewXBLPrototypeBinding(const nsCString& aRef, nsIContent* aElement,
|
||||
nsIXBLDocumentInfo* aInfo, nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = new nsXBLPrototypeBinding(aRef, aElement, aInfo);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
135
content/xbl/src/nsXBLPrototypeBinding.h
Normal file
135
content/xbl/src/nsXBLPrototypeBinding.h
Normal file
@ -0,0 +1,135 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIAtom;
|
||||
class nsIDocument;
|
||||
class nsIScriptContext;
|
||||
class nsISupportsArray;
|
||||
class nsSupportsHashtable;
|
||||
class nsIXBLService;
|
||||
class nsFixedSizeAllocator;
|
||||
|
||||
// *********************************************************************/
|
||||
// The XBLPrototypeBinding class
|
||||
|
||||
class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIXBLPrototypeBinding
|
||||
NS_IMETHOD GetBindingElement(nsIContent** aResult);
|
||||
NS_IMETHOD SetBindingElement(nsIContent* aElement);
|
||||
|
||||
NS_IMETHOD GetBindingURI(nsCString& aResult);
|
||||
NS_IMETHOD GetDocURI(nsCString& aResult);
|
||||
NS_IMETHOD GetID(nsCString& aResult);
|
||||
|
||||
NS_IMETHOD GetAllowScripts(PRBool* aResult);
|
||||
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult);
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(nsIXBLPrototypeHandler** aHandler);
|
||||
NS_IMETHOD SetPrototypeHandler(nsIXBLPrototypeHandler* aHandler);
|
||||
|
||||
NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag,
|
||||
nsIContent* aChangedElement, nsIContent* aAnonymousContent);
|
||||
|
||||
NS_IMETHOD SetBasePrototype(nsIXBLPrototypeBinding* aBinding);
|
||||
NS_IMETHOD GetBasePrototype(nsIXBLPrototypeBinding** aResult);
|
||||
|
||||
NS_IMETHOD GetXBLDocumentInfo(nsIContent* aBoundElement, nsIXBLDocumentInfo** aResult);
|
||||
|
||||
NS_IMETHOD HasBasePrototype(PRBool* aResult);
|
||||
NS_IMETHOD SetHasBasePrototype(PRBool aHasBase);
|
||||
|
||||
NS_IMETHOD SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);
|
||||
|
||||
NS_IMETHOD HasInsertionPoints(PRBool* aResult) { *aResult = (mInsertionPointTable != nsnull); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent* aChild, nsIContent** aResult);
|
||||
|
||||
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent** aResult, PRBool* aMultiple);
|
||||
|
||||
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag);
|
||||
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
|
||||
|
||||
public:
|
||||
nsXBLPrototypeBinding(const nsCString& aRef, nsIContent* aElement,
|
||||
nsIXBLDocumentInfo* aInfo);
|
||||
virtual ~nsXBLPrototypeBinding();
|
||||
|
||||
// Static members
|
||||
static PRUint32 gRefCnt;
|
||||
static nsIXBLService* gXBLService;
|
||||
static nsIAtom* kInheritStyleAtom;
|
||||
static nsIAtom* kHandlersAtom;
|
||||
static nsIAtom* kChildrenAtom;
|
||||
static nsIAtom* kIncludesAtom;
|
||||
static nsIAtom* kContentAtom;
|
||||
static nsIAtom* kInheritsAtom;
|
||||
static nsIAtom* kHTMLAtom;
|
||||
static nsIAtom* kValueAtom;
|
||||
|
||||
static nsFixedSizeAllocator kPool;
|
||||
|
||||
// Internal member functions
|
||||
public:
|
||||
void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult);
|
||||
void LocateInstance(nsIContent* aTemplRoot, nsIContent* aCopyRoot,
|
||||
nsIContent* aTemplChild, nsIContent** aCopyResult);
|
||||
|
||||
protected:
|
||||
void ConstructHandlers();
|
||||
void ConstructAttributeTable(nsIContent* aElement);
|
||||
void ConstructInsertionTable(nsIContent* aElement);
|
||||
void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList);
|
||||
|
||||
// MEMBER VARIABLES
|
||||
protected:
|
||||
nsCString mID;
|
||||
|
||||
nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> mBaseBinding; // Strong. We own the base binding in our explicit inheritance chain.
|
||||
PRPackedBool mInheritStyle;
|
||||
PRPackedBool mHasBaseProto;
|
||||
|
||||
nsWeakPtr mXBLDocInfoWeak; // A pointer back to our doc info. Weak, since it owns us.
|
||||
|
||||
nsSupportsHashtable* mAttributeTable; // A table for attribute entries. Used to efficiently
|
||||
// handle attribute changes.
|
||||
|
||||
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points for placing explicit content
|
||||
// underneath anonymous content.
|
||||
|
||||
PRInt32 mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will
|
||||
nsCOMPtr<nsIAtom> mBaseTag; // be stored in here.
|
||||
};
|
@ -54,6 +54,7 @@
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "nsIXBLBinding.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIXBLDocumentInfo.h"
|
||||
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
@ -343,9 +344,6 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
NS_NewXBLDocumentInfo(mBindingDocument, getter_AddRefs(info));
|
||||
|
||||
// Construct our prototype handlers.
|
||||
nsXBLService::ConstructPrototypeHandlers(info);
|
||||
|
||||
// If the doc is a chrome URI, then we put it into the XUL cache.
|
||||
PRBool cached = PR_FALSE;
|
||||
if (IsChromeURI(uri) && gXULUtils->UseXULCache()) {
|
||||
@ -486,7 +484,6 @@ PRUint32 nsXBLService::gClassLRUListLength = 0;
|
||||
PRUint32 nsXBLService::gClassLRUListQuota = 64;
|
||||
|
||||
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
|
||||
nsIAtom* nsXBLService::kHandlersAtom = nsnull;
|
||||
nsIAtom* nsXBLService::kScrollbarAtom = nsnull;
|
||||
nsIAtom* nsXBLService::kInputAtom = nsnull;
|
||||
|
||||
@ -526,7 +523,6 @@ nsXBLService::nsXBLService(void)
|
||||
|
||||
// Create our atoms
|
||||
kExtendsAtom = NS_NewAtom("extends");
|
||||
kHandlersAtom = NS_NewAtom("handlers");
|
||||
kScrollbarAtom = NS_NewAtom("scrollbar");
|
||||
kInputAtom = NS_NewAtom("input");
|
||||
|
||||
@ -558,7 +554,6 @@ nsXBLService::~nsXBLService(void)
|
||||
|
||||
// Release our atoms
|
||||
NS_RELEASE(kExtendsAtom);
|
||||
NS_RELEASE(kHandlersAtom);
|
||||
NS_RELEASE(kScrollbarAtom);
|
||||
NS_RELEASE(kInputAtom);
|
||||
|
||||
@ -915,77 +910,114 @@ NS_IMETHODIMP nsXBLService::GetBindingInternal(nsIContent* aBoundElement,
|
||||
PRBool allowScripts;
|
||||
docInfo->GetScriptAccess(&allowScripts);
|
||||
|
||||
// We have a doc. Obtain our specific binding element.
|
||||
// Walk the children looking for the binding that matches the ref
|
||||
// specified in the URL.
|
||||
nsCOMPtr<nsIContent> root = getter_AddRefs(doc->GetRootContent());
|
||||
if (!root)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> protoBinding;
|
||||
docInfo->GetPrototypeBinding(ref, getter_AddRefs(protoBinding));
|
||||
nsCOMPtr<nsIContent> child;
|
||||
if (!protoBinding) {
|
||||
// We have a doc. Obtain our specific binding element.
|
||||
// Walk the children looking for the binding that matches the ref
|
||||
// specified in the URL.
|
||||
nsCOMPtr<nsIContent> root = getter_AddRefs(doc->GetRootContent());
|
||||
if (!root)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString bindingName; bindingName.AssignWithConversion( NS_STATIC_CAST(const char*, ref) );
|
||||
nsAutoString bindingName; bindingName.AssignWithConversion( NS_STATIC_CAST(const char*, ref) );
|
||||
|
||||
PRInt32 count;
|
||||
root->ChildCount(count);
|
||||
PRInt32 count;
|
||||
root->ChildCount(count);
|
||||
|
||||
for (PRInt32 i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
root->ChildAt(i, *getter_AddRefs(child));
|
||||
for (PRInt32 i = 0; i < count; i++) {
|
||||
root->ChildAt(i, *getter_AddRefs(child));
|
||||
|
||||
nsAutoString value;
|
||||
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, value);
|
||||
nsAutoString value;
|
||||
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, value);
|
||||
|
||||
// If no ref is specified just use this.
|
||||
if ((bindingName.IsEmpty()) || (bindingName == value)) {
|
||||
// Check for the presence of an extends attribute
|
||||
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.
|
||||
// If no ref is specified just use this.
|
||||
if ((bindingName.IsEmpty()) || (bindingName == value)) {
|
||||
// Construct a prototype binding.
|
||||
NS_NewXBLPrototypeBinding(ref, child, docInfo, getter_AddRefs(protoBinding));
|
||||
docInfo->SetPrototypeBinding(ref, protoBinding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
protoBinding->GetBindingElement(getter_AddRefs(child));
|
||||
|
||||
// If our prototype already has a base, then don't check for an "extends" attribute.
|
||||
nsCOMPtr<nsIXBLBinding> baseBinding;
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> baseProto;
|
||||
PRBool hasBase;
|
||||
protoBinding->HasBasePrototype(&hasBase);
|
||||
protoBinding->GetBasePrototype(getter_AddRefs(baseProto));
|
||||
if (baseProto) {
|
||||
nsCAutoString url;
|
||||
baseProto->GetBindingURI(url);
|
||||
if (NS_FAILED(GetBindingInternal(aBoundElement, url, aPeekOnly, aIsReady, getter_AddRefs(baseBinding))))
|
||||
return NS_ERROR_FAILURE; // We aren't ready yet.
|
||||
if (!aPeekOnly) {
|
||||
// Make sure to set the base prototype.
|
||||
baseBinding->GetPrototypeBinding(getter_AddRefs(baseProto));
|
||||
protoBinding->SetBasePrototype(baseProto);
|
||||
}
|
||||
}
|
||||
else if (hasBase) {
|
||||
// Check for the presence of an extends attribute
|
||||
nsAutoString extends;
|
||||
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
|
||||
nsAutoString value(extends);
|
||||
if (extends.IsEmpty())
|
||||
protoBinding->SetHasBasePrototype(PR_FALSE);
|
||||
else {
|
||||
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 extend some widget/frame. We don't really have a base binding.
|
||||
protoBinding->SetHasBasePrototype(PR_FALSE);
|
||||
PRInt32 nameSpaceID;
|
||||
tagSpace->GetNameSpaceID(nameSpaceID);
|
||||
nsCOMPtr<nsIAtom> tagName = getter_AddRefs(NS_NewAtom(extends));
|
||||
protoBinding->SetBaseTag(nameSpaceID, tagName);
|
||||
}
|
||||
else {
|
||||
// We have a base class binding. Load it right now.
|
||||
nsCAutoString urlCString; urlCString.AssignWithConversion(value);
|
||||
if (NS_FAILED(GetBindingInternal(aBoundElement, urlCString, aPeekOnly, aIsReady, getter_AddRefs(baseBinding))))
|
||||
return NS_ERROR_FAILURE; // Binding not yet ready or an error occurred.
|
||||
if (!aPeekOnly) {
|
||||
// Make sure to set the base prototype.
|
||||
baseBinding->GetPrototypeBinding(getter_AddRefs(baseProto));
|
||||
protoBinding->SetBasePrototype(baseProto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
||||
*aIsReady = PR_TRUE;
|
||||
if (!aPeekOnly) {
|
||||
// Make a new binding
|
||||
NS_NewXBLBinding(protoBinding, aResult);
|
||||
if (baseBinding)
|
||||
(*aResult)->SetBaseBinding(baseBinding);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1058,9 +1090,6 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement, nsIDocument* aB
|
||||
if (document) {
|
||||
NS_NewXBLDocumentInfo(document, getter_AddRefs(info));
|
||||
|
||||
// Construct our prototype handlers.
|
||||
ConstructPrototypeHandlers(info);
|
||||
|
||||
// If the doc is a chrome URI, then we put it into the XUL cache.
|
||||
PRBool cached = PR_FALSE;
|
||||
if (IsChromeURI(uri) && gXULUtils->UseXULCache()) {
|
||||
@ -1288,40 +1317,6 @@ nsXBLService::BuildHandlerChain(nsIContent* aContent, nsIXBLPrototypeHandler** a
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXBLService::ConstructPrototypeHandlers(nsIXBLDocumentInfo* aInfo)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aInfo->GetDocument(getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIContent> bindings = getter_AddRefs(doc->GetRootContent());
|
||||
PRInt32 childCount;
|
||||
bindings->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> binding;
|
||||
bindings->ChildAt(i, *getter_AddRefs(binding));
|
||||
|
||||
// See if this binding has a handler elt.
|
||||
nsCOMPtr<nsIContent> handlers;
|
||||
GetImmediateChild(kHandlersAtom, binding, getter_AddRefs(handlers));
|
||||
if (handlers) {
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> firstHandler;
|
||||
nsXBLService::BuildHandlerChain(handlers, getter_AddRefs(firstHandler));
|
||||
|
||||
if (firstHandler) {
|
||||
nsAutoString ref;
|
||||
binding->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, ref);
|
||||
|
||||
nsCAutoString cref;
|
||||
cref.AssignWithConversion(ref);
|
||||
|
||||
aInfo->SetPrototypeHandler(cref, firstHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
|
@ -103,7 +103,6 @@ public:
|
||||
// This method walks a binding document and removes any text nodes
|
||||
// that contain only whitespace.
|
||||
static nsresult StripWhitespaceNodes(nsIContent* aContent);
|
||||
static nsresult ConstructPrototypeHandlers(nsIXBLDocumentInfo* aInfo);
|
||||
static nsresult BuildHandlerChain(nsIContent* aContent, nsIXBLPrototypeHandler** aResult);
|
||||
|
||||
// MEMBER VARIABLES
|
||||
@ -126,7 +125,6 @@ public:
|
||||
|
||||
// XBL Atoms
|
||||
static nsIAtom* kExtendsAtom;
|
||||
static nsIAtom* kHandlersAtom;
|
||||
static nsIAtom* kScrollbarAtom;
|
||||
static nsIAtom* kInputAtom;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
#include "nsXBLWindowKeyHandler.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
@ -41,6 +42,9 @@
|
||||
#include "nsIDOMXULCommandDispatcher.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
|
||||
PRUint32 nsXBLWindowKeyHandler::gRefCnt = 0;
|
||||
nsIAtom* nsXBLWindowKeyHandler::kKeyDownAtom = nsnull;
|
||||
@ -115,6 +119,33 @@ nsXBLWindowKeyHandler::IsEditor()
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
static void GetHandlers(nsIXBLDocumentInfo* aInfo, const nsCString& aDocURI,
|
||||
const nsCString& aRef, nsIXBLPrototypeHandler** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> binding;
|
||||
aInfo->GetPrototypeBinding(aRef, getter_AddRefs(binding));
|
||||
if (!binding) {
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aInfo->GetDocument(getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIContent> root = getter_AddRefs(doc->GetRootContent());
|
||||
PRInt32 childCount;
|
||||
root->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
root->ChildAt(i, *getter_AddRefs(child));
|
||||
nsAutoString id;
|
||||
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, id);
|
||||
if (id.EqualsWithConversion(aRef)) {
|
||||
NS_NewXBLPrototypeBinding(aRef, child, aInfo, getter_AddRefs(binding));
|
||||
aInfo->SetPrototypeBinding(aRef, binding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding->GetPrototypeHandler(aResult); // Addref happens here.
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLWindowKeyHandler::EnsureHandlers()
|
||||
{
|
||||
@ -158,16 +189,24 @@ nsXBLWindowKeyHandler::EnsureHandlers()
|
||||
|
||||
// Now determine which handlers we should be using.
|
||||
if (IsEditor()) {
|
||||
mXBLSpecialDocInfo->mPlatformHTMLBindings->GetPrototypeHandler(nsCAutoString("editor"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
mXBLSpecialDocInfo->mHTMLBindings->GetPrototypeHandler(nsCAutoString("editorBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mPlatformHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/platformHTMLBindings.xml"),
|
||||
nsCAutoString("editor"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/htmlBindings.xml"),
|
||||
nsCAutoString("editorBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
}
|
||||
else {
|
||||
mXBLSpecialDocInfo->mPlatformHTMLBindings->GetPrototypeHandler(nsCAutoString("browser"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
mXBLSpecialDocInfo->mHTMLBindings->GetPrototypeHandler(nsCAutoString("browserBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mPlatformHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/platformHTMLBindings.xml"),
|
||||
nsCAutoString("browser"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/htmlBindings.xml"),
|
||||
nsCAutoString("browserBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5278,14 +5278,7 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
|
||||
if (!xblService)
|
||||
return rv;
|
||||
|
||||
// Load the bindings.
|
||||
nsCOMPtr<nsIXBLBinding> binding;
|
||||
PRBool dummy;
|
||||
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding), &dummy);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_OK;
|
||||
|
||||
// Retrieve the anonymous content that we should build.
|
||||
// Retrieve the anonymous content that we should build.
|
||||
nsCOMPtr<nsISupportsArray> anonymousItems;
|
||||
nsCOMPtr<nsIContent> childElement;
|
||||
PRBool multiple;
|
||||
@ -5524,13 +5517,6 @@ nsCSSFrameConstructor::CreateAnonymousTableCellFrames(nsIPresShell* aPres
|
||||
if (!xblService)
|
||||
return rv;
|
||||
|
||||
// Load the bindings.
|
||||
nsCOMPtr<nsIXBLBinding> binding;
|
||||
PRBool dummy;
|
||||
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding), &dummy);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_OK;
|
||||
|
||||
// Retrieve the anonymous content that we should build.
|
||||
nsCOMPtr<nsIContent> childElement;
|
||||
nsCOMPtr<nsISupportsArray> anonymousItems;
|
||||
|
@ -5278,14 +5278,7 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
|
||||
if (!xblService)
|
||||
return rv;
|
||||
|
||||
// Load the bindings.
|
||||
nsCOMPtr<nsIXBLBinding> binding;
|
||||
PRBool dummy;
|
||||
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding), &dummy);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_OK;
|
||||
|
||||
// Retrieve the anonymous content that we should build.
|
||||
// Retrieve the anonymous content that we should build.
|
||||
nsCOMPtr<nsISupportsArray> anonymousItems;
|
||||
nsCOMPtr<nsIContent> childElement;
|
||||
PRBool multiple;
|
||||
@ -5524,13 +5517,6 @@ nsCSSFrameConstructor::CreateAnonymousTableCellFrames(nsIPresShell* aPres
|
||||
if (!xblService)
|
||||
return rv;
|
||||
|
||||
// Load the bindings.
|
||||
nsCOMPtr<nsIXBLBinding> binding;
|
||||
PRBool dummy;
|
||||
rv = xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE, getter_AddRefs(binding), &dummy);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_OK;
|
||||
|
||||
// Retrieve the anonymous content that we should build.
|
||||
nsCOMPtr<nsIContent> childElement;
|
||||
nsCOMPtr<nsISupportsArray> anonymousItems;
|
||||
|
@ -79,7 +79,7 @@ CSS_PROP(background-position, background_position, VISUAL)
|
||||
CSS_PROP(background-repeat, background_repeat, VISUAL)
|
||||
CSS_PROP(-x-background-x-position, background_x_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-x-background-y-position, background_y_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, REFLOW) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, FRAMECHANGE) // XXX bug 3935
|
||||
CSS_PROP(border, border, REFLOW)
|
||||
CSS_PROP(border-bottom, border_bottom, REFLOW)
|
||||
CSS_PROP(border-bottom-color, border_bottom_color, VISUAL)
|
||||
|
@ -79,7 +79,7 @@ CSS_PROP(background-position, background_position, VISUAL)
|
||||
CSS_PROP(background-repeat, background_repeat, VISUAL)
|
||||
CSS_PROP(-x-background-x-position, background_x_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-x-background-y-position, background_y_position, VISUAL) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, REFLOW) // XXX bug 3935
|
||||
CSS_PROP(-moz-binding, behavior, FRAMECHANGE) // XXX bug 3935
|
||||
CSS_PROP(border, border, REFLOW)
|
||||
CSS_PROP(border-bottom, border_bottom, REFLOW)
|
||||
CSS_PROP(border-bottom-color, border_bottom_color, VISUAL)
|
||||
|
@ -33,6 +33,7 @@ EXPORTS = \
|
||||
nsIXBLBinding.h \
|
||||
nsIXBLBindingAttachedHandler.h \
|
||||
nsIXBLDocumentInfo.h \
|
||||
nsIXBLPrototypeBinding.h \
|
||||
nsIXBLPrototypeHandler.h \
|
||||
nsIXBLService.h \
|
||||
$(NULL)
|
||||
|
@ -2,6 +2,6 @@ nsIBindingManager.h
|
||||
nsIXBLBinding.h
|
||||
nsIXBLBindingAttachedHandler.h
|
||||
nsIXBLDocumentInfo.h
|
||||
nsIXBLPrototypeBinding.h
|
||||
nsIXBLPrototypeHandler.h
|
||||
nsIXBLService.h
|
||||
|
||||
|
@ -26,6 +26,7 @@ EXPORTS = \
|
||||
nsIXBLBinding.h \
|
||||
nsIXBLBindingAttachedHandler.h \
|
||||
nsIXBLDocumentInfo.h \
|
||||
nsIXBLPrototypeBinding.h \
|
||||
nsIXBLPrototypeHandler.h \
|
||||
nsIXBLService.h \
|
||||
$(NULL)
|
||||
|
@ -38,6 +38,7 @@
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIScriptContext;
|
||||
class nsIXBLPrototypeBinding;
|
||||
|
||||
// {DDDBAD20-C8DF-11d3-97FB-00400553EEF0}
|
||||
#define NS_IXBLBINDING_IID \
|
||||
@ -48,6 +49,9 @@ class nsIXBLBinding : public nsISupports
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLBINDING_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetPrototypeBinding(nsIXBLPrototypeBinding** aResult)=0;
|
||||
NS_IMETHOD SetPrototypeBinding(nsIXBLPrototypeBinding* aProtoBinding)=0;
|
||||
|
||||
NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult) = 0;
|
||||
NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding) = 0;
|
||||
|
||||
@ -92,13 +96,11 @@ public:
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult)=0;
|
||||
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
|
||||
NS_NewXBLBinding(const nsCString& aDocURI, const nsCString& aID, nsIXBLBinding** aResult);
|
||||
NS_NewXBLBinding(nsIXBLPrototypeBinding* aProtoBinding, nsIXBLBinding** aResult);
|
||||
|
||||
#endif // nsIXBLBinding_h__
|
||||
|
@ -39,6 +39,7 @@ class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIScriptContext;
|
||||
class nsIXBLPrototypeHandler;
|
||||
class nsIXBLPrototypeBinding;
|
||||
|
||||
// {5C4D9674-A2CF-4ddf-9F65-E1806C34D28D}
|
||||
#define NS_IXBLDOCUMENTINFO_IID \
|
||||
@ -55,8 +56,10 @@ public:
|
||||
NS_IMETHOD GetScriptAccess(PRBool* aResult)=0;
|
||||
NS_IMETHOD SetScriptAccess(PRBool aAccess)=0;
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler** aResult)=0;
|
||||
NS_IMETHOD SetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler* aHandler)=0;
|
||||
NS_IMETHOD GetDocumentURI(nsCString& aDocURI)=0;
|
||||
|
||||
NS_IMETHOD GetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding** aResult)=0;
|
||||
NS_IMETHOD SetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding* aBinding)=0;
|
||||
};
|
||||
|
||||
extern nsresult
|
||||
|
88
layout/xbl/public/nsIXBLPrototypeBinding.h
Normal file
88
layout/xbl/public/nsIXBLPrototypeBinding.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsIXBLPrototypeBinding_h__
|
||||
#define nsIXBLPrototypeBinding_h__
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIXBLDocumentInfo;
|
||||
class nsIXBLPrototypeHandler;
|
||||
|
||||
// {34D700F5-C1A2-4408-A0B1-DD8F891DD1FE}
|
||||
#define NS_IXBLPROTOTYPEBINDING_IID \
|
||||
{ 0x34d700f5, 0xc1a2, 0x4408, { 0xa0, 0xb1, 0xdd, 0x8f, 0x89, 0x1d, 0xd1, 0xfe } }
|
||||
|
||||
class nsIXBLPrototypeBinding : public nsISupports
|
||||
{
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLPROTOTYPEBINDING_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetBindingElement(nsIContent** aResult)=0;
|
||||
NS_IMETHOD SetBindingElement(nsIContent* aElement)=0;
|
||||
|
||||
NS_IMETHOD GetBindingURI(nsCString& aResult)=0;
|
||||
NS_IMETHOD GetDocURI(nsCString& aResult)=0;
|
||||
NS_IMETHOD GetID(nsCString& aResult)=0;
|
||||
|
||||
NS_IMETHOD GetAllowScripts(PRBool* aResult)=0;
|
||||
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult)=0;
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(nsIXBLPrototypeHandler** aHandler)=0;
|
||||
NS_IMETHOD SetPrototypeHandler(nsIXBLPrototypeHandler* aHandler)=0;
|
||||
|
||||
NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag,
|
||||
nsIContent* aChangedElement, nsIContent* aAnonymousContent)=0;
|
||||
|
||||
NS_IMETHOD SetBasePrototype(nsIXBLPrototypeBinding* aBinding)=0;
|
||||
NS_IMETHOD GetBasePrototype(nsIXBLPrototypeBinding** aResult)=0;
|
||||
|
||||
NS_IMETHOD HasBasePrototype(PRBool* aResult)=0;
|
||||
NS_IMETHOD SetHasBasePrototype(PRBool aHasBase)=0;
|
||||
|
||||
NS_IMETHOD GetXBLDocumentInfo(nsIContent* aBoundElement, nsIXBLDocumentInfo** aResult)=0;
|
||||
|
||||
NS_IMETHOD SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)=0;
|
||||
|
||||
NS_IMETHOD HasInsertionPoints(PRBool* aResult)=0;
|
||||
|
||||
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent* aChild, nsIContent** aResult)=0;
|
||||
|
||||
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent** aResult, PRBool* aMultipleInsertionPoints)=0;
|
||||
|
||||
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag)=0;
|
||||
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)=0;
|
||||
};
|
||||
|
||||
extern nsresult
|
||||
NS_NewXBLPrototypeBinding(const nsCString& aRef,
|
||||
nsIContent* aElement, nsIXBLDocumentInfo* aInfo,
|
||||
nsIXBLPrototypeBinding** aResult);
|
||||
|
||||
#endif // nsIXBLPrototypeBinding_h__
|
@ -28,6 +28,7 @@ DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
CPPSRCS= \
|
||||
nsXBLBinding.cpp \
|
||||
nsXBLPrototypeBinding.cpp \
|
||||
nsXBLService.cpp \
|
||||
nsXBLEventHandler.cpp \
|
||||
nsXBLWindowKeyHandler.cpp \
|
||||
@ -46,6 +47,7 @@ CPPSRCS= \
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsXBLBinding.obj \
|
||||
.\$(OBJDIR)\nsXBLPrototypeBinding.obj \
|
||||
.\$(OBJDIR)\nsXBLEventHandler.obj \
|
||||
.\$(OBJDIR)\nsXBLWindowKeyHandler.obj \
|
||||
.\$(OBJDIR)\nsXBLKeyHandler.obj \
|
||||
|
@ -58,19 +58,20 @@
|
||||
|
||||
#include "nsIStyleRuleProcessor.h"
|
||||
#include "nsIStyleSet.h"
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIWeakReference.h"
|
||||
|
||||
// Static IIDs/CIDs. Try to minimize these.
|
||||
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
|
||||
static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
|
||||
static NS_DEFINE_CID(kParserCID, NS_PARSER_IID); // XXX What's up with this???
|
||||
|
||||
class nsXBLDocumentInfo : public nsIXBLDocumentInfo
|
||||
class nsXBLDocumentInfo : public nsIXBLDocumentInfo, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsXBLDocumentInfo(nsIDocument* aDocument);
|
||||
nsXBLDocumentInfo(const char* aDocURI, nsIDocument* aDocument);
|
||||
virtual ~nsXBLDocumentInfo();
|
||||
|
||||
NS_IMETHOD GetDocument(nsIDocument** aResult) { *aResult = mDocument; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
@ -79,32 +80,36 @@ public:
|
||||
NS_IMETHOD GetScriptAccess(PRBool* aResult) { *aResult = mScriptAccess; return NS_OK; };
|
||||
NS_IMETHOD SetScriptAccess(PRBool aAccess) { mScriptAccess = aAccess; return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler** aResult);
|
||||
NS_IMETHOD SetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler* aHandler);
|
||||
NS_IMETHOD GetDocumentURI(nsCString& aDocURI) { aDocURI = mDocURI; return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding** aResult);
|
||||
NS_IMETHOD SetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding* aBinding);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCString mDocURI;
|
||||
nsCOMPtr<nsISupportsArray> mRuleProcessors;
|
||||
PRBool mScriptAccess;
|
||||
nsSupportsHashtable* mHandlerTable;
|
||||
nsSupportsHashtable* mBindingTable;
|
||||
};
|
||||
|
||||
/* Implementation file */
|
||||
NS_IMPL_ISUPPORTS1(nsXBLDocumentInfo, nsIXBLDocumentInfo)
|
||||
NS_IMPL_ISUPPORTS2(nsXBLDocumentInfo, nsIXBLDocumentInfo, nsISupportsWeakReference)
|
||||
|
||||
nsXBLDocumentInfo::nsXBLDocumentInfo(nsIDocument* aDocument)
|
||||
nsXBLDocumentInfo::nsXBLDocumentInfo(const char* aDocURI, nsIDocument* aDocument)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
/* member initializers and constructor code */
|
||||
mDocURI = aDocURI;
|
||||
mDocument = aDocument;
|
||||
mScriptAccess = PR_TRUE;
|
||||
mHandlerTable = nsnull;
|
||||
mBindingTable = nsnull;
|
||||
}
|
||||
|
||||
nsXBLDocumentInfo::~nsXBLDocumentInfo()
|
||||
{
|
||||
/* destructor code */
|
||||
delete mHandlerTable;
|
||||
delete mBindingTable;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -144,33 +149,39 @@ nsXBLDocumentInfo::GetRuleProcessors(nsISupportsArray** aResult)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLDocumentInfo::GetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler** aResult)
|
||||
nsXBLDocumentInfo::GetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
if (!mHandlerTable)
|
||||
if (!mBindingTable)
|
||||
return NS_OK;
|
||||
|
||||
nsCStringKey key(aRef);
|
||||
*aResult = NS_STATIC_CAST(nsIXBLPrototypeHandler*, mHandlerTable->Get(&key)); // Addref happens here.
|
||||
*aResult = NS_STATIC_CAST(nsIXBLPrototypeBinding*, mBindingTable->Get(&key)); // Addref happens here.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLDocumentInfo::SetPrototypeHandler(const nsCString& aRef, nsIXBLPrototypeHandler* aHandler)
|
||||
nsXBLDocumentInfo::SetPrototypeBinding(const nsCString& aRef, nsIXBLPrototypeBinding* aBinding)
|
||||
{
|
||||
if (!mHandlerTable)
|
||||
mHandlerTable = new nsSupportsHashtable();
|
||||
if (!mBindingTable)
|
||||
mBindingTable = new nsSupportsHashtable();
|
||||
|
||||
nsCStringKey key(aRef);
|
||||
mHandlerTable->Put(&key, aHandler);
|
||||
mBindingTable->Put(&key, aBinding);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_NewXBLDocumentInfo(nsIDocument* aDocument, nsIXBLDocumentInfo** aResult)
|
||||
{
|
||||
*aResult = new nsXBLDocumentInfo(aDocument);
|
||||
nsCOMPtr<nsIURI> url = getter_AddRefs(aDocument->GetDocumentURL());
|
||||
|
||||
nsXPIDLCString str;
|
||||
url->GetSpec(getter_Copies(str));
|
||||
|
||||
*aResult = new nsXBLDocumentInfo((const char*)str, aDocument);
|
||||
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -683,10 +694,7 @@ nsBindingManager::RemoveLoadingDocListener(const nsCString& aURL)
|
||||
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();
|
||||
binding->MarkForDeath();
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -85,51 +85,6 @@
|
||||
static char kNameSpaceSeparator = ':';
|
||||
|
||||
// Helper classes
|
||||
// {A2892B81-CED9-11d3-97FB-00400553EEF0}
|
||||
#define NS_IXBLATTR_IID \
|
||||
{ 0xa2892b81, 0xced9, 0x11d3, { 0x97, 0xfb, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } }
|
||||
|
||||
class nsIXBLAttributeEntry : public nsISupports {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLATTR_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetAttribute(nsIAtom** aResult) = 0;
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) = 0;
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) = 0;
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) = 0;
|
||||
};
|
||||
|
||||
|
||||
class nsXBLAttributeEntry : public nsIXBLAttributeEntry {
|
||||
public:
|
||||
NS_IMETHOD GetAttribute(nsIAtom** aResult) { *aResult = mAttribute; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) { *aResult = mElement; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) { NS_IF_ADDREF(*aResult = mNext); return NS_OK; }
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) { mNext = aEntry; return NS_OK; }
|
||||
|
||||
nsIContent* mElement;
|
||||
nsCOMPtr<nsIAtom> mAttribute;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> mNext;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
nsXBLAttributeEntry(nsIAtom* aAtom, nsIContent* aContent) {
|
||||
NS_INIT_REFCNT(); mAttribute = aAtom; mElement = aContent;
|
||||
};
|
||||
|
||||
virtual ~nsXBLAttributeEntry() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
|
||||
|
||||
/***********************************************************************/
|
||||
//
|
||||
@ -193,10 +148,7 @@ nsIAtom* nsXBLBinding::kInheritsAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kEventAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kPhaseAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kExtendsAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kChildrenAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kValueAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kActionAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kHTMLAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kMethodAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kParameterAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kBodyAtom = nsnull;
|
||||
@ -210,19 +162,6 @@ nsIAtom* nsXBLBinding::kReadOnlyAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kAttachToAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kBindingAttachedAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kBindingDetachedAtom = nsnull;
|
||||
nsIAtom* nsXBLBinding::kInheritStyleAtom = nsnull;
|
||||
|
||||
nsIXBLService* nsXBLBinding::gXBLService = nsnull;
|
||||
|
||||
nsFixedSizeAllocator nsXBLBinding::kPool;
|
||||
|
||||
static const size_t kBucketSizes[] = {
|
||||
sizeof(nsXBLAttributeEntry)
|
||||
};
|
||||
|
||||
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
|
||||
static const PRInt32 kNumElements = 128;
|
||||
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
|
||||
|
||||
nsXBLBinding::EventHandlerMapEntry
|
||||
nsXBLBinding::kEventHandlerMap[] = {
|
||||
@ -283,22 +222,17 @@ nsXBLBinding::kEventHandlerMap[] = {
|
||||
NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
|
||||
|
||||
// Constructors/Destructors
|
||||
nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
: mDocURI(aDocURI), mID(aID), mFirstHandler(nsnull),
|
||||
nsXBLBinding::nsXBLBinding(nsIXBLPrototypeBinding* aBinding)
|
||||
: mFirstHandler(nsnull),
|
||||
mIsStyleBinding(PR_TRUE),
|
||||
mAllowScripts(PR_TRUE),
|
||||
mInheritStyle(PR_TRUE),
|
||||
mMarkedForDeath(PR_FALSE),
|
||||
mAttributeTable(nsnull),
|
||||
mInsertionPointTable(nsnull)
|
||||
mMarkedForDeath(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mPrototypeBinding = aBinding;
|
||||
gRefCnt++;
|
||||
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
|
||||
|
||||
if (gRefCnt == 1) {
|
||||
kPool.Init("XBL Attribute Entries", kBucketSizes, kNumBuckets, kInitialSize);
|
||||
|
||||
kXULTemplateAtom = NS_NewAtom("template");
|
||||
kXULObservesAtom = NS_NewAtom("observes");
|
||||
|
||||
@ -311,9 +245,6 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
kEventAtom = NS_NewAtom("event");
|
||||
kPhaseAtom = NS_NewAtom("phase");
|
||||
kExtendsAtom = NS_NewAtom("extends");
|
||||
kChildrenAtom = NS_NewAtom("children");
|
||||
kHTMLAtom = NS_NewAtom("html");
|
||||
kValueAtom = NS_NewAtom("value");
|
||||
kActionAtom = NS_NewAtom("action");
|
||||
kMethodAtom = NS_NewAtom("method");
|
||||
kParameterAtom = NS_NewAtom("parameter");
|
||||
@ -328,11 +259,6 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
kAttachToAtom = NS_NewAtom("attachto");
|
||||
kBindingAttachedAtom = NS_NewAtom("bindingattached");
|
||||
kBindingDetachedAtom = NS_NewAtom("bindingdetached");
|
||||
kInheritStyleAtom = NS_NewAtom("inheritstyle");
|
||||
|
||||
nsServiceManager::GetService("@mozilla.org/xbl;1",
|
||||
NS_GET_IID(nsIXBLService),
|
||||
(nsISupports**) &gXBLService);
|
||||
|
||||
EventHandlerMapEntry* entry = kEventHandlerMap;
|
||||
while (entry->mAttributeName) {
|
||||
@ -345,9 +271,6 @@ nsXBLBinding::nsXBLBinding(const nsCString& aDocURI, const nsCString& aID)
|
||||
|
||||
nsXBLBinding::~nsXBLBinding(void)
|
||||
{
|
||||
delete mAttributeTable;
|
||||
delete mInsertionPointTable;
|
||||
|
||||
gRefCnt--;
|
||||
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
|
||||
|
||||
@ -364,9 +287,6 @@ nsXBLBinding::~nsXBLBinding(void)
|
||||
NS_RELEASE(kEventAtom);
|
||||
NS_RELEASE(kPhaseAtom);
|
||||
NS_RELEASE(kExtendsAtom);
|
||||
NS_RELEASE(kChildrenAtom);
|
||||
NS_RELEASE(kHTMLAtom);
|
||||
NS_RELEASE(kValueAtom);
|
||||
NS_RELEASE(kActionAtom);
|
||||
NS_RELEASE(kMethodAtom);
|
||||
NS_RELEASE(kParameterAtom);
|
||||
@ -380,10 +300,6 @@ nsXBLBinding::~nsXBLBinding(void)
|
||||
NS_RELEASE(kReadOnlyAtom);
|
||||
NS_RELEASE(kAttachToAtom);
|
||||
NS_RELEASE(kBindingAttachedAtom);
|
||||
NS_RELEASE(kInheritStyleAtom);
|
||||
|
||||
nsServiceManager::ReleaseService("@mozilla.org/xbl;1", gXBLService);
|
||||
gXBLService = nsnull;
|
||||
|
||||
EventHandlerMapEntry* entry = kEventHandlerMap;
|
||||
while (entry->mAttributeName) {
|
||||
@ -448,32 +364,34 @@ nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
|
||||
child->SetBindingParent(mBoundElement);
|
||||
}
|
||||
|
||||
// (3) We need to insert entries into our attribute table for any elements
|
||||
// that are inheriting attributes. This table allows us to quickly determine
|
||||
// which elements in our anonymous content need to be updated when attributes change.
|
||||
ConstructAttributeTable(aParent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetPrototypeBinding(nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = mPrototypeBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::SetPrototypeBinding(nsIXBLPrototypeBinding* aProtoBinding)
|
||||
{
|
||||
mPrototypeBinding = aProtoBinding;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetBindingElement(nsIContent** aResult)
|
||||
{
|
||||
*aResult = mBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetBindingElement(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::SetBindingElement(nsIContent* aElement)
|
||||
{
|
||||
mBinding = aElement;
|
||||
nsAutoString inheritStyle;
|
||||
mBinding->GetAttribute(kNameSpaceID_None, kInheritStyleAtom, inheritStyle);
|
||||
if (inheritStyle == NS_LITERAL_STRING("false"))
|
||||
mInheritStyle = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->SetBindingElement(aElement);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -499,7 +417,7 @@ nsXBLBinding::HasStyleSheets(PRBool* aResolveStyle)
|
||||
// Find out if we need to re-resolve style. We'll need to do this
|
||||
// if we have additional stylesheets in our binding document.
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
gXBLService->GetXBLDocumentInfo(mDocURI, mBoundElement, getter_AddRefs(info));
|
||||
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
||||
if (!info)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsISupportsArray> rules;
|
||||
@ -528,87 +446,86 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
|
||||
else return NS_OK;
|
||||
}
|
||||
|
||||
// Plan to build the content by default.
|
||||
PRBool buildContent = PR_TRUE;
|
||||
// Find out if we're really building kids or if we're just
|
||||
// using the attribute-setting shorthand hack.
|
||||
PRInt32 contentCount;
|
||||
content->ChildCount(contentCount);
|
||||
|
||||
// See if there's an includes attribute.
|
||||
nsAutoString includes;
|
||||
content->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if ( includes != NS_LITERAL_STRING("*")) {
|
||||
PRInt32 childCount;
|
||||
aBoundElement->ChildCount(childCount);
|
||||
if (childCount > 0) {
|
||||
// We'll only build content if all the explicit children are
|
||||
// in the includes list.
|
||||
// Walk the children and ensure that all of them
|
||||
// are in the includes array.
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aBoundElement->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (!IsInExcludesList(tag, includes)) {
|
||||
// XXX HACK! Ignore <template> and <observes>
|
||||
if (tag.get() != kXULTemplateAtom &&
|
||||
tag.get() != kXULObservesAtom) {
|
||||
buildContent = PR_FALSE;
|
||||
break;
|
||||
// Plan to build the content by default.
|
||||
PRBool hasContent = (contentCount > 0);
|
||||
PRBool hasInsertionPoints;
|
||||
mPrototypeBinding->HasInsertionPoints(&hasInsertionPoints);
|
||||
|
||||
if (hasContent && !hasInsertionPoints) {
|
||||
// See if there's an includes attribute.
|
||||
nsAutoString includes;
|
||||
content->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if (includes != NS_LITERAL_STRING("*")) {
|
||||
PRInt32 childCount;
|
||||
aBoundElement->ChildCount(childCount);
|
||||
if (childCount > 0) {
|
||||
// We'll only build content if all the explicit children are
|
||||
// in the includes list.
|
||||
// Walk the children and ensure that all of them
|
||||
// are in the includes array.
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aBoundElement->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (!IsInExcludesList(tag, includes)) {
|
||||
// XXX HACK! Ignore <template> and <observes>
|
||||
if (tag.get() != kXULTemplateAtom &&
|
||||
tag.get() != kXULObservesAtom) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> childrenElement;
|
||||
// see if we have a <children/> element
|
||||
GetNestedChild(kChildrenAtom, content, getter_AddRefs(childrenElement));
|
||||
if (childrenElement)
|
||||
buildContent = PR_TRUE;
|
||||
|
||||
if (buildContent) {
|
||||
if (hasContent) {
|
||||
nsCOMPtr<nsIContent> clonedContent;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(content));
|
||||
|
||||
nsCOMPtr<nsIDOMNode> clonedNode;
|
||||
domElement->CloneNode(PR_TRUE, getter_AddRefs(clonedNode));
|
||||
|
||||
nsCOMPtr<nsIContent> clonedContent = do_QueryInterface(clonedNode);
|
||||
clonedContent = do_QueryInterface(clonedNode);
|
||||
SetAnonymousContent(clonedContent);
|
||||
}
|
||||
|
||||
// Always check the content element for potential attributes.
|
||||
PRInt32 length;
|
||||
clonedContent->GetAttributeCount(length);
|
||||
// Always check the content element for potential attributes.
|
||||
// This shorthand hack always happens, even when we didn't
|
||||
// build anonymous content.
|
||||
PRInt32 length;
|
||||
content->GetAttributeCount(length);
|
||||
|
||||
PRInt32 namespaceID;
|
||||
nsCOMPtr<nsIAtom> name;
|
||||
nsCOMPtr<nsIAtom> prefix;
|
||||
PRInt32 namespaceID;
|
||||
nsCOMPtr<nsIAtom> name;
|
||||
nsCOMPtr<nsIAtom> prefix;
|
||||
|
||||
for (PRInt32 i = 0; i < length; ++i)
|
||||
{
|
||||
clonedContent->GetAttributeNameAt(0, namespaceID, *getter_AddRefs(name), *getter_AddRefs(prefix));
|
||||
for (PRInt32 i = 0; i < length; ++i) {
|
||||
content->GetAttributeNameAt(0, namespaceID, *getter_AddRefs(name), *getter_AddRefs(prefix));
|
||||
|
||||
if (name.get() != kIncludesAtom) {
|
||||
nsAutoString value;
|
||||
mBoundElement->GetAttribute(namespaceID, name, value);
|
||||
if (value.IsEmpty()) {
|
||||
nsAutoString value2;
|
||||
clonedContent->GetAttribute(namespaceID, name, value2);
|
||||
mBoundElement->SetAttribute(namespaceID, name, value2, PR_FALSE);
|
||||
}
|
||||
if (name.get() != kIncludesAtom) {
|
||||
nsAutoString value;
|
||||
mBoundElement->GetAttribute(namespaceID, name, value);
|
||||
if (value.IsEmpty()) {
|
||||
nsAutoString value2;
|
||||
content->GetAttribute(namespaceID, name, value2);
|
||||
mBoundElement->SetAttribute(namespaceID, name, value2, PR_FALSE);
|
||||
}
|
||||
|
||||
// Conserve space by wiping the attributes off the clone.
|
||||
clonedContent->UnsetAttribute(namespaceID, name, PR_FALSE);
|
||||
}
|
||||
|
||||
if (childrenElement)
|
||||
BuildInsertionTable();
|
||||
// Conserve space by wiping the attributes off the clone.
|
||||
if (mContent)
|
||||
mContent->UnsetAttribute(namespaceID, name, PR_FALSE);
|
||||
}
|
||||
|
||||
/* XXX Handle selective decision to build anonymous content.
|
||||
if (mNextBinding) {
|
||||
return mNextBinding->GenerateAnonymousContent(aBoundElement);
|
||||
}
|
||||
*/
|
||||
if (mContent)
|
||||
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -620,12 +537,12 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement, nsIXBLBinding** aB
|
||||
if (AllowScripts()) {
|
||||
// Fetch the handlers prototypes for this binding.
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
gXBLService->GetXBLDocumentInfo(mDocURI, mBoundElement, getter_AddRefs(info));
|
||||
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
||||
if (!info)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> handlerChain;
|
||||
info->GetPrototypeHandler(mID, getter_AddRefs(handlerChain));
|
||||
mPrototypeBinding->GetPrototypeHandler(getter_AddRefs(handlerChain));
|
||||
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> curr = handlerChain;
|
||||
nsXBLEventHandler* currHandler = nsnull;
|
||||
@ -1058,116 +975,20 @@ nsXBLBinding::GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult)
|
||||
{
|
||||
if (mNextBinding)
|
||||
return mNextBinding->GetBaseTag(aNameSpaceID, aResult);
|
||||
|
||||
// XXX Cache the value as a "base" attribute so that we don't do this
|
||||
// check over and over each time the bound element occurs.
|
||||
|
||||
// We are the base binding. Obtain the extends attribute.
|
||||
nsAutoString extends;
|
||||
mBinding->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
|
||||
|
||||
if (!extends.IsEmpty()) {
|
||||
// Obtain the namespace prefix.
|
||||
nsAutoString prefix;
|
||||
PRInt32 offset = extends.FindChar(kNameSpaceSeparator);
|
||||
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(mBinding));
|
||||
if (xmlContent) {
|
||||
xmlContent->GetContainingNameSpace(*getter_AddRefs(nameSpace));
|
||||
|
||||
if (nameSpace) {
|
||||
nsCOMPtr<nsINameSpace> tagSpace;
|
||||
nameSpace->FindNameSpace(prefixAtom, *getter_AddRefs(tagSpace));
|
||||
if (tagSpace) {
|
||||
// Score! Return the tag.
|
||||
tagSpace->GetNameSpaceID(*aNameSpaceID);
|
||||
*aResult = NS_NewAtom(extends); // The addref happens here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag)
|
||||
{
|
||||
// XXX check to see if we inherit anonymous content from a base binding
|
||||
// if (mNextBinding)
|
||||
// mNextBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag);
|
||||
|
||||
if (!mAttributeTable)
|
||||
// XXX Change if we ever allow multiple bindings in a chain to contribute anonymous content
|
||||
if (!mContent) {
|
||||
if (mNextBinding)
|
||||
return mNextBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag);
|
||||
return NS_OK;
|
||||
|
||||
nsISupportsKey key(aAttribute);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> xblAttr = do_QueryInterface(supports);
|
||||
if (!xblAttr)
|
||||
return NS_OK;
|
||||
|
||||
// Iterate over the elements in the array.
|
||||
|
||||
while (xblAttr) {
|
||||
nsCOMPtr<nsIContent> element;
|
||||
nsCOMPtr<nsIAtom> setAttr;
|
||||
xblAttr->GetElement(getter_AddRefs(element));
|
||||
xblAttr->GetAttribute(getter_AddRefs(setAttr));
|
||||
|
||||
if (aRemoveFlag)
|
||||
element->UnsetAttribute(aNameSpaceID, setAttr, PR_TRUE);
|
||||
else {
|
||||
nsAutoString value;
|
||||
nsresult result = mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
|
||||
if (attrPresent)
|
||||
element->SetAttribute(aNameSpaceID, setAttr, value, PR_TRUE);
|
||||
}
|
||||
|
||||
// See if we're the <html> tag in XUL, and see if value is being
|
||||
// set or unset on us.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
element->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == kHTMLAtom) && (setAttr.get() == kValueAtom)) {
|
||||
// Flush out all our kids.
|
||||
PRInt32 childCount;
|
||||
element->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++)
|
||||
element->RemoveChildAt(0, PR_TRUE);
|
||||
|
||||
if (!aRemoveFlag) {
|
||||
// Construct a new text node and insert it.
|
||||
nsAutoString value;
|
||||
mBoundElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
if (!value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
mBoundElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(element));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = xblAttr;
|
||||
tmpAttr->GetNext(getter_AddRefs(xblAttr));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag, mBoundElement, mContent);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1254,7 +1075,7 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||
GetAnonymousContent(getter_AddRefs(anonymous));
|
||||
if (anonymous) {
|
||||
if (mIsStyleBinding)
|
||||
anonymous->SetDocument(nsnull, PR_TRUE, AllowScripts()); // Kill it.
|
||||
anonymous->SetDocument(nsnull, PR_TRUE, PR_TRUE); // Kill it.
|
||||
else anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around.
|
||||
}
|
||||
}
|
||||
@ -1265,32 +1086,32 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetBindingURI(nsCString& aResult)
|
||||
{
|
||||
aResult = mDocURI;
|
||||
aResult += "#";
|
||||
aResult += mID;
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetBindingURI(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetDocURI(nsCString& aResult)
|
||||
{
|
||||
aResult = mDocURI;
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetDocURI(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetID(nsCString& aResult)
|
||||
{
|
||||
aResult = mID;
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetID(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::InheritsStyle(PRBool* aResult)
|
||||
{
|
||||
// XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
|
||||
// Most derived binding with anonymous content determines style inheritance for now.
|
||||
|
||||
// XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
|
||||
if (mContent)
|
||||
*aResult = mInheritStyle;
|
||||
else if (mNextBinding)
|
||||
return mPrototypeBinding->InheritsStyle(aResult);
|
||||
|
||||
if (mNextBinding)
|
||||
return mNextBinding->InheritsStyle(aResult);
|
||||
|
||||
return NS_OK;
|
||||
@ -1307,7 +1128,7 @@ nsXBLBinding::WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData)
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
gXBLService->GetXBLDocumentInfo(mDocURI, mBoundElement, getter_AddRefs(info));
|
||||
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
||||
if (!info)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsISupportsArray> rules;
|
||||
@ -1422,12 +1243,15 @@ nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
|
||||
void
|
||||
nsXBLBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIContent> binding;
|
||||
mPrototypeBinding->GetBindingElement(getter_AddRefs(binding));
|
||||
|
||||
*aResult = nsnull;
|
||||
PRInt32 childCount;
|
||||
mBinding->ChildCount(childCount);
|
||||
binding->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
mBinding->ChildAt(i, *getter_AddRefs(child));
|
||||
binding->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
@ -1440,114 +1264,6 @@ nsXBLBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
PRInt32 childCount;
|
||||
aContent->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aContent->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
*aResult = aContent; // We return the parent of the correct child.
|
||||
NS_ADDREF(*aResult);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
GetNestedChild(aTag, child, aResult);
|
||||
if (*aResult)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList)
|
||||
{
|
||||
PRInt32 childCount;
|
||||
aContent->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aContent->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get())
|
||||
aList->AppendElement(child);
|
||||
else
|
||||
GetNestedChildren(aTag, child, aList);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::BuildInsertionTable()
|
||||
{
|
||||
if (!mInsertionPointTable)
|
||||
mInsertionPointTable = new nsSupportsHashtable;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> childrenElements;
|
||||
NS_NewISupportsArray(getter_AddRefs(childrenElements));
|
||||
GetNestedChildren(kChildrenAtom, mContent, childrenElements);
|
||||
|
||||
PRUint32 count;
|
||||
childrenElements->Count(&count);
|
||||
PRUint32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
nsAutoString includes;
|
||||
child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if (includes.IsEmpty()) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
}
|
||||
else {
|
||||
// The user specified at least one attribute.
|
||||
char* str = includes.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichar's
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, "| ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this string.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
|
||||
nsISupportsKey key(atom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove the <children> elements.
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
PRInt32 index;
|
||||
parent->IndexOf(child, index);
|
||||
parent->RemoveChildAt(index, PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
|
||||
{
|
||||
@ -1578,113 +1294,6 @@ nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::ConstructAttributeTable(nsIContent* aElement)
|
||||
{
|
||||
nsAutoString inherits;
|
||||
aElement->GetAttribute(kNameSpaceID_None, kInheritsAtom, inherits);
|
||||
if (!inherits.IsEmpty()) {
|
||||
if (!mAttributeTable) {
|
||||
mAttributeTable = new nsSupportsHashtable(4);
|
||||
}
|
||||
|
||||
// The user specified at least one attribute.
|
||||
char* str = inherits.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichar's
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, ", ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this attribute.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
nsCOMPtr<nsIAtom> attribute;
|
||||
|
||||
// Figure out if this token contains a :.
|
||||
nsAutoString attrTok; attrTok.AssignWithConversion(token);
|
||||
PRInt32 index = attrTok.Find("=", PR_TRUE);
|
||||
if (index != -1) {
|
||||
// This attribute maps to something different.
|
||||
nsAutoString left, right;
|
||||
attrTok.Left(left, index);
|
||||
attrTok.Right(right, attrTok.Length()-index-1);
|
||||
|
||||
atom = getter_AddRefs(NS_NewAtom(right.GetUnicode()));
|
||||
attribute = getter_AddRefs(NS_NewAtom(left.GetUnicode()));
|
||||
}
|
||||
else {
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
attribute = atom;
|
||||
}
|
||||
|
||||
// Create an XBL attribute entry.
|
||||
nsXBLAttributeEntry* xblAttr = new (kPool) nsXBLAttributeEntry(attribute, aElement);
|
||||
|
||||
// Now we should see if some element within our anonymous
|
||||
// content is already observing this attribute.
|
||||
nsISupportsKey key(atom);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> entry = do_QueryInterface(supports);
|
||||
if (!entry) {
|
||||
// Put it in the table.
|
||||
mAttributeTable->Put(&key, xblAttr);
|
||||
} else {
|
||||
nsCOMPtr<nsIXBLAttributeEntry> attr = entry;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = entry;
|
||||
do {
|
||||
attr = tmpAttr;
|
||||
attr->GetNext(getter_AddRefs(tmpAttr));
|
||||
} while (tmpAttr);
|
||||
attr->SetNext(xblAttr);
|
||||
}
|
||||
|
||||
// Now make sure that this attribute is initially set.
|
||||
// XXX How to deal with NAMESPACES!!!?
|
||||
nsAutoString value;
|
||||
nsresult result = mBoundElement->GetAttribute(kNameSpaceID_None, atom, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
|
||||
if (attrPresent) {
|
||||
aElement->SetAttribute(kNameSpaceID_None, attribute, value, PR_FALSE);
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
aElement->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == kHTMLAtom) && (attribute.get() == kValueAtom) && !value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
mBoundElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(aElement));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove the inherits attribute from the cloned element. It is used
|
||||
// on the template only, and we don't need it anymore.
|
||||
aElement->UnsetAttribute(kNameSpaceID_None, kInheritsAtom, PR_FALSE);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
|
||||
// Recur into our children.
|
||||
PRInt32 childCount;
|
||||
aElement->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aElement->ChildAt(i, *getter_AddRefs(child));
|
||||
ConstructAttributeTable(child);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound)
|
||||
{
|
||||
@ -1771,28 +1380,19 @@ nsXBLBinding::GetTextData(nsIContent *aParent, nsString& aResult)
|
||||
PRBool
|
||||
nsXBLBinding::AllowScripts()
|
||||
{
|
||||
return mAllowScripts;
|
||||
PRBool result;
|
||||
mPrototypeBinding->GetAllowScripts(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
if (mInsertionPointTable) {
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
aChild->GetTag(*getter_AddRefs(tag));
|
||||
nsISupportsKey key(tag);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
if (!content) {
|
||||
nsISupportsKey key2(kChildrenAtom);
|
||||
content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2)));
|
||||
}
|
||||
if (!mContent)
|
||||
return NS_OK;
|
||||
|
||||
*aResult = content;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1800,18 +1400,10 @@ nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleIns
|
||||
{
|
||||
*aResult = nsnull;
|
||||
*aMultipleInsertionPoints = PR_FALSE;
|
||||
if (mInsertionPointTable) {
|
||||
if(mInsertionPointTable->Count() == 1) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
*aResult = content;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
else
|
||||
*aMultipleInsertionPoints = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
if (!mContent)
|
||||
return NS_OK;
|
||||
|
||||
return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aMultipleInsertionPoints);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1844,6 +1436,7 @@ NS_IMETHODIMP
|
||||
nsXBLBinding::MarkForDeath()
|
||||
{
|
||||
mMarkedForDeath = PR_TRUE;
|
||||
ExecuteDetachedHandler();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1857,12 +1450,11 @@ nsXBLBinding::MarkedForDeath(PRBool* aResult)
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
NS_NewXBLBinding(const nsCString& aDocURI, const nsCString& aRef, nsIXBLBinding** aResult)
|
||||
NS_NewXBLBinding(nsIXBLPrototypeBinding* aBinding, nsIXBLBinding** aResult)
|
||||
{
|
||||
*aResult = new nsXBLBinding(aDocURI, aRef);
|
||||
*aResult = new nsXBLBinding(aBinding);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLBinding.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIAtom;
|
||||
@ -42,6 +43,9 @@ class nsXBLBinding: public nsIXBLBinding
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIXBLBinding
|
||||
NS_IMETHOD GetPrototypeBinding(nsIXBLPrototypeBinding** aResult);
|
||||
NS_IMETHOD SetPrototypeBinding(nsIXBLPrototypeBinding* aProtoBinding);
|
||||
|
||||
NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult);
|
||||
NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding);
|
||||
|
||||
@ -86,13 +90,11 @@ class nsXBLBinding: public nsIXBLBinding
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult);
|
||||
NS_IMETHOD WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData);
|
||||
|
||||
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);
|
||||
nsXBLBinding(nsIXBLPrototypeBinding* aProtoBinding);
|
||||
virtual ~nsXBLBinding();
|
||||
|
||||
NS_IMETHOD AddScriptEventListener(nsIContent* aElement, nsIAtom* aName, const nsString& aValue, REFNSIID aIID);
|
||||
@ -125,17 +127,12 @@ public:
|
||||
static nsIAtom* kOnGetAtom;
|
||||
static nsIAtom* kGetterAtom;
|
||||
static nsIAtom* kSetterAtom;
|
||||
static nsIAtom* kHTMLAtom;
|
||||
static nsIAtom* kValueAtom;
|
||||
static nsIAtom* kActionAtom;
|
||||
static nsIAtom* kNameAtom;
|
||||
static nsIAtom* kReadOnlyAtom;
|
||||
static nsIAtom* kAttachToAtom;
|
||||
static nsIAtom* kBindingAttachedAtom;
|
||||
static nsIAtom* kBindingDetachedAtom;
|
||||
static nsIAtom* kInheritStyleAtom;
|
||||
|
||||
static nsIXBLService* gXBLService;
|
||||
|
||||
// Used to easily obtain the correct IID for an event.
|
||||
struct EventHandlerMapEntry {
|
||||
@ -148,8 +145,6 @@ public:
|
||||
|
||||
static PRBool IsSupportedHandler(const nsIID* aIID);
|
||||
|
||||
static nsFixedSizeAllocator kPool;
|
||||
|
||||
static void GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound);
|
||||
|
||||
// Internal member functions
|
||||
@ -159,21 +154,11 @@ protected:
|
||||
void** aScriptObject, void** aClassObject);
|
||||
|
||||
void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult);
|
||||
void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult);
|
||||
void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList);
|
||||
void BuildInsertionTable();
|
||||
void GetNestedChildren();
|
||||
PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList);
|
||||
|
||||
NS_IMETHOD ConstructAttributeTable(nsIContent* aElement);
|
||||
|
||||
|
||||
// MEMBER VARIABLES
|
||||
protected:
|
||||
nsCString mDocURI;
|
||||
nsCString mID;
|
||||
|
||||
nsCOMPtr<nsIContent> mBinding; // Strong. As long as we're around, the binding can't go away.
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> mPrototypeBinding; // Strong. As long as we're around, the binding can't go away.
|
||||
nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
|
||||
nsCOMPtr<nsIXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.
|
||||
|
||||
@ -183,10 +168,5 @@ protected:
|
||||
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
|
||||
|
||||
PRPackedBool mIsStyleBinding;
|
||||
PRPackedBool mAllowScripts;
|
||||
PRPackedBool mInheritStyle;
|
||||
PRPackedBool mMarkedForDeath;
|
||||
|
||||
nsSupportsHashtable* mAttributeTable; // A table for attribute entries.
|
||||
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points.
|
||||
};
|
||||
|
805
layout/xbl/src/nsXBLPrototypeBinding.cpp
Normal file
805
layout/xbl/src/nsXBLPrototypeBinding.cpp
Normal file
@ -0,0 +1,805 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIXBLDocumentInfo.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIDOMEventReceiver.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "plstr.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIXMLContent.h"
|
||||
#include "nsIXULContent.h"
|
||||
#include "nsIXMLContentSink.h"
|
||||
#include "nsLayoutCID.h"
|
||||
#include "nsXMLDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMText.h"
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsINameSpace.h"
|
||||
#include "nsXBLService.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
|
||||
// Helper Classes =====================================================================
|
||||
|
||||
// nsIXBLAttributeEntry and helpers. This class is used to efficiently handle
|
||||
// attribute changes in anonymous content.
|
||||
|
||||
// {A2892B81-CED9-11d3-97FB-00400553EEF0}
|
||||
#define NS_IXBLATTR_IID \
|
||||
{ 0xa2892b81, 0xced9, 0x11d3, { 0x97, 0xfb, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } }
|
||||
|
||||
class nsIXBLAttributeEntry : public nsISupports {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IXBLATTR_IID; return iid; }
|
||||
|
||||
NS_IMETHOD GetSrcAttribute(nsIAtom** aResult) = 0;
|
||||
NS_IMETHOD GetDstAttribute(nsIAtom** aResult) = 0;
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) = 0;
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) = 0;
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) = 0;
|
||||
};
|
||||
|
||||
class nsXBLAttributeEntry : public nsIXBLAttributeEntry {
|
||||
public:
|
||||
NS_IMETHOD GetSrcAttribute(nsIAtom** aResult) { *aResult = mSrcAttribute; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
NS_IMETHOD GetDstAttribute(nsIAtom** aResult) { *aResult = mDstAttribute; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetElement(nsIContent** aResult) { *aResult = mElement; NS_IF_ADDREF(*aResult); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetNext(nsIXBLAttributeEntry** aResult) { NS_IF_ADDREF(*aResult = mNext); return NS_OK; }
|
||||
NS_IMETHOD SetNext(nsIXBLAttributeEntry* aEntry) { mNext = aEntry; return NS_OK; }
|
||||
|
||||
nsIContent* mElement;
|
||||
|
||||
nsCOMPtr<nsIAtom> mSrcAttribute;
|
||||
nsCOMPtr<nsIAtom> mDstAttribute;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> mNext;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, nsIContent* aContent) {
|
||||
NS_INIT_REFCNT(); mSrcAttribute = aSrcAtom; mDstAttribute = aDstAtom; mElement = aContent;
|
||||
};
|
||||
|
||||
virtual ~nsXBLAttributeEntry() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// Static initialization
|
||||
PRUint32 nsXBLPrototypeBinding::gRefCnt = 0;
|
||||
nsIAtom* nsXBLPrototypeBinding::kInheritStyleAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kHandlersAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kChildrenAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kIncludesAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kContentAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kInheritsAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kHTMLAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeBinding::kValueAtom = nsnull;
|
||||
|
||||
nsIXBLService* nsXBLPrototypeBinding::gXBLService = nsnull;
|
||||
nsFixedSizeAllocator nsXBLPrototypeBinding::kPool;
|
||||
|
||||
static const size_t kBucketSizes[] = {
|
||||
sizeof(nsXBLAttributeEntry)
|
||||
};
|
||||
|
||||
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
|
||||
static const PRInt32 kNumElements = 128;
|
||||
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
|
||||
|
||||
// Implementation /////////////////////////////////////////////////////////////////
|
||||
|
||||
// Implement our nsISupports methods
|
||||
NS_IMPL_ISUPPORTS1(nsXBLPrototypeBinding, nsIXBLPrototypeBinding)
|
||||
|
||||
// Constructors/Destructors
|
||||
nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsCString& aID, nsIContent* aElement,
|
||||
nsIXBLDocumentInfo* aInfo)
|
||||
: mID(aID),
|
||||
mInheritStyle(PR_TRUE),
|
||||
mHasBaseProto(PR_TRUE),
|
||||
mAttributeTable(nsnull),
|
||||
mInsertionPointTable(nsnull)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
mXBLDocInfoWeak = getter_AddRefs(NS_GetWeakReference(aInfo));
|
||||
|
||||
gRefCnt++;
|
||||
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
|
||||
|
||||
if (gRefCnt == 1) {
|
||||
kPool.Init("XBL Attribute Entries", kBucketSizes, kNumBuckets, kInitialSize);
|
||||
|
||||
kInheritStyleAtom = NS_NewAtom("inheritstyle");
|
||||
kHandlersAtom = NS_NewAtom("handlers");
|
||||
kChildrenAtom = NS_NewAtom("children");
|
||||
kContentAtom = NS_NewAtom("content");
|
||||
kIncludesAtom = NS_NewAtom("includes");
|
||||
kInheritsAtom = NS_NewAtom("inherits");
|
||||
kHTMLAtom = NS_NewAtom("html");
|
||||
kValueAtom = NS_NewAtom("value");
|
||||
|
||||
nsServiceManager::GetService("@mozilla.org/xbl;1",
|
||||
NS_GET_IID(nsIXBLService),
|
||||
(nsISupports**) &gXBLService);
|
||||
}
|
||||
|
||||
// These all use atoms, so we have to do these ops last to ensure
|
||||
// the atoms exist.
|
||||
SetBindingElement(aElement);
|
||||
|
||||
PRBool allowScripts;
|
||||
aInfo->GetScriptAccess(&allowScripts);
|
||||
if (allowScripts) {
|
||||
ConstructHandlers();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(content));
|
||||
if (content) {
|
||||
ConstructAttributeTable(content);
|
||||
ConstructInsertionTable(content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
|
||||
{
|
||||
delete mAttributeTable;
|
||||
delete mInsertionPointTable;
|
||||
gRefCnt--;
|
||||
if (gRefCnt == 0) {
|
||||
NS_RELEASE(kInheritStyleAtom);
|
||||
NS_RELEASE(kHandlersAtom);
|
||||
NS_RELEASE(kChildrenAtom);
|
||||
NS_RELEASE(kContentAtom);
|
||||
NS_RELEASE(kIncludesAtom);
|
||||
NS_RELEASE(kInheritsAtom);
|
||||
NS_RELEASE(kHTMLAtom);
|
||||
NS_RELEASE(kValueAtom);
|
||||
|
||||
nsServiceManager::ReleaseService("@mozilla.org/xbl;1", gXBLService);
|
||||
gXBLService = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
// nsIXBLPrototypeBinding Interface ////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBasePrototype(nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = mBaseBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetBasePrototype(nsIXBLPrototypeBinding* aBinding)
|
||||
{
|
||||
if (mBaseBinding.get() == aBinding)
|
||||
return NS_OK;
|
||||
|
||||
if (mBaseBinding) {
|
||||
NS_ERROR("Base XBL prototype binding is already defined!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mBaseBinding = aBinding; // Comptr handles rel/add
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBindingElement(nsIContent** aResult)
|
||||
{
|
||||
*aResult = mBinding;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
|
||||
{
|
||||
mBinding = aElement;
|
||||
nsAutoString inheritStyle;
|
||||
mBinding->GetAttribute(kNameSpaceID_None, kInheritStyleAtom, inheritStyle);
|
||||
if (inheritStyle == NS_LITERAL_STRING("false"))
|
||||
mInheritStyle = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBindingURI(nsCString& aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
GetXBLDocumentInfo(nsnull, getter_AddRefs(info));
|
||||
|
||||
info->GetDocumentURI(aResult);
|
||||
aResult += "#";
|
||||
aResult += mID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetDocURI(nsCString& aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
GetXBLDocumentInfo(nsnull, getter_AddRefs(info));
|
||||
|
||||
info->GetDocumentURI(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetID(nsCString& aResult)
|
||||
{
|
||||
aResult = mID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetAllowScripts(PRBool* aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
GetXBLDocumentInfo(nsnull, getter_AddRefs(info));
|
||||
return info->GetScriptAccess(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::InheritsStyle(PRBool* aResult)
|
||||
{
|
||||
*aResult = mInheritStyle;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetXBLDocumentInfo(nsIContent* aBoundElement, nsIXBLDocumentInfo** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info(do_QueryReferent(mXBLDocInfoWeak));
|
||||
if (info) {
|
||||
*aResult = info;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
else *aResult=nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::HasBasePrototype(PRBool* aResult)
|
||||
{
|
||||
*aResult = mHasBaseProto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetHasBasePrototype(PRBool aHasBase)
|
||||
{
|
||||
mHasBaseProto = aHasBase;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetPrototypeHandler(nsIXBLPrototypeHandler** aResult)
|
||||
{
|
||||
*aResult = mPrototypeHandler;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetPrototypeHandler(nsIXBLPrototypeHandler* aHandler)
|
||||
{
|
||||
mPrototypeHandler = aHandler;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag,
|
||||
nsIContent* aChangedElement, nsIContent* aAnonymousContent)
|
||||
{
|
||||
if (!mAttributeTable)
|
||||
return NS_OK;
|
||||
|
||||
nsISupportsKey key(aAttribute);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> xblAttr = do_QueryInterface(supports);
|
||||
if (!xblAttr)
|
||||
return NS_OK;
|
||||
|
||||
// Iterate over the elements in the array.
|
||||
nsCOMPtr<nsIContent> content;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(content));
|
||||
while (xblAttr) {
|
||||
nsCOMPtr<nsIContent> element;
|
||||
nsCOMPtr<nsIAtom> dstAttr;
|
||||
xblAttr->GetElement(getter_AddRefs(element));
|
||||
|
||||
nsCOMPtr<nsIContent> realElement;
|
||||
LocateInstance(content, aAnonymousContent, element, getter_AddRefs(realElement));
|
||||
|
||||
xblAttr->GetDstAttribute(getter_AddRefs(dstAttr));
|
||||
|
||||
if (aRemoveFlag)
|
||||
realElement->UnsetAttribute(aNameSpaceID, dstAttr, PR_TRUE);
|
||||
else {
|
||||
nsAutoString value;
|
||||
nsresult result = aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
|
||||
if (attrPresent)
|
||||
realElement->SetAttribute(aNameSpaceID, dstAttr, value, PR_TRUE);
|
||||
}
|
||||
|
||||
// See if we're the <html> tag in XUL, and see if value is being
|
||||
// set or unset on us.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
realElement->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == kHTMLAtom) && (dstAttr.get() == kValueAtom)) {
|
||||
// Flush out all our kids.
|
||||
PRInt32 childCount;
|
||||
realElement->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++)
|
||||
realElement->RemoveChildAt(0, PR_TRUE);
|
||||
|
||||
if (!aRemoveFlag) {
|
||||
// Construct a new text node and insert it.
|
||||
nsAutoString value;
|
||||
aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
|
||||
if (!value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aChangedElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(realElement));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = xblAttr;
|
||||
tmpAttr->GetNext(getter_AddRefs(xblAttr));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent* aChild, nsIContent** aResult)
|
||||
{
|
||||
if (mInsertionPointTable) {
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
aChild->GetTag(*getter_AddRefs(tag));
|
||||
nsISupportsKey key(tag);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
if (!content) {
|
||||
nsISupportsKey key2(kChildrenAtom);
|
||||
content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2)));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> realContent;
|
||||
nsCOMPtr<nsIContent> templContent;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
|
||||
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
|
||||
if (realContent)
|
||||
*aResult = realContent;
|
||||
else *aResult = aBoundElement;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
|
||||
nsIContent* aCopyRoot,
|
||||
nsIContent** aResult, PRBool* aMultipleInsertionPoints)
|
||||
{
|
||||
if (mInsertionPointTable) {
|
||||
if(mInsertionPointTable->Count() == 1) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
|
||||
mInsertionPointTable->Get(&key)));
|
||||
nsCOMPtr<nsIContent> realContent;
|
||||
nsCOMPtr<nsIContent> templContent;
|
||||
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
|
||||
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
|
||||
if (realContent)
|
||||
*aResult = realContent;
|
||||
else *aResult = aBoundElement;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
else
|
||||
*aMultipleInsertionPoints = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)
|
||||
{
|
||||
mBaseNameSpaceID = aNamespaceID;
|
||||
mBaseTag = aTag;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aResult)
|
||||
{
|
||||
if (mBaseTag) {
|
||||
*aResult = mBaseTag;
|
||||
NS_ADDREF(*aResult);
|
||||
*aNamespaceID = mBaseNameSpaceID;
|
||||
}
|
||||
else *aResult = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Internal helpers ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
PRInt32 childCount;
|
||||
mBinding->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
mBinding->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
*aResult = child;
|
||||
NS_ADDREF(*aResult);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::ConstructHandlers()
|
||||
{
|
||||
// See if this binding has a handler elt.
|
||||
nsCOMPtr<nsIContent> handlers;
|
||||
GetImmediateChild(kHandlersAtom, getter_AddRefs(handlers));
|
||||
if (handlers) {
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> firstHandler;
|
||||
nsXBLService::BuildHandlerChain(handlers, getter_AddRefs(firstHandler));
|
||||
SetPrototypeHandler(firstHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::LocateInstance(nsIContent* aTemplRoot, nsIContent* aCopyRoot,
|
||||
nsIContent* aTemplChild, nsIContent** aCopyResult)
|
||||
{
|
||||
// XXX We will get in trouble if the binding instantiation deviates from the template
|
||||
// in the prototype.
|
||||
if (aTemplChild == aTemplRoot) {
|
||||
*aCopyResult = nsnull;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> templParent;
|
||||
nsCOMPtr<nsIContent> copyParent;
|
||||
|
||||
aTemplChild->GetParent(*getter_AddRefs(templParent));
|
||||
|
||||
if (templParent.get() == aTemplRoot)
|
||||
copyParent = aCopyRoot;
|
||||
else
|
||||
LocateInstance(aTemplRoot, aCopyRoot, templParent, getter_AddRefs(copyParent));
|
||||
|
||||
PRInt32 index;
|
||||
templParent->IndexOf(aTemplChild, index);
|
||||
copyParent->ChildAt(index, *aCopyResult); // Addref happens here.
|
||||
}
|
||||
|
||||
struct nsXBLAttrChangeData
|
||||
{
|
||||
nsXBLPrototypeBinding* mProto;
|
||||
nsIContent* mBoundElement;
|
||||
nsIContent* mContent;
|
||||
|
||||
nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
|
||||
nsIContent* aElt, nsIContent* aContent)
|
||||
:mProto(aProto), mBoundElement(aElt), mContent(aContent) {};
|
||||
};
|
||||
|
||||
PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
|
||||
{
|
||||
// XXX How to deal with NAMESPACES!!!?
|
||||
nsIXBLAttributeEntry* entry = (nsIXBLAttributeEntry*)aData;
|
||||
nsXBLAttrChangeData* changeData = (nsXBLAttrChangeData*)aClosure;
|
||||
|
||||
nsCOMPtr<nsIAtom> src;
|
||||
entry->GetSrcAttribute(getter_AddRefs(src));
|
||||
|
||||
nsAutoString value;
|
||||
nsresult result = changeData->mBoundElement->GetAttribute(kNameSpaceID_None, src, value);
|
||||
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
|
||||
result == NS_CONTENT_ATTR_HAS_VALUE);
|
||||
if (attrPresent) {
|
||||
nsCOMPtr<nsIContent> content;
|
||||
changeData->mProto->GetImmediateChild(nsXBLPrototypeBinding::kContentAtom, getter_AddRefs(content));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> curr = entry;
|
||||
while (curr) {
|
||||
nsCOMPtr<nsIAtom> dst;
|
||||
nsCOMPtr<nsIContent> element;
|
||||
curr->GetDstAttribute(getter_AddRefs(dst));
|
||||
curr->GetElement(getter_AddRefs(element));
|
||||
|
||||
nsCOMPtr<nsIContent> realElement;
|
||||
changeData->mProto->LocateInstance(content, changeData->mContent, element, getter_AddRefs(realElement));
|
||||
if (realElement) {
|
||||
realElement->SetAttribute(kNameSpaceID_None, dst, value, PR_FALSE);
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
realElement->GetTag(*getter_AddRefs(tag));
|
||||
if ((tag.get() == nsXBLPrototypeBinding::kHTMLAtom) && (dst.get() == nsXBLPrototypeBinding::kValueAtom) && !value.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMText> textNode;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
changeData->mBoundElement->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
|
||||
domDoc->CreateTextNode(value, getter_AddRefs(textNode));
|
||||
nsCOMPtr<nsIDOMNode> dummy;
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(realElement));
|
||||
domElement->AppendChild(textNode, getter_AddRefs(dummy));
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> next = curr;
|
||||
curr->GetNext(getter_AddRefs(next));
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
|
||||
{
|
||||
if (mAttributeTable) {
|
||||
nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
|
||||
mAttributeTable->Enumerate(SetAttrs, (void*)&data);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
|
||||
{
|
||||
nsAutoString inherits;
|
||||
aElement->GetAttribute(kNameSpaceID_None, kInheritsAtom, inherits);
|
||||
if (!inherits.IsEmpty()) {
|
||||
if (!mAttributeTable) {
|
||||
mAttributeTable = new nsSupportsHashtable(4);
|
||||
}
|
||||
|
||||
// The user specified at least one attribute.
|
||||
char* str = inherits.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichars
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, ", ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this attribute.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
nsCOMPtr<nsIAtom> attribute;
|
||||
|
||||
// Figure out if this token contains a :.
|
||||
nsAutoString attrTok; attrTok.AssignWithConversion(token);
|
||||
PRInt32 index = attrTok.Find("=", PR_TRUE);
|
||||
if (index != -1) {
|
||||
// This attribute maps to something different.
|
||||
nsAutoString left, right;
|
||||
attrTok.Left(left, index);
|
||||
attrTok.Right(right, attrTok.Length()-index-1);
|
||||
|
||||
atom = getter_AddRefs(NS_NewAtom(right.GetUnicode()));
|
||||
attribute = getter_AddRefs(NS_NewAtom(left.GetUnicode()));
|
||||
}
|
||||
else {
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
attribute = atom;
|
||||
}
|
||||
|
||||
// Create an XBL attribute entry.
|
||||
nsXBLAttributeEntry* xblAttr = new (kPool) nsXBLAttributeEntry(atom, attribute, aElement);
|
||||
|
||||
// Now we should see if some element within our anonymous
|
||||
// content is already observing this attribute.
|
||||
nsISupportsKey key(atom);
|
||||
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
|
||||
mAttributeTable->Get(&key)));
|
||||
|
||||
nsCOMPtr<nsIXBLAttributeEntry> entry = do_QueryInterface(supports);
|
||||
if (!entry) {
|
||||
// Put it in the table.
|
||||
mAttributeTable->Put(&key, xblAttr);
|
||||
} else {
|
||||
nsCOMPtr<nsIXBLAttributeEntry> attr = entry;
|
||||
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = entry;
|
||||
do {
|
||||
attr = tmpAttr;
|
||||
attr->GetNext(getter_AddRefs(tmpAttr));
|
||||
} while (tmpAttr);
|
||||
attr->SetNext(xblAttr);
|
||||
}
|
||||
|
||||
// Now remove the inherits attribute from the element so that it doesn't
|
||||
// show up on clones of the element. It is used
|
||||
// by the template only, and we don't need it anymore.
|
||||
aElement->UnsetAttribute(kNameSpaceID_None, kInheritsAtom, PR_FALSE);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
|
||||
// Recur into our children.
|
||||
PRInt32 childCount;
|
||||
aElement->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aElement->ChildAt(i, *getter_AddRefs(child));
|
||||
ConstructAttributeTable(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
|
||||
{
|
||||
nsCOMPtr<nsISupportsArray> childrenElements;
|
||||
GetNestedChildren(kChildrenAtom, aContent, getter_AddRefs(childrenElements));
|
||||
|
||||
if (!childrenElements)
|
||||
return;
|
||||
|
||||
mInsertionPointTable = new nsSupportsHashtable;
|
||||
|
||||
PRUint32 count;
|
||||
childrenElements->Count(&count);
|
||||
PRUint32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
nsAutoString includes;
|
||||
child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
||||
if (includes.IsEmpty()) {
|
||||
nsISupportsKey key(kChildrenAtom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
}
|
||||
else {
|
||||
// The user specified at least one attribute.
|
||||
char* str = includes.ToNewCString();
|
||||
char* newStr;
|
||||
// XXX We should use a strtok function that tokenizes PRUnichar's
|
||||
// so that we don't have to convert from Unicode to ASCII and then back
|
||||
|
||||
char* token = nsCRT::strtok( str, "| ", &newStr );
|
||||
while( token != NULL ) {
|
||||
// Build an atom out of this string.
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
|
||||
nsAutoString tok; tok.AssignWithConversion(token);
|
||||
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
|
||||
|
||||
nsISupportsKey key(atom);
|
||||
mInsertionPointTable->Put(&key, parent);
|
||||
|
||||
token = nsCRT::strtok( newStr, ", ", &newStr );
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove the <children> elements.
|
||||
for (i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childrenElements->GetElementAt(i, getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
|
||||
if (child) {
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
child->GetParent(*getter_AddRefs(parent));
|
||||
PRInt32 index;
|
||||
parent->IndexOf(child, index);
|
||||
parent->RemoveChildAt(index, PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList)
|
||||
{
|
||||
PRInt32 childCount;
|
||||
aContent->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aContent->ChildAt(i, *getter_AddRefs(child));
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
child->GetTag(*getter_AddRefs(tag));
|
||||
if (aTag == tag.get()) {
|
||||
if (!*aList)
|
||||
NS_NewISupportsArray(aList); // Addref happens here.
|
||||
(*aList)->AppendElement(child);
|
||||
}
|
||||
else
|
||||
GetNestedChildren(aTag, child, aList);
|
||||
}
|
||||
}
|
||||
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
NS_NewXBLPrototypeBinding(const nsCString& aRef, nsIContent* aElement,
|
||||
nsIXBLDocumentInfo* aInfo, nsIXBLPrototypeBinding** aResult)
|
||||
{
|
||||
*aResult = new nsXBLPrototypeBinding(aRef, aElement, aInfo);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
135
layout/xbl/src/nsXBLPrototypeBinding.h
Normal file
135
layout/xbl/src/nsXBLPrototypeBinding.h
Normal file
@ -0,0 +1,135 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIAtom;
|
||||
class nsIDocument;
|
||||
class nsIScriptContext;
|
||||
class nsISupportsArray;
|
||||
class nsSupportsHashtable;
|
||||
class nsIXBLService;
|
||||
class nsFixedSizeAllocator;
|
||||
|
||||
// *********************************************************************/
|
||||
// The XBLPrototypeBinding class
|
||||
|
||||
class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIXBLPrototypeBinding
|
||||
NS_IMETHOD GetBindingElement(nsIContent** aResult);
|
||||
NS_IMETHOD SetBindingElement(nsIContent* aElement);
|
||||
|
||||
NS_IMETHOD GetBindingURI(nsCString& aResult);
|
||||
NS_IMETHOD GetDocURI(nsCString& aResult);
|
||||
NS_IMETHOD GetID(nsCString& aResult);
|
||||
|
||||
NS_IMETHOD GetAllowScripts(PRBool* aResult);
|
||||
|
||||
NS_IMETHOD InheritsStyle(PRBool* aResult);
|
||||
|
||||
NS_IMETHOD GetPrototypeHandler(nsIXBLPrototypeHandler** aHandler);
|
||||
NS_IMETHOD SetPrototypeHandler(nsIXBLPrototypeHandler* aHandler);
|
||||
|
||||
NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag,
|
||||
nsIContent* aChangedElement, nsIContent* aAnonymousContent);
|
||||
|
||||
NS_IMETHOD SetBasePrototype(nsIXBLPrototypeBinding* aBinding);
|
||||
NS_IMETHOD GetBasePrototype(nsIXBLPrototypeBinding** aResult);
|
||||
|
||||
NS_IMETHOD GetXBLDocumentInfo(nsIContent* aBoundElement, nsIXBLDocumentInfo** aResult);
|
||||
|
||||
NS_IMETHOD HasBasePrototype(PRBool* aResult);
|
||||
NS_IMETHOD SetHasBasePrototype(PRBool aHasBase);
|
||||
|
||||
NS_IMETHOD SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);
|
||||
|
||||
NS_IMETHOD HasInsertionPoints(PRBool* aResult) { *aResult = (mInsertionPointTable != nsnull); return NS_OK; };
|
||||
|
||||
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent* aChild, nsIContent** aResult);
|
||||
|
||||
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
|
||||
nsIContent** aResult, PRBool* aMultiple);
|
||||
|
||||
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag);
|
||||
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
|
||||
|
||||
public:
|
||||
nsXBLPrototypeBinding(const nsCString& aRef, nsIContent* aElement,
|
||||
nsIXBLDocumentInfo* aInfo);
|
||||
virtual ~nsXBLPrototypeBinding();
|
||||
|
||||
// Static members
|
||||
static PRUint32 gRefCnt;
|
||||
static nsIXBLService* gXBLService;
|
||||
static nsIAtom* kInheritStyleAtom;
|
||||
static nsIAtom* kHandlersAtom;
|
||||
static nsIAtom* kChildrenAtom;
|
||||
static nsIAtom* kIncludesAtom;
|
||||
static nsIAtom* kContentAtom;
|
||||
static nsIAtom* kInheritsAtom;
|
||||
static nsIAtom* kHTMLAtom;
|
||||
static nsIAtom* kValueAtom;
|
||||
|
||||
static nsFixedSizeAllocator kPool;
|
||||
|
||||
// Internal member functions
|
||||
public:
|
||||
void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult);
|
||||
void LocateInstance(nsIContent* aTemplRoot, nsIContent* aCopyRoot,
|
||||
nsIContent* aTemplChild, nsIContent** aCopyResult);
|
||||
|
||||
protected:
|
||||
void ConstructHandlers();
|
||||
void ConstructAttributeTable(nsIContent* aElement);
|
||||
void ConstructInsertionTable(nsIContent* aElement);
|
||||
void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList);
|
||||
|
||||
// MEMBER VARIABLES
|
||||
protected:
|
||||
nsCString mID;
|
||||
|
||||
nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> mBaseBinding; // Strong. We own the base binding in our explicit inheritance chain.
|
||||
PRPackedBool mInheritStyle;
|
||||
PRPackedBool mHasBaseProto;
|
||||
|
||||
nsWeakPtr mXBLDocInfoWeak; // A pointer back to our doc info. Weak, since it owns us.
|
||||
|
||||
nsSupportsHashtable* mAttributeTable; // A table for attribute entries. Used to efficiently
|
||||
// handle attribute changes.
|
||||
|
||||
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points for placing explicit content
|
||||
// underneath anonymous content.
|
||||
|
||||
PRInt32 mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will
|
||||
nsCOMPtr<nsIAtom> mBaseTag; // be stored in here.
|
||||
};
|
@ -54,6 +54,7 @@
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "nsIXBLBinding.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIXBLDocumentInfo.h"
|
||||
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
@ -343,9 +344,6 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent)
|
||||
nsCOMPtr<nsIXBLDocumentInfo> info;
|
||||
NS_NewXBLDocumentInfo(mBindingDocument, getter_AddRefs(info));
|
||||
|
||||
// Construct our prototype handlers.
|
||||
nsXBLService::ConstructPrototypeHandlers(info);
|
||||
|
||||
// If the doc is a chrome URI, then we put it into the XUL cache.
|
||||
PRBool cached = PR_FALSE;
|
||||
if (IsChromeURI(uri) && gXULUtils->UseXULCache()) {
|
||||
@ -486,7 +484,6 @@ PRUint32 nsXBLService::gClassLRUListLength = 0;
|
||||
PRUint32 nsXBLService::gClassLRUListQuota = 64;
|
||||
|
||||
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
|
||||
nsIAtom* nsXBLService::kHandlersAtom = nsnull;
|
||||
nsIAtom* nsXBLService::kScrollbarAtom = nsnull;
|
||||
nsIAtom* nsXBLService::kInputAtom = nsnull;
|
||||
|
||||
@ -526,7 +523,6 @@ nsXBLService::nsXBLService(void)
|
||||
|
||||
// Create our atoms
|
||||
kExtendsAtom = NS_NewAtom("extends");
|
||||
kHandlersAtom = NS_NewAtom("handlers");
|
||||
kScrollbarAtom = NS_NewAtom("scrollbar");
|
||||
kInputAtom = NS_NewAtom("input");
|
||||
|
||||
@ -558,7 +554,6 @@ nsXBLService::~nsXBLService(void)
|
||||
|
||||
// Release our atoms
|
||||
NS_RELEASE(kExtendsAtom);
|
||||
NS_RELEASE(kHandlersAtom);
|
||||
NS_RELEASE(kScrollbarAtom);
|
||||
NS_RELEASE(kInputAtom);
|
||||
|
||||
@ -915,77 +910,114 @@ NS_IMETHODIMP nsXBLService::GetBindingInternal(nsIContent* aBoundElement,
|
||||
PRBool allowScripts;
|
||||
docInfo->GetScriptAccess(&allowScripts);
|
||||
|
||||
// We have a doc. Obtain our specific binding element.
|
||||
// Walk the children looking for the binding that matches the ref
|
||||
// specified in the URL.
|
||||
nsCOMPtr<nsIContent> root = getter_AddRefs(doc->GetRootContent());
|
||||
if (!root)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> protoBinding;
|
||||
docInfo->GetPrototypeBinding(ref, getter_AddRefs(protoBinding));
|
||||
nsCOMPtr<nsIContent> child;
|
||||
if (!protoBinding) {
|
||||
// We have a doc. Obtain our specific binding element.
|
||||
// Walk the children looking for the binding that matches the ref
|
||||
// specified in the URL.
|
||||
nsCOMPtr<nsIContent> root = getter_AddRefs(doc->GetRootContent());
|
||||
if (!root)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString bindingName; bindingName.AssignWithConversion( NS_STATIC_CAST(const char*, ref) );
|
||||
nsAutoString bindingName; bindingName.AssignWithConversion( NS_STATIC_CAST(const char*, ref) );
|
||||
|
||||
PRInt32 count;
|
||||
root->ChildCount(count);
|
||||
PRInt32 count;
|
||||
root->ChildCount(count);
|
||||
|
||||
for (PRInt32 i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
root->ChildAt(i, *getter_AddRefs(child));
|
||||
for (PRInt32 i = 0; i < count; i++) {
|
||||
root->ChildAt(i, *getter_AddRefs(child));
|
||||
|
||||
nsAutoString value;
|
||||
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, value);
|
||||
nsAutoString value;
|
||||
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, value);
|
||||
|
||||
// If no ref is specified just use this.
|
||||
if ((bindingName.IsEmpty()) || (bindingName == value)) {
|
||||
// Check for the presence of an extends attribute
|
||||
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.
|
||||
// If no ref is specified just use this.
|
||||
if ((bindingName.IsEmpty()) || (bindingName == value)) {
|
||||
// Construct a prototype binding.
|
||||
NS_NewXBLPrototypeBinding(ref, child, docInfo, getter_AddRefs(protoBinding));
|
||||
docInfo->SetPrototypeBinding(ref, protoBinding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
protoBinding->GetBindingElement(getter_AddRefs(child));
|
||||
|
||||
// If our prototype already has a base, then don't check for an "extends" attribute.
|
||||
nsCOMPtr<nsIXBLBinding> baseBinding;
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> baseProto;
|
||||
PRBool hasBase;
|
||||
protoBinding->HasBasePrototype(&hasBase);
|
||||
protoBinding->GetBasePrototype(getter_AddRefs(baseProto));
|
||||
if (baseProto) {
|
||||
nsCAutoString url;
|
||||
baseProto->GetBindingURI(url);
|
||||
if (NS_FAILED(GetBindingInternal(aBoundElement, url, aPeekOnly, aIsReady, getter_AddRefs(baseBinding))))
|
||||
return NS_ERROR_FAILURE; // We aren't ready yet.
|
||||
if (!aPeekOnly) {
|
||||
// Make sure to set the base prototype.
|
||||
baseBinding->GetPrototypeBinding(getter_AddRefs(baseProto));
|
||||
protoBinding->SetBasePrototype(baseProto);
|
||||
}
|
||||
}
|
||||
else if (hasBase) {
|
||||
// Check for the presence of an extends attribute
|
||||
nsAutoString extends;
|
||||
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
|
||||
nsAutoString value(extends);
|
||||
if (extends.IsEmpty())
|
||||
protoBinding->SetHasBasePrototype(PR_FALSE);
|
||||
else {
|
||||
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 extend some widget/frame. We don't really have a base binding.
|
||||
protoBinding->SetHasBasePrototype(PR_FALSE);
|
||||
PRInt32 nameSpaceID;
|
||||
tagSpace->GetNameSpaceID(nameSpaceID);
|
||||
nsCOMPtr<nsIAtom> tagName = getter_AddRefs(NS_NewAtom(extends));
|
||||
protoBinding->SetBaseTag(nameSpaceID, tagName);
|
||||
}
|
||||
else {
|
||||
// We have a base class binding. Load it right now.
|
||||
nsCAutoString urlCString; urlCString.AssignWithConversion(value);
|
||||
if (NS_FAILED(GetBindingInternal(aBoundElement, urlCString, aPeekOnly, aIsReady, getter_AddRefs(baseBinding))))
|
||||
return NS_ERROR_FAILURE; // Binding not yet ready or an error occurred.
|
||||
if (!aPeekOnly) {
|
||||
// Make sure to set the base prototype.
|
||||
baseBinding->GetPrototypeBinding(getter_AddRefs(baseProto));
|
||||
protoBinding->SetBasePrototype(baseProto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
||||
*aIsReady = PR_TRUE;
|
||||
if (!aPeekOnly) {
|
||||
// Make a new binding
|
||||
NS_NewXBLBinding(protoBinding, aResult);
|
||||
if (baseBinding)
|
||||
(*aResult)->SetBaseBinding(baseBinding);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1058,9 +1090,6 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement, nsIDocument* aB
|
||||
if (document) {
|
||||
NS_NewXBLDocumentInfo(document, getter_AddRefs(info));
|
||||
|
||||
// Construct our prototype handlers.
|
||||
ConstructPrototypeHandlers(info);
|
||||
|
||||
// If the doc is a chrome URI, then we put it into the XUL cache.
|
||||
PRBool cached = PR_FALSE;
|
||||
if (IsChromeURI(uri) && gXULUtils->UseXULCache()) {
|
||||
@ -1288,40 +1317,6 @@ nsXBLService::BuildHandlerChain(nsIContent* aContent, nsIXBLPrototypeHandler** a
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXBLService::ConstructPrototypeHandlers(nsIXBLDocumentInfo* aInfo)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aInfo->GetDocument(getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIContent> bindings = getter_AddRefs(doc->GetRootContent());
|
||||
PRInt32 childCount;
|
||||
bindings->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> binding;
|
||||
bindings->ChildAt(i, *getter_AddRefs(binding));
|
||||
|
||||
// See if this binding has a handler elt.
|
||||
nsCOMPtr<nsIContent> handlers;
|
||||
GetImmediateChild(kHandlersAtom, binding, getter_AddRefs(handlers));
|
||||
if (handlers) {
|
||||
nsCOMPtr<nsIXBLPrototypeHandler> firstHandler;
|
||||
nsXBLService::BuildHandlerChain(handlers, getter_AddRefs(firstHandler));
|
||||
|
||||
if (firstHandler) {
|
||||
nsAutoString ref;
|
||||
binding->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, ref);
|
||||
|
||||
nsCAutoString cref;
|
||||
cref.AssignWithConversion(ref);
|
||||
|
||||
aInfo->SetPrototypeHandler(cref, firstHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
|
@ -103,7 +103,6 @@ public:
|
||||
// This method walks a binding document and removes any text nodes
|
||||
// that contain only whitespace.
|
||||
static nsresult StripWhitespaceNodes(nsIContent* aContent);
|
||||
static nsresult ConstructPrototypeHandlers(nsIXBLDocumentInfo* aInfo);
|
||||
static nsresult BuildHandlerChain(nsIContent* aContent, nsIXBLPrototypeHandler** aResult);
|
||||
|
||||
// MEMBER VARIABLES
|
||||
@ -126,7 +125,6 @@ public:
|
||||
|
||||
// XBL Atoms
|
||||
static nsIAtom* kExtendsAtom;
|
||||
static nsIAtom* kHandlersAtom;
|
||||
static nsIAtom* kScrollbarAtom;
|
||||
static nsIAtom* kInputAtom;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIXBLPrototypeHandler.h"
|
||||
#include "nsXBLWindowKeyHandler.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
@ -41,6 +42,9 @@
|
||||
#include "nsIDOMXULCommandDispatcher.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
|
||||
PRUint32 nsXBLWindowKeyHandler::gRefCnt = 0;
|
||||
nsIAtom* nsXBLWindowKeyHandler::kKeyDownAtom = nsnull;
|
||||
@ -115,6 +119,33 @@ nsXBLWindowKeyHandler::IsEditor()
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
static void GetHandlers(nsIXBLDocumentInfo* aInfo, const nsCString& aDocURI,
|
||||
const nsCString& aRef, nsIXBLPrototypeHandler** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> binding;
|
||||
aInfo->GetPrototypeBinding(aRef, getter_AddRefs(binding));
|
||||
if (!binding) {
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aInfo->GetDocument(getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIContent> root = getter_AddRefs(doc->GetRootContent());
|
||||
PRInt32 childCount;
|
||||
root->ChildCount(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; i++) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
root->ChildAt(i, *getter_AddRefs(child));
|
||||
nsAutoString id;
|
||||
child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, id);
|
||||
if (id.EqualsWithConversion(aRef)) {
|
||||
NS_NewXBLPrototypeBinding(aRef, child, aInfo, getter_AddRefs(binding));
|
||||
aInfo->SetPrototypeBinding(aRef, binding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding->GetPrototypeHandler(aResult); // Addref happens here.
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLWindowKeyHandler::EnsureHandlers()
|
||||
{
|
||||
@ -158,16 +189,24 @@ nsXBLWindowKeyHandler::EnsureHandlers()
|
||||
|
||||
// Now determine which handlers we should be using.
|
||||
if (IsEditor()) {
|
||||
mXBLSpecialDocInfo->mPlatformHTMLBindings->GetPrototypeHandler(nsCAutoString("editor"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
mXBLSpecialDocInfo->mHTMLBindings->GetPrototypeHandler(nsCAutoString("editorBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mPlatformHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/platformHTMLBindings.xml"),
|
||||
nsCAutoString("editor"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/htmlBindings.xml"),
|
||||
nsCAutoString("editorBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
}
|
||||
else {
|
||||
mXBLSpecialDocInfo->mPlatformHTMLBindings->GetPrototypeHandler(nsCAutoString("browser"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
mXBLSpecialDocInfo->mHTMLBindings->GetPrototypeHandler(nsCAutoString("browserBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mPlatformHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/platformHTMLBindings.xml"),
|
||||
nsCAutoString("browser"),
|
||||
getter_AddRefs(mPlatformHandler));
|
||||
GetHandlers(mXBLSpecialDocInfo->mHTMLBindings,
|
||||
nsCAutoString("chrome://global/content/htmlBindings.xml"),
|
||||
nsCAutoString("browserBase"),
|
||||
getter_AddRefs(mHandler));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user