Bug 51444 Make xbl:inherits work with namespaced attributes p=smaug@welho.com r+sr=bz

This commit is contained in:
neil%parkwaycc.co.uk 2005-01-01 18:02:03 +00:00
Родитель 9030bead0f
Коммит 36fef2db76
6 изменённых файлов: 169 добавлений и 50 удалений

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

@ -294,6 +294,14 @@ public:
static nsresult CheckQName(const nsAString& aQualifiedName,
PRBool aNamespaceAware = PR_TRUE);
static nsresult SplitQName(nsIContent* aNamespaceResolver,
const nsAFlatString& aQName,
PRInt32 *aNamespace, nsIAtom **aLocalName);
static nsresult LookupNamespaceURI(nsIContent* aNamespaceResolver,
const nsAString& aNamespacePrefix,
nsAString& aNamespaceURI);
static nsresult GetNodeInfoFromQName(const nsAString& aNamespaceURI,
const nsAString& aQualifiedName,
nsNodeInfoManager* aNodeInfoManager,

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

@ -1627,6 +1627,66 @@ nsContentUtils::CheckQName(const nsAString& aQualifiedName,
aNamespaceAware, &colon);
}
//static
nsresult
nsContentUtils::SplitQName(nsIContent* aNamespaceResolver,
const nsAFlatString& aQName,
PRInt32 *aNamespace, nsIAtom **aLocalName)
{
nsIParserService* parserService = GetParserServiceWeakRef();
NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
const PRUnichar* colon;
nsresult rv = parserService->CheckQName(aQName, PR_TRUE, &colon);
NS_ENSURE_SUCCESS(rv, rv);
if (colon) {
const PRUnichar* end;
aQName.EndReading(end);
nsAutoString nameSpace;
rv = LookupNamespaceURI(aNamespaceResolver, Substring(aQName.get(), colon),
nameSpace);
NS_ENSURE_SUCCESS(rv, rv);
GetNSManagerWeakRef()->GetNameSpaceID(nameSpace, aNamespace);
if (*aNamespace == kNameSpaceID_Unknown)
return NS_ERROR_FAILURE;
*aLocalName = NS_NewAtom(Substring(colon + 1, end));
}
else {
*aNamespace = kNameSpaceID_None;
*aLocalName = NS_NewAtom(aQName);
}
NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
// static
nsresult
nsContentUtils::LookupNamespaceURI(nsIContent* aNamespaceResolver,
const nsAString& aNamespacePrefix,
nsAString& aNamespaceURI)
{
nsCOMPtr<nsIAtom> name;
if (!aNamespacePrefix.IsEmpty()) {
name = do_GetAtom(aNamespacePrefix);
NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
}
else {
name = nsLayoutAtoms::xmlnsNameSpace;
}
// Trace up the content parent chain looking for the namespace
// declaration that declares aNamespacePrefix.
for (nsIContent* content = aNamespaceResolver; content;
content = content->GetParent()) {
if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI) ==
NS_CONTENT_ATTR_HAS_VALUE)
return NS_OK;
}
return NS_ERROR_FAILURE;
}
// static
nsresult
nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,

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

@ -460,28 +460,11 @@ NS_IMETHODIMP
nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix,
nsAString& aNamespaceURI)
{
nsCOMPtr<nsIAtom> name;
if (!aNamespacePrefix.IsEmpty()) {
name = do_GetAtom(aNamespacePrefix);
NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
} else {
name = nsLayoutAtoms::xmlnsNameSpace;
if (NS_FAILED(nsContentUtils::LookupNamespaceURI(mContent,
aNamespacePrefix,
aNamespaceURI))) {
SetDOMStringToNull(aNamespaceURI);
}
// Trace up the content parent chain looking for the namespace
// declaration that declares aNamespacePrefix.
for (nsIContent* content = mContent; content;
content = content->GetParent()) {
nsresult rv = content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI);
if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
return NS_OK;
}
}
SetDOMStringToNull(aNamespaceURI);
return NS_OK;
}

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

@ -66,7 +66,6 @@ XBL_ATOM(image, "image")
XBL_ATOM(stylesheet, "stylesheet")
XBL_ATOM(implementation, "implementation")
XBL_ATOM(implements, "implements")
XBL_ATOM(xbltext, "xbl:text")
XBL_ATOM(method, "method")
XBL_ATOM(property, "property")
XBL_ATOM(field, "field")

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

@ -73,6 +73,7 @@
#include "nsXBLAtoms.h"
#include "nsXBLProtoImpl.h"
#include "nsCRT.h"
#include "nsContentUtils.h"
#include "nsIScriptContext.h"
@ -88,6 +89,7 @@ class nsXBLAttributeEntry {
public:
nsIAtom* GetSrcAttribute() { return mSrcAttribute; }
nsIAtom* GetDstAttribute() { return mDstAttribute; }
PRInt32 GetDstNameSpace() { return mDstNameSpace; }
nsIContent* GetElement() { return mElement; }
@ -95,9 +97,10 @@ public:
void SetNext(nsXBLAttributeEntry* aEntry) { mNext = aEntry; }
static nsXBLAttributeEntry*
Create(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, nsIContent* aContent) {
Create(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, PRInt32 aDstNameSpace, nsIContent* aContent) {
void* place = nsXBLPrototypeBinding::kAttrPool->Alloc(sizeof(nsXBLAttributeEntry));
return place ? ::new (place) nsXBLAttributeEntry(aSrcAtom, aDstAtom, aContent) : nsnull;
return place ? ::new (place) nsXBLAttributeEntry(aSrcAtom, aDstAtom, aDstNameSpace,
aContent) : nsnull;
}
static void
@ -111,13 +114,15 @@ protected:
nsCOMPtr<nsIAtom> mSrcAttribute;
nsCOMPtr<nsIAtom> mDstAttribute;
PRInt32 mDstNameSpace;
nsXBLAttributeEntry* mNext;
nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom,
nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, PRInt32 aDstNameSpace,
nsIContent* aContent)
: mElement(aContent),
mSrcAttribute(aSrcAtom),
mDstAttribute(aDstAtom),
mDstNameSpace(aDstNameSpace),
mNext(nsnull) { }
~nsXBLAttributeEntry() { delete mNext; }
@ -226,7 +231,7 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding()
mHasBaseProto(PR_TRUE),
mKeyHandlersRegistered(PR_FALSE),
mResources(nsnull),
mAttributeTable(nsnull),
mAttributeTable(nsnull),
mInsertionPointTable(nsnull),
mInterfaceTable(nsnull)
{
@ -436,9 +441,15 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute,
{
if (!mAttributeTable)
return;
nsPRUint32Key nskey(aNameSpaceID);
nsObjectHashtable *attributesNS = NS_STATIC_CAST(nsObjectHashtable*,
mAttributeTable->Get(&nskey));
if (!attributesNS)
return;
nsISupportsKey key(aAttribute);
nsXBLAttributeEntry* xblAttr = NS_STATIC_CAST(nsXBLAttributeEntry*, mAttributeTable->Get(&key));
nsXBLAttributeEntry* xblAttr = NS_STATIC_CAST(nsXBLAttributeEntry*,
attributesNS->Get(&key));
if (!xblAttr)
return;
@ -453,15 +464,16 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute,
if (realElement) {
nsIAtom* dstAttr = xblAttr->GetDstAttribute();
PRInt32 dstNs = xblAttr->GetDstNameSpace();
if (aRemoveFlag)
realElement->UnsetAttr(aNameSpaceID, dstAttr, aNotify);
realElement->UnsetAttr(dstNs, dstAttr, aNotify);
else {
PRBool attrPresent = PR_TRUE;
nsAutoString 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 == nsXBLAtoms::xbltext) {
if (aAttribute == nsHTMLAtoms::text && aNameSpaceID == kNameSpaceID_XBL) {
nsXBLBinding::GetTextData(aChangedElement, value);
value.StripChar(PRUnichar('\n'));
value.StripChar(PRUnichar('\r'));
@ -477,14 +489,14 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute,
}
if (attrPresent)
realElement->SetAttr(aNameSpaceID, dstAttr, value, aNotify);
realElement->SetAttr(dstNs, dstAttr, value, aNotify);
}
// See if we're the <html> tag in XUL, and see if value is being
// set or unset on us. We may also be a tag that is having
// xbl:text set on us.
if (dstAttr == nsXBLAtoms::xbltext ||
if ((dstAttr == nsHTMLAtoms::text && dstNs == kNameSpaceID_XBL) ||
realElement->GetNodeInfo()->Equals(nsHTMLAtoms::html,
kNameSpaceID_XUL) &&
dstAttr == nsHTMLAtoms::value) {
@ -833,6 +845,7 @@ struct nsXBLAttrChangeData
nsXBLPrototypeBinding* mProto;
nsIContent* mBoundElement;
nsIContent* mContent;
PRInt32 mSrcNamespace;
nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
nsIContent* aElt, nsIContent* aContent)
@ -841,15 +854,15 @@ struct nsXBLAttrChangeData
PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
{
// XXX How to deal with NAMESPACES!!!?
nsXBLAttributeEntry* entry = NS_STATIC_CAST(nsXBLAttributeEntry*, aData);
nsXBLAttrChangeData* changeData = NS_STATIC_CAST(nsXBLAttrChangeData*, aClosure);
nsIAtom* src = entry->GetSrcAttribute();
PRInt32 srcNs = changeData->mSrcNamespace;
nsAutoString value;
PRBool attrPresent = PR_TRUE;
if (src == nsXBLAtoms::xbltext) {
if (src == nsHTMLAtoms::text && srcNs == kNameSpaceID_XBL) {
nsXBLBinding::GetTextData(changeData->mBoundElement, value);
value.StripChar(PRUnichar('\n'));
value.StripChar(PRUnichar('\r'));
@ -860,7 +873,7 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
attrPresent = PR_FALSE;
}
else {
nsresult result = changeData->mBoundElement->GetAttr(kNameSpaceID_None, src, value);
nsresult result = changeData->mBoundElement->GetAttr(srcNs, src, value);
attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE ||
result == NS_CONTENT_ATTR_HAS_VALUE);
}
@ -872,6 +885,7 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
nsXBLAttributeEntry* curr = entry;
while (curr) {
nsIAtom* dst = curr->GetDstAttribute();
PRInt32 dstNs = curr->GetDstNameSpace();
nsIContent* element = curr->GetElement();
nsCOMPtr<nsIContent> realElement;
@ -880,9 +894,9 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
changeData->mContent,
element);
if (realElement) {
realElement->SetAttr(kNameSpaceID_None, dst, value, PR_FALSE);
realElement->SetAttr(dstNs, dst, value, PR_FALSE);
if (dst == nsXBLAtoms::xbltext ||
if ((dst == nsHTMLAtoms::text && dstNs == kNameSpaceID_XBL) ||
(realElement->GetNodeInfo()->Equals(nsHTMLAtoms::html,
kNameSpaceID_XUL) &&
dst == nsHTMLAtoms::value && !value.IsEmpty())) {
@ -904,12 +918,26 @@ PRBool PR_CALLBACK SetAttrs(nsHashKey* aKey, void* aData, void* aClosure)
return PR_TRUE;
}
PRBool PR_CALLBACK SetAttrsNS(nsHashKey* aKey, void* aData, void* aClosure)
{
if (aData && aClosure) {
nsPRUint32Key * key = NS_STATIC_CAST(nsPRUint32Key*, aKey);
nsObjectHashtable* xblAttributes =
NS_STATIC_CAST(nsObjectHashtable*, aData);
nsXBLAttrChangeData * changeData = NS_STATIC_CAST(nsXBLAttrChangeData *,
aClosure);
changeData->mSrcNamespace = key->GetValue();
xblAttributes->Enumerate(SetAttrs, (void*)changeData);
}
return PR_TRUE;
}
void
nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
{
if (mAttributeTable) {
nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
mAttributeTable->Enumerate(SetAttrs, (void*)&data);
mAttributeTable->Enumerate(SetAttrsNS, (void*)&data);
}
}
@ -936,9 +964,14 @@ nsXBLPrototypeBinding::GetStyleSheets()
PRBool
nsXBLPrototypeBinding::ShouldBuildChildFrames()
{
if (mAttributeTable) {
nsISupportsKey key(nsXBLAtoms::xbltext);
void* entry = mAttributeTable->Get(&key);
if (!mAttributeTable)
return PR_TRUE;
nsPRUint32Key nskey(kNameSpaceID_XBL);
nsObjectHashtable* xblAttributes =
NS_STATIC_CAST(nsObjectHashtable*, mAttributeTable->Get(&nskey));
if (xblAttributes) {
nsISupportsKey key(nsHTMLAtoms::text);
void* entry = xblAttributes->Get(&key);
return !entry;
}
@ -952,6 +985,13 @@ DeleteAttributeEntry(nsHashKey* aKey, void* aData, void* aClosure)
return PR_TRUE;
}
static PRBool PR_CALLBACK
DeleteAttributeTable(nsHashKey* aKey, void* aData, void* aClosure)
{
delete NS_STATIC_CAST(nsObjectHashtable*, aData);
return PR_TRUE;
}
void
nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
{
@ -961,7 +1001,7 @@ nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
if (!inherits.IsEmpty()) {
if (!mAttributeTable) {
mAttributeTable = new nsObjectHashtable(nsnull, nsnull,
DeleteAttributeEntry, nsnull, 4);
DeleteAttributeTable, nsnull, 4);
if (!mAttributeTable)
return;
}
@ -976,38 +1016,66 @@ nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
while( token != NULL ) {
// Build an atom out of this attribute.
nsCOMPtr<nsIAtom> atom;
PRInt32 atomNsID = kNameSpaceID_None;
nsCOMPtr<nsIAtom> attribute;
PRInt32 attributeNsID = kNameSpaceID_None;
// Figure out if this token contains a :.
nsAutoString attrTok; attrTok.AssignWithConversion(token);
PRInt32 index = attrTok.Find("=", PR_TRUE);
nsresult rv;
if (index != -1) {
// This attribute maps to something different.
nsAutoString left, right;
attrTok.Left(left, index);
attrTok.Right(right, attrTok.Length()-index-1);
atom = do_GetAtom(right);
attribute = do_GetAtom(left);
rv = nsContentUtils::SplitQName(aElement, left, &attributeNsID,
getter_AddRefs(attribute));
if (NS_FAILED(rv))
return;
rv = nsContentUtils::SplitQName(aElement, right, &atomNsID,
getter_AddRefs(atom));
if (NS_FAILED(rv))
return;
}
else {
nsAutoString tok;
tok.AssignWithConversion(token);
atom = do_GetAtom(tok);
rv = nsContentUtils::SplitQName(aElement, tok, &atomNsID,
getter_AddRefs(atom));
if (NS_FAILED(rv))
return;
attribute = atom;
attributeNsID = atomNsID;
}
nsPRUint32Key nskey(atomNsID);
nsObjectHashtable* attributesNS =
NS_STATIC_CAST(nsObjectHashtable*, mAttributeTable->Get(&nskey));
if (!attributesNS) {
attributesNS = new nsObjectHashtable(nsnull, nsnull,
DeleteAttributeEntry, nsnull, 4);
if (!attributesNS)
return;
mAttributeTable->Put(&nskey, attributesNS);
}
// Create an XBL attribute entry.
nsXBLAttributeEntry* xblAttr = nsXBLAttributeEntry::Create(atom, attribute, aElement);
nsXBLAttributeEntry* xblAttr =
nsXBLAttributeEntry::Create(atom, attribute, attributeNsID, aElement);
// Now we should see if some element within our anonymous
// content is already observing this attribute.
nsISupportsKey key(atom);
nsXBLAttributeEntry* entry = NS_STATIC_CAST(nsXBLAttributeEntry*, mAttributeTable->Get(&key));
nsXBLAttributeEntry* entry = NS_STATIC_CAST(nsXBLAttributeEntry*,
attributesNS->Get(&key));
if (!entry) {
// Put it in the table.
mAttributeTable->Put(&key, xblAttr);
attributesNS->Put(&key, xblAttr);
} else {
while (entry->GetNext())
entry = entry->GetNext();
@ -1250,7 +1318,7 @@ nsXBLPrototypeBinding::CreateKeyHandlers()
PRInt32 count = mKeyHandlers.Count();
PRInt32 i;
nsXBLKeyEventHandler* handler;
nsXBLKeyEventHandler* handler = nsnull;
for (i = 0; i < count; ++i) {
handler = mKeyHandlers[i];
if (handler->Matches(eventAtom, phase, type))

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

@ -236,8 +236,9 @@ protected:
nsIXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info. Weak, since it owns us.
nsObjectHashtable* mAttributeTable; // A table for attribute entries. Used to efficiently
// handle attribute changes.
nsObjectHashtable* mAttributeTable; // A table for attribute containers. Namespace IDs are used as
// keys in the table. Containers are nsObjectHashtables.
// This table is used to efficiently handle attribute changes.
nsObjectHashtable* mInsertionPointTable; // A table of insertion points for placing explicit content
// underneath anonymous content.