Big XBL landing. Fixes numerous XBL bugs. a=ben

This commit is contained in:
hyatt%netscape.com 2000-12-07 10:11:21 +00:00
parent 021da9b1d3
commit a809cb4755
20 changed files with 780 additions and 74 deletions

View File

@ -41,6 +41,7 @@ class nsIXBLBindingAttachedHandler;
class nsIXBLDocumentInfo;
class nsIAtom;
class nsIStreamListener;
class nsIXPConnectWrappedJS;
// {55D70FE0-C8E5-11d3-97FB-00400553EEF0}
#define NS_IBINDING_MANAGER_IID \
@ -54,6 +55,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult) = 0;
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding) = 0;
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult) = 0;
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult) = 0;
/**
* Notify the binding manager that an element
* has been moved from one document to another,
@ -100,6 +104,10 @@ public:
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult) = 0;
NS_IMETHOD FlushChromeBindings() = 0;
NS_IMETHOD GetBindingImplementation(nsIContent* aContent, void* aScriptObject, REFNSIID aIID, void** aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(nsIContent* aContent, PRBool* aResult) = 0;
};
#endif // nsIBinding_Manager_h__

View File

@ -98,6 +98,10 @@ public:
NS_IMETHOD MarkForDeath()=0;
NS_IMETHOD MarkedForDeath(PRBool* aResult)=0;
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult)=0;
};
extern nsresult

View File

@ -84,6 +84,10 @@ public:
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag)=0;
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)=0;
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult)=0;
};
extern nsresult

View File

@ -62,6 +62,8 @@
#include "nsIXBLPrototypeBinding.h"
#include "nsIWeakReference.h"
#include "nsIXPConnect.h"
// Static IIDs/CIDs. Try to minimize these.
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
@ -203,6 +205,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult);
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding);
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult);
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
NS_IMETHOD ChangeDocumentFor(nsIContent* aContent, nsIDocument* aOldDocument,
nsIDocument* aNewDocument);
@ -234,12 +239,16 @@ public:
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD FlushChromeBindings();
NS_IMETHOD GetBindingImplementation(nsIContent* aContent, void* aScriptObject, REFNSIID aIID, void** aResult);
// nsIStyleRuleSupplier
NS_IMETHOD UseDocumentRules(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD WalkRules(nsIStyleSet* aStyleSet,
nsISupportsArrayEnumFunc aFunc, void* aData,
nsIContent* aContent);
NS_IMETHOD ShouldBuildChildFrames(nsIContent* aContent, PRBool* aResult);
protected:
void GetEnclosingScope(nsIContent* aContent, nsIContent** aParent);
void GetOutermostStyleScope(nsIContent* aContent, nsIContent** aParent);
@ -250,6 +259,7 @@ protected:
// MEMBER VARIABLES
protected:
nsSupportsHashtable* mBindingTable;
nsSupportsHashtable* mWrapperTable;
nsSupportsHashtable* mDocumentTable;
nsSupportsHashtable* mLoadingDocTable;
@ -269,7 +279,7 @@ nsBindingManager::nsBindingManager(void)
NS_INIT_REFCNT();
mBindingTable = nsnull;
mWrapperTable = nsnull;
mDocumentTable = nsnull;
mLoadingDocTable = nsnull;
@ -279,6 +289,7 @@ nsBindingManager::nsBindingManager(void)
nsBindingManager::~nsBindingManager(void)
{
delete mBindingTable;
delete mWrapperTable;
delete mDocumentTable;
delete mLoadingDocTable;
}
@ -312,9 +323,43 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding )
if (aBinding) {
mBindingTable->Put(&key, aBinding);
}
else
else {
mBindingTable->Remove(&key);
// The death of the bindings means the death of the JS wrapper.
SetWrappedJS(aContent, nsnull);
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult)
{
if (mWrapperTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIXPConnectWrappedJS*, mWrapperTable->Get(&key));
}
else {
*aResult = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aWrappedJS)
{
if (!mWrapperTable)
mWrapperTable = new nsSupportsHashtable;
nsISupportsKey key(aContent);
if (aWrappedJS) {
mWrapperTable->Put(&key, aWrappedJS);
}
else
mWrapperTable->Remove(&key);
return NS_OK;
}
@ -669,6 +714,69 @@ nsBindingManager::FlushChromeBindings()
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetBindingImplementation(nsIContent* aContent, void* aScriptObject, REFNSIID aIID, void** aResult)
{
*aResult = nsnull;
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aContent, getter_AddRefs(binding));
if (binding) {
PRBool supportsInterface;
binding->ImplementsInterface(aIID, &supportsInterface);
if (supportsInterface) {
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS;
GetWrappedJS(aContent, getter_AddRefs(wrappedJS));
if (wrappedJS)
return wrappedJS->AggregatedQueryInterface(aIID, aResult);
// We have never made a wrapper for this implementation.
// Create an XPC wrapper for the script object and hand it back.
JSObject* jsobj = (JSObject*)aScriptObject;
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
if (!doc)
return NS_NOINTERFACE;
nsCOMPtr<nsIScriptGlobalObject> global;
doc->GetScriptGlobalObject(getter_AddRefs(global));
if (!global)
return NS_NOINTERFACE;
nsCOMPtr<nsIScriptContext> context;
global->GetContext(getter_AddRefs(context));
if (!context)
return NS_NOINTERFACE;
JSContext* jscontext = (JSContext*)context->GetNativeContext();
if (!jscontext)
return NS_NOINTERFACE;
nsCOMPtr<nsIXPConnect> xpConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
if (!xpConnect)
return NS_NOINTERFACE;
nsISupports* nativeThis = (nsISupports*)JS_GetPrivate(jscontext, jsobj);
nsresult rv = xpConnect->WrapJSAggregatedToNative(nativeThis, jscontext, jsobj, aIID, aResult);
if (NS_FAILED(rv))
return rv;
// We successfully created a wrapper. We will own this wrapper for as long as the binding remains
// alive. At the time the binding is cleared out of the bindingManager, we will remove the wrapper
// from the bindingManager as well.
nsISupports* supp = NS_STATIC_CAST(nsISupports*, *aResult);
wrappedJS = do_QueryInterface(supp);
SetWrappedJS(aContent, wrappedJS);
return rv;
}
}
*aResult = nsnull;
return NS_NOINTERFACE;
}
NS_IMETHODIMP
nsBindingManager::InheritsStyle(nsIContent* aContent, PRBool* aResult)
{
@ -781,6 +889,19 @@ nsBindingManager::WalkRules(nsIStyleSet* aStyleSet,
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::ShouldBuildChildFrames(nsIContent* aContent, PRBool* aResult)
{
*aResult = PR_TRUE;
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aContent, getter_AddRefs(binding));
if (binding)
return binding->ShouldBuildChildFrames(aResult);
return NS_OK;
}
// Creation Routine ///////////////////////////////////////////////////////////////////////

View File

@ -993,9 +993,10 @@ nsXBLBinding::InstallProperties(nsIContent* aBoundElement)
NS_IMETHODIMP
nsXBLBinding::GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult)
{
if (mNextBinding)
mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
if (!*aResult && mNextBinding)
return mNextBinding->GetBaseTag(aNameSpaceID, aResult);
return mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
return NS_OK;
}
NS_IMETHODIMP
@ -1467,6 +1468,27 @@ nsXBLBinding::MarkedForDeath(PRBool* aResult)
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
{
mPrototypeBinding->ImplementsInterface(aIID, aResult);
if (!*aResult && mNextBinding)
return mNextBinding->ImplementsInterface(aIID, aResult);
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::ShouldBuildChildFrames(PRBool* aResult)
{
*aResult = PR_TRUE;
if (mContent)
return mPrototypeBinding->ShouldBuildChildFrames(aResult);
else if (mNextBinding)
return mNextBinding->ShouldBuildChildFrames(aResult);
return NS_OK;
}
// Creation Routine ///////////////////////////////////////////////////////////////////////
nsresult

View File

@ -34,6 +34,7 @@ class nsISupportsArray;
class nsSupportsHashtable;
class nsIXBLService;
class nsFixedSizeAllocator;
class nsXBLEventHandler;
// *********************************************************************/
// The XBLBinding class
@ -93,6 +94,10 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD MarkForDeath();
NS_IMETHOD MarkedForDeath(PRBool* aResult);
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult);
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult);
public:
nsXBLBinding(nsIXBLPrototypeBinding* aProtoBinding);
virtual ~nsXBLBinding();

View File

@ -47,8 +47,11 @@
#include "nsSupportsArray.h"
#include "nsINameSpace.h"
#include "nsXBLService.h"
#include "nsXBLBinding.h"
#include "nsXBLPrototypeBinding.h"
#include "nsFixedSizeAllocator.h"
#include "xptinfo.h"
#include "nsIInterfaceInfoManager.h"
// Helper Classes =====================================================================
@ -117,7 +120,9 @@ nsIAtom* nsXBLPrototypeBinding::kContentAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kInheritsAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kHTMLAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kValueAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kXBLTextAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementationAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementsAtom = nsnull;
nsFixedSizeAllocator nsXBLPrototypeBinding::kPool;
static const size_t kBucketSizes[] = {
@ -140,7 +145,8 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
mInheritStyle(PR_TRUE),
mHasBaseProto(PR_TRUE),
mAttributeTable(nsnull),
mInsertionPointTable(nsnull)
mInsertionPointTable(nsnull),
mInterfaceTable(nsnull)
{
NS_INIT_REFCNT();
@ -160,6 +166,9 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
kInheritsAtom = NS_NewAtom("inherits");
kHTMLAtom = NS_NewAtom("html");
kValueAtom = NS_NewAtom("value");
kXBLTextAtom = NS_NewAtom("xbl:text");
kImplementationAtom = NS_NewAtom("implementation");
kImplementsAtom = NS_NewAtom("implements");
}
// These all use atoms, so we have to do these ops last to ensure
@ -178,6 +187,11 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
ConstructAttributeTable(content);
ConstructInsertionTable(content);
}
nsCOMPtr<nsIContent> impl;
GetImmediateChild(kImplementationAtom, getter_AddRefs(impl));
if (impl)
ConstructInterfaceTable(impl);
}
@ -185,6 +199,7 @@ nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
{
delete mAttributeTable;
delete mInsertionPointTable;
delete mInterfaceTable;
gRefCnt--;
if (gRefCnt == 0) {
NS_RELEASE(kInheritStyleAtom);
@ -195,6 +210,9 @@ nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
NS_RELEASE(kInheritsAtom);
NS_RELEASE(kHTMLAtom);
NS_RELEASE(kValueAtom);
NS_RELEASE(kXBLTextAtom);
NS_RELEASE(kImplementationAtom);
NS_RELEASE(kImplementsAtom);
}
}
@ -389,20 +407,35 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceI
if (aRemoveFlag)
realElement->UnsetAttribute(aNameSpaceID, dstAttr, PR_TRUE);
else {
PRBool attrPresent = PR_TRUE;
nsAutoString value;
nsresult result = aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
result == NS_CONTENT_ATTR_HAS_VALUE);
// Check to see if the src attribute is xbl:text. If so, then we need to obtain the
// children of the real element and get the text nodes' values.
if (aAttribute == kXBLTextAtom) {
nsXBLBinding::GetTextData(aChangedElement, value);
value.StripChar('\n');
value.StripChar('\r');
nsAutoString stripVal(value);
stripVal.StripWhitespace();
if (stripVal.IsEmpty())
attrPresent = PR_FALSE;
}
else {
nsresult result = aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
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.
// set or unset on us. We may also be a tag that is having
// xbl:text set on us.
nsCOMPtr<nsIAtom> tag;
realElement->GetTag(*getter_AddRefs(tag));
if ((tag.get() == kHTMLAtom) && (dstAttr.get() == kValueAtom)) {
if (dstAttr.get() == kXBLTextAtom || (tag.get() == kHTMLAtom) && (dstAttr.get() == kValueAtom)) {
// Flush out all our kids.
PRInt32 childCount;
realElement->ChildCount(childCount);
@ -425,6 +458,7 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceI
}
}
}
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = xblAttr;
tmpAttr->GetNext(getter_AddRefs(xblAttr));
}
@ -521,6 +555,23 @@ nsXBLPrototypeBinding::GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
{
// Init the answer to FALSE.
*aResult = PR_FALSE;
// Now check our IID table.
if (mInterfaceTable) {
nsIIDKey key(aIID);
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
mInterfaceTable->Get(&key)));
*aResult = supports != nsnull;
}
return NS_OK;
}
// Internal helpers ///////////////////////////////////////////////////////////////////////
void
@ -601,9 +652,23 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
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);
PRBool attrPresent = PR_TRUE;
if (src.get() == nsXBLPrototypeBinding::kXBLTextAtom) {
nsXBLBinding::GetTextData(changeData->mBoundElement, value);
value.StripChar('\n');
value.StripChar('\r');
nsAutoString stripVal(value);
stripVal.StripWhitespace();
if (stripVal.IsEmpty())
attrPresent = PR_FALSE;
}
else {
nsresult result = changeData->mBoundElement->GetAttribute(kNameSpaceID_None, src, value);
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));
@ -621,7 +686,8 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
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()) {
if (dst.get() == nsXBLPrototypeBinding::kXBLTextAtom ||
(tag.get() == nsXBLPrototypeBinding::kHTMLAtom) && (dst.get() == nsXBLPrototypeBinding::kValueAtom) && !value.IsEmpty()) {
nsCOMPtr<nsIDOMText> textNode;
nsCOMPtr<nsIDocument> doc;
changeData->mBoundElement->GetDocument(*getter_AddRefs(doc));
@ -652,6 +718,21 @@ nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIConten
return NS_OK;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::ShouldBuildChildFrames(PRBool* aResult)
{
*aResult = PR_TRUE;
if (mAttributeTable) {
nsISupportsKey key(kXBLTextAtom);
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
mAttributeTable->Get(&key)));
*aResult = !supports.get();
}
return NS_OK;
}
void
nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
{
@ -804,6 +885,55 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
}
}
void
nsXBLPrototypeBinding::ConstructInterfaceTable(nsIContent* aElement)
{
nsAutoString impls;
aElement->GetAttribute(kNameSpaceID_None, kImplementsAtom, impls);
if (!impls.IsEmpty()) {
// Obtain the interface info manager that can tell us the IID
// for a given interface name.
nsCOMPtr<nsIInterfaceInfoManager> infoManager = getter_AddRefs(XPTI_GetInterfaceInfoManager());
if (!infoManager)
return;
// Create the table.
if (!mInterfaceTable)
mInterfaceTable = new nsSupportsHashtable(4);
// The user specified at least one attribute.
char* str = impls.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 ) {
// Take the name and try obtain an IID.
nsIID* iid = nsnull;
infoManager->GetIIDForName(token, &iid);
if (iid) {
// We found a valid iid. Add it to our table.
nsIIDKey key(*iid);
mInterfaceTable->Put(&key, mBinding);
nsMemory::Free(iid);
}
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::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList)

View File

@ -84,6 +84,10 @@ class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag);
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult);
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult);
public:
nsXBLPrototypeBinding(const nsAReadableCString& aRef, nsIContent* aElement,
nsIXBLDocumentInfo* aInfo);
@ -99,7 +103,10 @@ public:
static nsIAtom* kInheritsAtom;
static nsIAtom* kHTMLAtom;
static nsIAtom* kValueAtom;
static nsIAtom* kXBLTextAtom;
static nsIAtom* kImplementationAtom;
static nsIAtom* kImplementsAtom;
static nsFixedSizeAllocator kPool;
// Internal member functions
@ -112,8 +119,33 @@ protected:
void ConstructHandlers();
void ConstructAttributeTable(nsIContent* aElement);
void ConstructInsertionTable(nsIContent* aElement);
void ConstructInterfaceTable(nsIContent* aElement);
void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList);
protected:
// Internal helper class for managing our IID table.
class nsIIDKey : public nsHashKey {
protected:
nsIID mKey;
public:
nsIIDKey(REFNSIID key) : mKey(key) {}
~nsIIDKey(void) {}
PRUint32 HashCode(void) const {
// Just use the 32-bit m0 field.
return mKey.m0;
}
PRBool Equals(const nsHashKey *aKey) const {
return mKey.Equals( ((nsIIDKey*) aKey)->mKey);
}
nsHashKey *Clone(void) const {
return new nsIIDKey(mKey);
}
};
// MEMBER VARIABLES
protected:
nsCString mID;
@ -134,6 +166,8 @@ protected:
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points for placing explicit content
// underneath anonymous content.
nsSupportsHashtable* mInterfaceTable; // A table of cached interfaces that we support.
PRInt32 mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will
nsCOMPtr<nsIAtom> mBaseTag; // be stored in here.
};

View File

@ -502,6 +502,7 @@ JSCList nsXBLService::gClassLRUList = JS_INIT_STATIC_CLIST(&nsXBLService::gClas
PRUint32 nsXBLService::gClassLRUListLength = 0;
PRUint32 nsXBLService::gClassLRUListQuota = 64;
nsIAtom* nsXBLService::kDisplayAtom = nsnull;
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
nsIAtom* nsXBLService::kEventAtom = nsnull;
nsIAtom* nsXBLService::kScrollbarAtom = nsnull;
@ -542,6 +543,7 @@ nsXBLService::nsXBLService(void)
if (NS_FAILED(rv)) return;
// Create our atoms
kDisplayAtom = NS_NewAtom("display");
kExtendsAtom = NS_NewAtom("extends");
kEventAtom = NS_NewAtom("event");
kScrollbarAtom = NS_NewAtom("scrollbar");
@ -573,6 +575,7 @@ nsXBLService::~nsXBLService(void)
NS_IF_RELEASE(gNameSpaceManager);
// Release our atoms
NS_RELEASE(kDisplayAtom);
NS_RELEASE(kExtendsAtom);
NS_RELEASE(kEventAtom);
NS_RELEASE(kScrollbarAtom);
@ -1027,51 +1030,72 @@ NS_IMETHODIMP nsXBLService::GetBindingInternal(nsIContent* aBoundElement,
}
}
else if (hasBase) {
// Check for the presence of an extends attribute
nsAutoString extends;
// Check for the presence of a 'extends' and 'display' attributes
nsAutoString display, extends;
child->GetAttribute(kNameSpaceID_None, kDisplayAtom, display);
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
PRBool hasDisplay = !display.IsEmpty();
PRBool hasExtends = !extends.IsEmpty();
nsAutoString value(extends);
if (extends.IsEmpty())
PRBool prefixIsDisplay = PR_FALSE;
if (!hasDisplay && !hasExtends)
protoBinding->SetHasBasePrototype(PR_FALSE);
else {
nsAutoString prefix;
PRInt32 offset = extends.FindChar(':');
if (-1 != offset) {
extends.Left(prefix, offset);
extends.Cut(0, offset+1);
PRInt32 offset;
if (hasDisplay) {
prefixIsDisplay = PR_TRUE;
offset = display.FindChar(':');
if (-1 != offset) {
display.Left(prefix, offset);
display.Cut(0, offset+1);
}
}
else if (hasExtends) {
offset = extends.FindChar(':');
if (-1 != offset) {
extends.Left(prefix, offset);
extends.Cut(0, offset+1);
display = extends;
}
}
nsCOMPtr<nsINameSpace> tagSpace;
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));
nsCOMPtr<nsIAtom> tagName = getter_AddRefs(NS_NewAtom(display));
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);
}
}
}
}
}
if (hasExtends && (hasDisplay || (!hasDisplay && !tagSpace))) {
// Look up the prefix.
// 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);
}
}
}
}

View File

@ -128,6 +128,7 @@ public:
static PRUint32 gClassLRUListQuota; // Quota on class LRU list.
// XBL Atoms
static nsIAtom* kDisplayAtom;
static nsIAtom* kExtendsAtom;
static nsIAtom* kEventAtom;
static nsIAtom* kScrollbarAtom;

View File

@ -41,6 +41,7 @@ class nsIXBLBindingAttachedHandler;
class nsIXBLDocumentInfo;
class nsIAtom;
class nsIStreamListener;
class nsIXPConnectWrappedJS;
// {55D70FE0-C8E5-11d3-97FB-00400553EEF0}
#define NS_IBINDING_MANAGER_IID \
@ -54,6 +55,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult) = 0;
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding) = 0;
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult) = 0;
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult) = 0;
/**
* Notify the binding manager that an element
* has been moved from one document to another,
@ -100,6 +104,10 @@ public:
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult) = 0;
NS_IMETHOD FlushChromeBindings() = 0;
NS_IMETHOD GetBindingImplementation(nsIContent* aContent, void* aScriptObject, REFNSIID aIID, void** aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(nsIContent* aContent, PRBool* aResult) = 0;
};
#endif // nsIBinding_Manager_h__

View File

@ -98,6 +98,10 @@ public:
NS_IMETHOD MarkForDeath()=0;
NS_IMETHOD MarkedForDeath(PRBool* aResult)=0;
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult)=0;
};
extern nsresult

View File

@ -84,6 +84,10 @@ public:
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag)=0;
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)=0;
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult)=0;
};
extern nsresult

View File

@ -62,6 +62,8 @@
#include "nsIXBLPrototypeBinding.h"
#include "nsIWeakReference.h"
#include "nsIXPConnect.h"
// Static IIDs/CIDs. Try to minimize these.
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
@ -203,6 +205,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult);
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding);
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult);
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
NS_IMETHOD ChangeDocumentFor(nsIContent* aContent, nsIDocument* aOldDocument,
nsIDocument* aNewDocument);
@ -234,12 +239,16 @@ public:
NS_IMETHOD InheritsStyle(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD FlushChromeBindings();
NS_IMETHOD GetBindingImplementation(nsIContent* aContent, void* aScriptObject, REFNSIID aIID, void** aResult);
// nsIStyleRuleSupplier
NS_IMETHOD UseDocumentRules(nsIContent* aContent, PRBool* aResult);
NS_IMETHOD WalkRules(nsIStyleSet* aStyleSet,
nsISupportsArrayEnumFunc aFunc, void* aData,
nsIContent* aContent);
NS_IMETHOD ShouldBuildChildFrames(nsIContent* aContent, PRBool* aResult);
protected:
void GetEnclosingScope(nsIContent* aContent, nsIContent** aParent);
void GetOutermostStyleScope(nsIContent* aContent, nsIContent** aParent);
@ -250,6 +259,7 @@ protected:
// MEMBER VARIABLES
protected:
nsSupportsHashtable* mBindingTable;
nsSupportsHashtable* mWrapperTable;
nsSupportsHashtable* mDocumentTable;
nsSupportsHashtable* mLoadingDocTable;
@ -269,7 +279,7 @@ nsBindingManager::nsBindingManager(void)
NS_INIT_REFCNT();
mBindingTable = nsnull;
mWrapperTable = nsnull;
mDocumentTable = nsnull;
mLoadingDocTable = nsnull;
@ -279,6 +289,7 @@ nsBindingManager::nsBindingManager(void)
nsBindingManager::~nsBindingManager(void)
{
delete mBindingTable;
delete mWrapperTable;
delete mDocumentTable;
delete mLoadingDocTable;
}
@ -312,9 +323,43 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding )
if (aBinding) {
mBindingTable->Put(&key, aBinding);
}
else
else {
mBindingTable->Remove(&key);
// The death of the bindings means the death of the JS wrapper.
SetWrappedJS(aContent, nsnull);
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult)
{
if (mWrapperTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIXPConnectWrappedJS*, mWrapperTable->Get(&key));
}
else {
*aResult = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aWrappedJS)
{
if (!mWrapperTable)
mWrapperTable = new nsSupportsHashtable;
nsISupportsKey key(aContent);
if (aWrappedJS) {
mWrapperTable->Put(&key, aWrappedJS);
}
else
mWrapperTable->Remove(&key);
return NS_OK;
}
@ -669,6 +714,69 @@ nsBindingManager::FlushChromeBindings()
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetBindingImplementation(nsIContent* aContent, void* aScriptObject, REFNSIID aIID, void** aResult)
{
*aResult = nsnull;
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aContent, getter_AddRefs(binding));
if (binding) {
PRBool supportsInterface;
binding->ImplementsInterface(aIID, &supportsInterface);
if (supportsInterface) {
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS;
GetWrappedJS(aContent, getter_AddRefs(wrappedJS));
if (wrappedJS)
return wrappedJS->AggregatedQueryInterface(aIID, aResult);
// We have never made a wrapper for this implementation.
// Create an XPC wrapper for the script object and hand it back.
JSObject* jsobj = (JSObject*)aScriptObject;
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
if (!doc)
return NS_NOINTERFACE;
nsCOMPtr<nsIScriptGlobalObject> global;
doc->GetScriptGlobalObject(getter_AddRefs(global));
if (!global)
return NS_NOINTERFACE;
nsCOMPtr<nsIScriptContext> context;
global->GetContext(getter_AddRefs(context));
if (!context)
return NS_NOINTERFACE;
JSContext* jscontext = (JSContext*)context->GetNativeContext();
if (!jscontext)
return NS_NOINTERFACE;
nsCOMPtr<nsIXPConnect> xpConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
if (!xpConnect)
return NS_NOINTERFACE;
nsISupports* nativeThis = (nsISupports*)JS_GetPrivate(jscontext, jsobj);
nsresult rv = xpConnect->WrapJSAggregatedToNative(nativeThis, jscontext, jsobj, aIID, aResult);
if (NS_FAILED(rv))
return rv;
// We successfully created a wrapper. We will own this wrapper for as long as the binding remains
// alive. At the time the binding is cleared out of the bindingManager, we will remove the wrapper
// from the bindingManager as well.
nsISupports* supp = NS_STATIC_CAST(nsISupports*, *aResult);
wrappedJS = do_QueryInterface(supp);
SetWrappedJS(aContent, wrappedJS);
return rv;
}
}
*aResult = nsnull;
return NS_NOINTERFACE;
}
NS_IMETHODIMP
nsBindingManager::InheritsStyle(nsIContent* aContent, PRBool* aResult)
{
@ -781,6 +889,19 @@ nsBindingManager::WalkRules(nsIStyleSet* aStyleSet,
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::ShouldBuildChildFrames(nsIContent* aContent, PRBool* aResult)
{
*aResult = PR_TRUE;
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aContent, getter_AddRefs(binding));
if (binding)
return binding->ShouldBuildChildFrames(aResult);
return NS_OK;
}
// Creation Routine ///////////////////////////////////////////////////////////////////////

View File

@ -993,9 +993,10 @@ nsXBLBinding::InstallProperties(nsIContent* aBoundElement)
NS_IMETHODIMP
nsXBLBinding::GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult)
{
if (mNextBinding)
mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
if (!*aResult && mNextBinding)
return mNextBinding->GetBaseTag(aNameSpaceID, aResult);
return mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
return NS_OK;
}
NS_IMETHODIMP
@ -1467,6 +1468,27 @@ nsXBLBinding::MarkedForDeath(PRBool* aResult)
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
{
mPrototypeBinding->ImplementsInterface(aIID, aResult);
if (!*aResult && mNextBinding)
return mNextBinding->ImplementsInterface(aIID, aResult);
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::ShouldBuildChildFrames(PRBool* aResult)
{
*aResult = PR_TRUE;
if (mContent)
return mPrototypeBinding->ShouldBuildChildFrames(aResult);
else if (mNextBinding)
return mNextBinding->ShouldBuildChildFrames(aResult);
return NS_OK;
}
// Creation Routine ///////////////////////////////////////////////////////////////////////
nsresult

View File

@ -34,6 +34,7 @@ class nsISupportsArray;
class nsSupportsHashtable;
class nsIXBLService;
class nsFixedSizeAllocator;
class nsXBLEventHandler;
// *********************************************************************/
// The XBLBinding class
@ -93,6 +94,10 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD MarkForDeath();
NS_IMETHOD MarkedForDeath(PRBool* aResult);
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult);
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult);
public:
nsXBLBinding(nsIXBLPrototypeBinding* aProtoBinding);
virtual ~nsXBLBinding();

View File

@ -47,8 +47,11 @@
#include "nsSupportsArray.h"
#include "nsINameSpace.h"
#include "nsXBLService.h"
#include "nsXBLBinding.h"
#include "nsXBLPrototypeBinding.h"
#include "nsFixedSizeAllocator.h"
#include "xptinfo.h"
#include "nsIInterfaceInfoManager.h"
// Helper Classes =====================================================================
@ -117,7 +120,9 @@ nsIAtom* nsXBLPrototypeBinding::kContentAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kInheritsAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kHTMLAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kValueAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kXBLTextAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementationAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementsAtom = nsnull;
nsFixedSizeAllocator nsXBLPrototypeBinding::kPool;
static const size_t kBucketSizes[] = {
@ -140,7 +145,8 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
mInheritStyle(PR_TRUE),
mHasBaseProto(PR_TRUE),
mAttributeTable(nsnull),
mInsertionPointTable(nsnull)
mInsertionPointTable(nsnull),
mInterfaceTable(nsnull)
{
NS_INIT_REFCNT();
@ -160,6 +166,9 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
kInheritsAtom = NS_NewAtom("inherits");
kHTMLAtom = NS_NewAtom("html");
kValueAtom = NS_NewAtom("value");
kXBLTextAtom = NS_NewAtom("xbl:text");
kImplementationAtom = NS_NewAtom("implementation");
kImplementsAtom = NS_NewAtom("implements");
}
// These all use atoms, so we have to do these ops last to ensure
@ -178,6 +187,11 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
ConstructAttributeTable(content);
ConstructInsertionTable(content);
}
nsCOMPtr<nsIContent> impl;
GetImmediateChild(kImplementationAtom, getter_AddRefs(impl));
if (impl)
ConstructInterfaceTable(impl);
}
@ -185,6 +199,7 @@ nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
{
delete mAttributeTable;
delete mInsertionPointTable;
delete mInterfaceTable;
gRefCnt--;
if (gRefCnt == 0) {
NS_RELEASE(kInheritStyleAtom);
@ -195,6 +210,9 @@ nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
NS_RELEASE(kInheritsAtom);
NS_RELEASE(kHTMLAtom);
NS_RELEASE(kValueAtom);
NS_RELEASE(kXBLTextAtom);
NS_RELEASE(kImplementationAtom);
NS_RELEASE(kImplementsAtom);
}
}
@ -389,20 +407,35 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceI
if (aRemoveFlag)
realElement->UnsetAttribute(aNameSpaceID, dstAttr, PR_TRUE);
else {
PRBool attrPresent = PR_TRUE;
nsAutoString value;
nsresult result = aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
result == NS_CONTENT_ATTR_HAS_VALUE);
// Check to see if the src attribute is xbl:text. If so, then we need to obtain the
// children of the real element and get the text nodes' values.
if (aAttribute == kXBLTextAtom) {
nsXBLBinding::GetTextData(aChangedElement, value);
value.StripChar('\n');
value.StripChar('\r');
nsAutoString stripVal(value);
stripVal.StripWhitespace();
if (stripVal.IsEmpty())
attrPresent = PR_FALSE;
}
else {
nsresult result = aChangedElement->GetAttribute(aNameSpaceID, aAttribute, value);
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.
// set or unset on us. We may also be a tag that is having
// xbl:text set on us.
nsCOMPtr<nsIAtom> tag;
realElement->GetTag(*getter_AddRefs(tag));
if ((tag.get() == kHTMLAtom) && (dstAttr.get() == kValueAtom)) {
if (dstAttr.get() == kXBLTextAtom || (tag.get() == kHTMLAtom) && (dstAttr.get() == kValueAtom)) {
// Flush out all our kids.
PRInt32 childCount;
realElement->ChildCount(childCount);
@ -425,6 +458,7 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceI
}
}
}
nsCOMPtr<nsIXBLAttributeEntry> tmpAttr = xblAttr;
tmpAttr->GetNext(getter_AddRefs(xblAttr));
}
@ -521,6 +555,23 @@ nsXBLPrototypeBinding::GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
{
// Init the answer to FALSE.
*aResult = PR_FALSE;
// Now check our IID table.
if (mInterfaceTable) {
nsIIDKey key(aIID);
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
mInterfaceTable->Get(&key)));
*aResult = supports != nsnull;
}
return NS_OK;
}
// Internal helpers ///////////////////////////////////////////////////////////////////////
void
@ -601,9 +652,23 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
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);
PRBool attrPresent = PR_TRUE;
if (src.get() == nsXBLPrototypeBinding::kXBLTextAtom) {
nsXBLBinding::GetTextData(changeData->mBoundElement, value);
value.StripChar('\n');
value.StripChar('\r');
nsAutoString stripVal(value);
stripVal.StripWhitespace();
if (stripVal.IsEmpty())
attrPresent = PR_FALSE;
}
else {
nsresult result = changeData->mBoundElement->GetAttribute(kNameSpaceID_None, src, value);
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));
@ -621,7 +686,8 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
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()) {
if (dst.get() == nsXBLPrototypeBinding::kXBLTextAtom ||
(tag.get() == nsXBLPrototypeBinding::kHTMLAtom) && (dst.get() == nsXBLPrototypeBinding::kValueAtom) && !value.IsEmpty()) {
nsCOMPtr<nsIDOMText> textNode;
nsCOMPtr<nsIDocument> doc;
changeData->mBoundElement->GetDocument(*getter_AddRefs(doc));
@ -652,6 +718,21 @@ nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIConten
return NS_OK;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::ShouldBuildChildFrames(PRBool* aResult)
{
*aResult = PR_TRUE;
if (mAttributeTable) {
nsISupportsKey key(kXBLTextAtom);
nsCOMPtr<nsISupports> supports = getter_AddRefs(NS_STATIC_CAST(nsISupports*,
mAttributeTable->Get(&key)));
*aResult = !supports.get();
}
return NS_OK;
}
void
nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
{
@ -804,6 +885,55 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
}
}
void
nsXBLPrototypeBinding::ConstructInterfaceTable(nsIContent* aElement)
{
nsAutoString impls;
aElement->GetAttribute(kNameSpaceID_None, kImplementsAtom, impls);
if (!impls.IsEmpty()) {
// Obtain the interface info manager that can tell us the IID
// for a given interface name.
nsCOMPtr<nsIInterfaceInfoManager> infoManager = getter_AddRefs(XPTI_GetInterfaceInfoManager());
if (!infoManager)
return;
// Create the table.
if (!mInterfaceTable)
mInterfaceTable = new nsSupportsHashtable(4);
// The user specified at least one attribute.
char* str = impls.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 ) {
// Take the name and try obtain an IID.
nsIID* iid = nsnull;
infoManager->GetIIDForName(token, &iid);
if (iid) {
// We found a valid iid. Add it to our table.
nsIIDKey key(*iid);
mInterfaceTable->Put(&key, mBinding);
nsMemory::Free(iid);
}
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::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList)

View File

@ -84,6 +84,10 @@ class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag);
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult);
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult);
public:
nsXBLPrototypeBinding(const nsAReadableCString& aRef, nsIContent* aElement,
nsIXBLDocumentInfo* aInfo);
@ -99,7 +103,10 @@ public:
static nsIAtom* kInheritsAtom;
static nsIAtom* kHTMLAtom;
static nsIAtom* kValueAtom;
static nsIAtom* kXBLTextAtom;
static nsIAtom* kImplementationAtom;
static nsIAtom* kImplementsAtom;
static nsFixedSizeAllocator kPool;
// Internal member functions
@ -112,8 +119,33 @@ protected:
void ConstructHandlers();
void ConstructAttributeTable(nsIContent* aElement);
void ConstructInsertionTable(nsIContent* aElement);
void ConstructInterfaceTable(nsIContent* aElement);
void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray** aList);
protected:
// Internal helper class for managing our IID table.
class nsIIDKey : public nsHashKey {
protected:
nsIID mKey;
public:
nsIIDKey(REFNSIID key) : mKey(key) {}
~nsIIDKey(void) {}
PRUint32 HashCode(void) const {
// Just use the 32-bit m0 field.
return mKey.m0;
}
PRBool Equals(const nsHashKey *aKey) const {
return mKey.Equals( ((nsIIDKey*) aKey)->mKey);
}
nsHashKey *Clone(void) const {
return new nsIIDKey(mKey);
}
};
// MEMBER VARIABLES
protected:
nsCString mID;
@ -134,6 +166,8 @@ protected:
nsSupportsHashtable* mInsertionPointTable; // A table of insertion points for placing explicit content
// underneath anonymous content.
nsSupportsHashtable* mInterfaceTable; // A table of cached interfaces that we support.
PRInt32 mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will
nsCOMPtr<nsIAtom> mBaseTag; // be stored in here.
};

View File

@ -502,6 +502,7 @@ JSCList nsXBLService::gClassLRUList = JS_INIT_STATIC_CLIST(&nsXBLService::gClas
PRUint32 nsXBLService::gClassLRUListLength = 0;
PRUint32 nsXBLService::gClassLRUListQuota = 64;
nsIAtom* nsXBLService::kDisplayAtom = nsnull;
nsIAtom* nsXBLService::kExtendsAtom = nsnull;
nsIAtom* nsXBLService::kEventAtom = nsnull;
nsIAtom* nsXBLService::kScrollbarAtom = nsnull;
@ -542,6 +543,7 @@ nsXBLService::nsXBLService(void)
if (NS_FAILED(rv)) return;
// Create our atoms
kDisplayAtom = NS_NewAtom("display");
kExtendsAtom = NS_NewAtom("extends");
kEventAtom = NS_NewAtom("event");
kScrollbarAtom = NS_NewAtom("scrollbar");
@ -573,6 +575,7 @@ nsXBLService::~nsXBLService(void)
NS_IF_RELEASE(gNameSpaceManager);
// Release our atoms
NS_RELEASE(kDisplayAtom);
NS_RELEASE(kExtendsAtom);
NS_RELEASE(kEventAtom);
NS_RELEASE(kScrollbarAtom);
@ -1027,51 +1030,72 @@ NS_IMETHODIMP nsXBLService::GetBindingInternal(nsIContent* aBoundElement,
}
}
else if (hasBase) {
// Check for the presence of an extends attribute
nsAutoString extends;
// Check for the presence of a 'extends' and 'display' attributes
nsAutoString display, extends;
child->GetAttribute(kNameSpaceID_None, kDisplayAtom, display);
child->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends);
PRBool hasDisplay = !display.IsEmpty();
PRBool hasExtends = !extends.IsEmpty();
nsAutoString value(extends);
if (extends.IsEmpty())
PRBool prefixIsDisplay = PR_FALSE;
if (!hasDisplay && !hasExtends)
protoBinding->SetHasBasePrototype(PR_FALSE);
else {
nsAutoString prefix;
PRInt32 offset = extends.FindChar(':');
if (-1 != offset) {
extends.Left(prefix, offset);
extends.Cut(0, offset+1);
PRInt32 offset;
if (hasDisplay) {
prefixIsDisplay = PR_TRUE;
offset = display.FindChar(':');
if (-1 != offset) {
display.Left(prefix, offset);
display.Cut(0, offset+1);
}
}
else if (hasExtends) {
offset = extends.FindChar(':');
if (-1 != offset) {
extends.Left(prefix, offset);
extends.Cut(0, offset+1);
display = extends;
}
}
nsCOMPtr<nsINameSpace> tagSpace;
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));
nsCOMPtr<nsIAtom> tagName = getter_AddRefs(NS_NewAtom(display));
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);
}
}
}
}
}
if (hasExtends && (hasDisplay || (!hasDisplay && !tagSpace))) {
// Look up the prefix.
// 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);
}
}
}
}

View File

@ -128,6 +128,7 @@ public:
static PRUint32 gClassLRUListQuota; // Quota on class LRU list.
// XBL Atoms
static nsIAtom* kDisplayAtom;
static nsIAtom* kExtendsAtom;
static nsIAtom* kEventAtom;
static nsIAtom* kScrollbarAtom;