Fix for 53417. r=brendan, a=brendan

This commit is contained in:
hyatt%netscape.com 2000-09-27 20:23:49 +00:00
parent 8e3f2ce2da
commit bc40a1821f
36 changed files with 2700 additions and 1430 deletions

View File

@ -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)

View File

@ -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)

View File

@ -33,6 +33,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \
$(NULL)

View File

@ -2,6 +2,6 @@ nsIBindingManager.h
nsIXBLBinding.h
nsIXBLBindingAttachedHandler.h
nsIXBLDocumentInfo.h
nsIXBLPrototypeBinding.h
nsIXBLPrototypeHandler.h
nsIXBLService.h

View File

@ -26,6 +26,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \
$(NULL)

View File

@ -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__

View File

@ -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

View 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__

View File

@ -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 \

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.
};

View 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;
}

View 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.
};

View File

@ -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

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -33,6 +33,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \
$(NULL)

View File

@ -2,6 +2,6 @@ nsIBindingManager.h
nsIXBLBinding.h
nsIXBLBindingAttachedHandler.h
nsIXBLDocumentInfo.h
nsIXBLPrototypeBinding.h
nsIXBLPrototypeHandler.h
nsIXBLService.h

View File

@ -26,6 +26,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \
$(NULL)

View File

@ -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__

View File

@ -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

View 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__

View File

@ -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 \

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.
};

View 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;
}

View 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.
};

View File

@ -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

View File

@ -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;

View File

@ -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));
}
}