diff --git a/content/base/public/nsIContent.h b/content/base/public/nsIContent.h index 105be819376..8dae699bbb7 100644 --- a/content/base/public/nsIContent.h +++ b/content/base/public/nsIContent.h @@ -63,8 +63,8 @@ class nsIDocShell; // IID for the nsIContent interface #define NS_ICONTENT_IID \ -{ 0x36b375cb, 0xf01e, 0x4c18, \ - { 0xbf, 0x9e, 0xba, 0xad, 0x77, 0x1d, 0xce, 0x22 } } +{ 0x609baee8, 0x3c0a, 0x4122, \ + { 0x9c, 0xc6, 0xe4, 0xc9, 0x83, 0x53, 0xff, 0x9c } } // hack to make egcs / gcc 2.95.2 happy class nsIContent_base : public nsINode { @@ -211,10 +211,21 @@ public: /** * Returns an atom holding the name of the attribute of type ID on - * this content node (if applicable). Returns null for non-element - * content nodes. + * this content node (if applicable). + * Language specific ID attribute has the highest priority, then + * ID attribute defined in DTD, and finally xml:id. + * Returns null for non-element content nodes. */ - virtual nsIAtom *GetIDAttributeName() const = 0; + virtual nsIAtom* GetIDAttributeName(PRInt32& aNameSpaceID) const = 0; + + /** + * Returns true if the attribute can be + * used as an ID attribute of the element. + * Note this may return true with many attributes, but only one + * is used as an ID at a time. + */ + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const = 0; /** * Normalizes an attribute name and returns it as a nodeinfo if an attribute @@ -731,8 +742,8 @@ public: /** * Get the ID of this content node (the atom corresponding to the - * value of the null-namespace attribute whose name is given by - * GetIDAttributeName(). This may be null if there is no ID. + * value of the attribute whose name is given by GetIDAttributeName(). + * This may be null if there is no ID. */ virtual nsIAtom* GetID() const = 0; diff --git a/content/base/src/nsDOMAttribute.cpp b/content/base/src/nsDOMAttribute.cpp index d01023df035..fd31bbfbe09 100644 --- a/content/base/src/nsDOMAttribute.cpp +++ b/content/base/src/nsDOMAttribute.cpp @@ -600,14 +600,15 @@ nsDOMAttribute::GetIsId(PRBool* aReturn) return NS_OK; } - nsIAtom* idAtom = content->GetIDAttributeName(); + PRInt32 namespaceID; + nsIAtom* idAtom = content->GetIDAttributeName(namespaceID); if (!idAtom) { *aReturn = PR_FALSE; return NS_OK; } - *aReturn = mNodeInfo->Equals(idAtom, kNameSpaceID_None); + *aReturn = mNodeInfo->Equals(idAtom, namespaceID); return NS_OK; } diff --git a/content/base/src/nsGenericDOMDataNode.cpp b/content/base/src/nsGenericDOMDataNode.cpp index 5f436eae71b..4ea0c2bd2e7 100644 --- a/content/base/src/nsGenericDOMDataNode.cpp +++ b/content/base/src/nsGenericDOMDataNode.cpp @@ -631,11 +631,19 @@ nsGenericDOMDataNode::UnbindFromTree(PRBool aDeep, PRBool aNullParent) } nsIAtom * -nsGenericDOMDataNode::GetIDAttributeName() const +nsGenericDOMDataNode::GetIDAttributeName(PRInt32& aNameSpaceID) const { + aNameSpaceID = kNameSpaceID_Unknown; return nsnull; } +PRBool +nsGenericDOMDataNode::IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const +{ + return PR_FALSE; +} + already_AddRefed nsGenericDOMDataNode::GetExistingAttrNameFromQName(const nsAString& aStr) const { diff --git a/content/base/src/nsGenericDOMDataNode.h b/content/base/src/nsGenericDOMDataNode.h index dedcbcd51c9..e076d48b1ed 100644 --- a/content/base/src/nsGenericDOMDataNode.h +++ b/content/base/src/nsGenericDOMDataNode.h @@ -195,7 +195,9 @@ public: virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, PRBool aNullParent = PR_TRUE); - virtual nsIAtom *GetIDAttributeName() const; + virtual nsIAtom *GetIDAttributeName(PRInt32& aNamespaceId) const; + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const; virtual already_AddRefed GetExistingAttrNameFromQName(const nsAString& aStr) const; nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 92044c5a8df..d6b8b9f3d4c 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -2260,9 +2260,10 @@ nsGenericElement::DispatchDOMEvent(nsEvent* aEvent, nsIAtom* nsGenericElement::GetID() const { - nsIAtom* IDName = GetIDAttributeName(); + PRInt32 namespaceID; + nsIAtom* IDName = GetIDAttributeName(namespaceID); if (IDName) { - const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(IDName); + const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(IDName, namespaceID); if (attrVal){ if (attrVal->Type() == nsAttrValue::eAtom) { return attrVal->GetAtomValue(); @@ -2325,9 +2326,26 @@ nsGenericElement::GetAttributeChangeHint(const nsIAtom* aAttribute, } nsIAtom * -nsGenericElement::GetIDAttributeName() const +nsGenericElement::GetIDAttributeName(PRInt32& aNameSpaceID) const { - return mNodeInfo->GetIDAttributeAtom(); + aNameSpaceID = kNameSpaceID_None; + nsIAtom* idAtom = mNodeInfo->GetIDAttributeAtom(); + if (idAtom && HasAttr(aNameSpaceID, idAtom)) { + return idAtom; + } + + aNameSpaceID = kNameSpaceID_XML; + return nsGkAtoms::id; +} + +PRBool +nsGenericElement::IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const +{ + return (aNameSpaceID == kNameSpaceID_None && + aAtom == mNodeInfo->GetIDAttributeAtom()) || + (aNameSpaceID == kNameSpaceID_XML && + aAtom == nsGkAtoms::id); } nsIAtom * @@ -3652,8 +3670,8 @@ nsGenericElement::ParseAttribute(PRInt32 aNamespaceID, const nsAString& aValue, nsAttrValue& aResult) { - if (aNamespaceID == kNameSpaceID_None && - aAttribute == GetIDAttributeName() && !aValue.IsEmpty()) { + if (IsPotentialIDAttributeName(aNamespaceID, aAttribute) && + !aValue.IsEmpty()) { // Store id as an atom. id="" means that the element has no id, // not that it has an emptystring as the id. aResult.ParseAtom(aValue); diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index 3b8c9b835d5..61bfea5e020 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -383,7 +383,9 @@ public: PRBool aCompileEventHandlers); virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, PRBool aNullParent = PR_TRUE); - virtual nsIAtom *GetIDAttributeName() const; + virtual nsIAtom *GetIDAttributeName(PRInt32& aNameSpaceID) const; + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const; virtual nsIAtom *GetClassAttributeName() const; virtual already_AddRefed GetExistingAttrNameFromQName(const nsAString& aStr) const; nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, diff --git a/content/events/src/nsXMLEventsElement.cpp b/content/events/src/nsXMLEventsElement.cpp index 37c07a419d7..4c850345913 100644 --- a/content/events/src/nsXMLEventsElement.cpp +++ b/content/events/src/nsXMLEventsElement.cpp @@ -46,7 +46,9 @@ public: virtual ~nsXMLEventsElement(); NS_FORWARD_NSIDOMNODE(nsXMLElement::) - virtual nsIAtom *GetIDAttributeName() const; + virtual nsIAtom *GetIDAttributeName(PRInt32& aNameSpaceID) const; + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const; virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, PRBool aNotify); @@ -63,11 +65,21 @@ nsXMLEventsElement::~nsXMLEventsElement() } nsIAtom * -nsXMLEventsElement::GetIDAttributeName() const +nsXMLEventsElement::GetIDAttributeName(PRInt32& aNameSpaceID) const { - if (mNodeInfo->Equals(nsGkAtoms::listener)) + if (HasAttr(kNameSpaceID_None, nsGkAtoms::id)) { + aNameSpaceID = kNameSpaceID_None; return nsGkAtoms::id; - return nsXMLElement::GetIDAttributeName(); + } + return nsGenericElement::GetIDAttributeName(aNameSpaceID); +} + +PRBool +nsXMLEventsElement::IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const +{ + return (aNameSpaceID == kNameSpaceID_None && aAtom == nsGkAtoms::id) || + nsGenericElement::IsPotentialIDAttributeName(aNameSpaceID, aAtom); } nsresult diff --git a/content/events/src/nsXMLEventsManager.cpp b/content/events/src/nsXMLEventsManager.cpp index 0924f30b2a3..f17cbcd1109 100644 --- a/content/events/src/nsXMLEventsManager.cpp +++ b/content/events/src/nsXMLEventsManager.cpp @@ -377,20 +377,11 @@ nsXMLEventsManager::AttributeChanged(nsIDocument* aDocument, AddXMLEventsContent(aContent); nsXMLEventsListener::InitXMLEventsListener(aDocument, this, aContent); } - else if (aContent->GetIDAttributeName() == aAttribute) { - if (aModType == nsIDOMMutationEvent::REMOVAL) - mListeners.Enumerate(EnumAndSetIncomplete, aContent); - else if (aModType == nsIDOMMutationEvent::MODIFICATION) { - //Remove possible listener - mListeners.Enumerate(EnumAndSetIncomplete, aContent); - //Add new listeners - AddListeners(aDocument); - } - else { - //If we are adding the ID attribute, we must check whether we can - //add new listeners - AddListeners(aDocument); - } + else if (aContent->IsPotentialIDAttributeName(aNameSpaceID, aAttribute)) { + //Remove possible listener + mListeners.Enumerate(EnumAndSetIncomplete, aContent); + //Add new listeners + AddListeners(aDocument); } } } diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 63ff13081bb..f0eebb8fb77 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -1493,9 +1493,21 @@ nsGenericHTMLElement::GetClasses() const } nsIAtom * -nsGenericHTMLElement::GetIDAttributeName() const +nsGenericHTMLElement::GetIDAttributeName(PRInt32& aNameSpaceID) const { - return nsGkAtoms::id; + if (HasAttr(kNameSpaceID_None, nsGkAtoms::id)) { + aNameSpaceID = kNameSpaceID_None; + return nsGkAtoms::id; + } + return nsGenericElement::GetIDAttributeName(aNameSpaceID); +} + +PRBool +nsGenericHTMLElement::IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const +{ + return (aNameSpaceID == kNameSpaceID_None && aAtom == nsGkAtoms::id) || + nsGenericElement::IsPotentialIDAttributeName(aNameSpaceID, aAtom); } nsIAtom * diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 8a6c0cb8f91..63d05800cb1 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -241,7 +241,9 @@ public: virtual void UpdateEditableState(); virtual const nsAttrValue* GetClasses() const; - virtual nsIAtom *GetIDAttributeName() const; + virtual nsIAtom *GetIDAttributeName(PRInt32& aNameSpaceID) const; + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const; virtual nsIAtom *GetClassAttributeName() const; NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); virtual nsICSSStyleRule* GetInlineStyleRule(); diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 032b30f2f3c..6dc67af4c6d 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -1376,8 +1376,7 @@ nsHTMLDocument::AttributeWillChange(nsIContent* aContent, PRInt32 aNameSpaceID, return; } } - } else if (aAttribute == aContent->GetIDAttributeName() && - aNameSpaceID == kNameSpaceID_None) { + } else if (aContent->IsPotentialIDAttributeName(aNameSpaceID, aAttribute)) { nsresult rv = RemoveFromIdTable(aContent); if (NS_FAILED(rv)) { @@ -1406,8 +1405,7 @@ nsHTMLDocument::AttributeChanged(nsIDocument* aDocument, if (name) { UpdateNameTableEntry(name, aContent); } - } else if (aAttribute == aContent->GetIDAttributeName() && - aNameSpaceID == kNameSpaceID_None) { + } else if (aContent->IsPotentialIDAttributeName(aNameSpaceID, aAttribute)) { nsIAtom* id = aContent->GetID(); if (id) { UpdateIdTableEntry(id, aContent); diff --git a/content/svg/content/src/nsSVGElement.cpp b/content/svg/content/src/nsSVGElement.cpp index 247f376d4bc..1fcca6bc4b8 100644 --- a/content/svg/content/src/nsSVGElement.cpp +++ b/content/svg/content/src/nsSVGElement.cpp @@ -126,10 +126,22 @@ NS_INTERFACE_MAP_END_INHERITING(nsGenericElement) //---------------------------------------------------------------------- // nsIContent methods -nsIAtom * -nsSVGElement::GetIDAttributeName() const +nsIAtom* +nsSVGElement::GetIDAttributeName(PRInt32& aNameSpaceID) const { - return nsGkAtoms::id; + if (HasAttr(kNameSpaceID_None, nsGkAtoms::id)) { + aNameSpaceID = kNameSpaceID_None; + return nsGkAtoms::id; + } + return nsGenericElement::GetIDAttributeName(aNameSpaceID); +} + +PRBool +nsSVGElement::IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const +{ + return (aNameSpaceID == kNameSpaceID_None && aAtom == nsGkAtoms::id) || + nsGenericElement::IsPotentialIDAttributeName(aNameSpaceID, aAtom); } nsIAtom * diff --git a/content/svg/content/src/nsSVGElement.h b/content/svg/content/src/nsSVGElement.h index c7c31416867..9db34f2f55c 100644 --- a/content/svg/content/src/nsSVGElement.h +++ b/content/svg/content/src/nsSVGElement.h @@ -71,7 +71,9 @@ public: // nsIContent interface methods - virtual nsIAtom *GetIDAttributeName() const; + virtual nsIAtom *GetIDAttributeName(PRInt32& aNameSpaceID) const; + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const; virtual nsIAtom *GetClassAttributeName() const; virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRBool aNotify); diff --git a/content/xtf/src/nsXTFElementWrapper.cpp b/content/xtf/src/nsXTFElementWrapper.cpp index 9fdeb951713..638d7d8f8d8 100644 --- a/content/xtf/src/nsXTFElementWrapper.cpp +++ b/content/xtf/src/nsXTFElementWrapper.cpp @@ -265,10 +265,21 @@ nsXTFElementWrapper::RemoveChildAt(PRUint32 aIndex, PRBool aNotify) } nsIAtom * -nsXTFElementWrapper::GetIDAttributeName() const +nsXTFElementWrapper::GetIDAttributeName(PRInt32& aNameSpaceID) const { - // XXX: - return nsGkAtoms::id; + if (HasAttr(kNameSpaceID_None, nsGkAtoms::id)) { + aNameSpaceID = kNameSpaceID_None; + return nsGkAtoms::id; + } + return nsXTFElementWrapperBase::GetIDAttributeName(aNameSpaceID); +} + +PRBool +nsXTFElementWrapper::IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const +{ + return (aNameSpaceID == kNameSpaceID_None && aAtom == nsGkAtoms::id) || + nsXTFElementWrapperBase::IsPotentialIDAttributeName(aNameSpaceID, aAtom); } nsresult diff --git a/content/xtf/src/nsXTFElementWrapper.h b/content/xtf/src/nsXTFElementWrapper.h index b85fae77736..3001ffcc2b1 100644 --- a/content/xtf/src/nsXTFElementWrapper.h +++ b/content/xtf/src/nsXTFElementWrapper.h @@ -78,7 +78,9 @@ public: nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify); nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify); - nsIAtom *GetIDAttributeName() const; + virtual nsIAtom *GetIDAttributeName(PRInt32& aNameSpaceID) const; + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const; nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, PRBool aNotify); diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 770477b2532..5f3e842a80a 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -1633,7 +1633,9 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify) nsIAtom* nsXULElement::GetID() const { - const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::id); + PRInt32 namespaceID; + nsIAtom* IDName = GetIDAttributeName(namespaceID); + const nsAttrValue* attrVal = FindLocalOrProtoAttr(namespaceID, IDName); NS_ASSERTION(!attrVal || attrVal->Type() == nsAttrValue::eAtom || @@ -1739,9 +1741,21 @@ nsXULElement::IsAttributeMapped(const nsIAtom* aAttribute) const } nsIAtom * -nsXULElement::GetIDAttributeName() const +nsXULElement::GetIDAttributeName(PRInt32& aNameSpaceID) const { + if (HasAttr(kNameSpaceID_None, nsGkAtoms::id)) { + aNameSpaceID = kNameSpaceID_None; return nsGkAtoms::id; + } + return nsGenericElement::GetIDAttributeName(aNameSpaceID); +} + +PRBool +nsXULElement::IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const +{ + return (aNameSpaceID == kNameSpaceID_None && aAtom == nsGkAtoms::id) || + nsGenericElement::IsPotentialIDAttributeName(aNameSpaceID, aAtom); } nsIAtom * diff --git a/content/xul/content/src/nsXULElement.h b/content/xul/content/src/nsXULElement.h index 3da3a6dea12..75193ac4eff 100644 --- a/content/xul/content/src/nsXULElement.h +++ b/content/xul/content/src/nsXULElement.h @@ -505,7 +505,9 @@ public: virtual void UnbindFromTree(PRBool aDeep, PRBool aNullParent); virtual void SetNativeAnonymous(PRBool aAnonymous); virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify); - virtual nsIAtom *GetIDAttributeName() const; + virtual nsIAtom *GetIDAttributeName(PRInt32& aNameSpaceID) const; + virtual PRBool IsPotentialIDAttributeName(PRInt32 aNameSpaceID, + nsIAtom* aAtom) const; virtual nsIAtom *GetClassAttributeName() const; virtual PRBool GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsAString& aResult) const; diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index 88de793d1e4..5f422e1fc23 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -929,7 +929,8 @@ nsXULDocument::AttributeChanged(nsIDocument* aDocument, // XXXbz check aNameSpaceID, dammit! // First see if we need to update our element map. - if ((aAttribute == nsGkAtoms::id) || (aAttribute == nsGkAtoms::ref)) { + if (aElement->IsPotentialIDAttributeName(aNameSpaceID, aAttribute) || + (aAttribute == nsGkAtoms::ref && aNameSpaceID == kNameSpaceID_None)) { rv = mElementMap.Enumerate(RemoveElementsFromMapByContent, aElement); if (NS_FAILED(rv)) return; @@ -1757,31 +1758,29 @@ nsXULDocument::GetTemplateBuilderFor(nsIContent* aContent, return NS_OK; } -// Attributes that are used with getElementById() and the -// resource-to-element map. -nsIAtom** nsXULDocument::kIdentityAttrs[] = -{ - &nsGkAtoms::id, - &nsGkAtoms::ref, - nsnull -}; - nsresult nsXULDocument::AddElementToMap(nsIContent* aElement) { - // Look at the element's 'id' and 'ref' attributes, and if set, + // Look at the element's ID and 'ref' attributes, and if set, // add pointers in the resource-to-element map to the element. nsresult rv; - - for (PRInt32 i = 0; kIdentityAttrs[i] != nsnull; ++i) { - nsAutoString value; - aElement->GetAttr(kNameSpaceID_None, *kIdentityAttrs[i], value); - if (!value.IsEmpty()) { - rv = mElementMap.Add(value, aElement); - if (NS_FAILED(rv)) return rv; + nsIAtom* idAtom = aElement->GetID(); + if (idAtom) { + nsAutoString idStr; + idAtom->ToString(idStr); + if (!idStr.IsEmpty()) { + rv = mElementMap.Add(idStr, aElement); + NS_ENSURE_SUCCESS(rv, rv); } } + nsAutoString refvalue; + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, refvalue); + if (!refvalue.IsEmpty()) { + rv = mElementMap.Add(refvalue, aElement); + NS_ENSURE_SUCCESS(rv, rv); + } + return NS_OK; } @@ -1791,16 +1790,23 @@ nsXULDocument::RemoveElementFromMap(nsIContent* aElement) { // Remove the element from the resource-to-element map. nsresult rv; - - for (PRInt32 i = 0; kIdentityAttrs[i] != nsnull; ++i) { - nsAutoString value; - aElement->GetAttr(kNameSpaceID_None, *kIdentityAttrs[i], value); - if (!value.IsEmpty()) { - rv = mElementMap.Remove(value, aElement); - if (NS_FAILED(rv)) return rv; + nsIAtom* idAtom = aElement->GetID(); + if (idAtom) { + nsAutoString idStr; + idAtom->ToString(idStr); + if (!idStr.IsEmpty()) { + rv = mElementMap.Remove(idStr, aElement); + NS_ENSURE_SUCCESS(rv, rv); } } + nsAutoString refvalue; + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, refvalue); + if (!refvalue.IsEmpty()) { + rv = mElementMap.Remove(refvalue, aElement); + NS_ENSURE_SUCCESS(rv, rv); + } + return NS_OK; } diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index e65a9ab2bcf..e5f18c4e0f2 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -10128,7 +10128,8 @@ nsCSSFrameConstructor::AttributeChanged(nsIContent* aContent, #endif // the style tag has its own interpretation based on aHint - nsChangeHint hint = aContent->GetAttributeChangeHint(aAttribute, aModType); + nsChangeHint hint = (aNameSpaceID == kNameSpaceID_None) + ? aContent->GetAttributeChangeHint(aAttribute, aModType) : nsChangeHint(0); PRBool reframe = (hint & nsChangeHint_ReconstructFrame) != 0; @@ -10163,15 +10164,19 @@ nsCSSFrameConstructor::AttributeChanged(nsIContent* aContent, if (primaryFrame) { // See if we have appearance information for a theme. - const nsStyleDisplay* disp = primaryFrame->GetStyleDisplay(); - if (disp->mAppearance) { - nsPresContext* presContext = mPresShell->GetPresContext(); - nsITheme *theme = presContext->GetTheme(); - if (theme && theme->ThemeSupportsWidget(presContext, primaryFrame, disp->mAppearance)) { - PRBool repaint = PR_FALSE; - theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute, &repaint); - if (repaint) - NS_UpdateHint(hint, nsChangeHint_RepaintFrame); + if (aNameSpaceID == kNameSpaceID_None) { + const nsStyleDisplay* disp = primaryFrame->GetStyleDisplay(); + if (disp->mAppearance) { + nsPresContext* presContext = mPresShell->GetPresContext(); + nsITheme *theme = presContext->GetTheme(); + if (theme && theme->ThemeSupportsWidget(presContext, primaryFrame, + disp->mAppearance)) { + PRBool repaint = PR_FALSE; + theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute, + &repaint); + if (repaint) + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); + } } } @@ -10188,6 +10193,7 @@ nsCSSFrameConstructor::AttributeChanged(nsIContent* aContent, // the frame's AttributeChanged() in case it does something that affects the style nsFrameManager *frameManager = shell->FrameManager(); nsReStyleHint rshint = frameManager->HasAttributeDependentStyle(aContent, + aNameSpaceID, aAttribute, aModType, aStateMask); diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp index c1e0a2e870a..76fcd07c996 100644 --- a/layout/base/nsFrameManager.cpp +++ b/layout/base/nsFrameManager.cpp @@ -1445,12 +1445,14 @@ nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame, nsReStyleHint nsFrameManager::HasAttributeDependentStyle(nsIContent *aContent, + PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType, PRUint32 aStateMask) { nsReStyleHint hint = mStyleSet->HasAttributeDependentStyle(GetPresContext(), aContent, + aNameSpaceID, aAttribute, aModType, aStateMask); diff --git a/layout/base/nsFrameManager.h b/layout/base/nsFrameManager.h index 31cd2cc2688..556d4c6e8ec 100644 --- a/layout/base/nsFrameManager.h +++ b/layout/base/nsFrameManager.h @@ -191,6 +191,7 @@ public: // Determine whether an attribute affects style NS_HIDDEN_(nsReStyleHint) HasAttributeDependentStyle(nsIContent *aContent, + PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType, PRUint32 aStateMask); diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index fe360c931f7..15cb92d4115 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1001,6 +1001,8 @@ static PRBool AttrMatchesValue(const nsAttrSelector* aAttrSelector, static PRBool SelectorMatches(RuleProcessorData &data, nsCSSSelector* aSelector, PRInt32 aStateMask, // states NOT to test + PRInt32 aNameSpaceID, // the namespace of the + // attribute NOT to test nsIAtom* aAttribute, // attribute NOT to test PRBool* const aDependence = nsnull) @@ -1322,9 +1324,9 @@ static PRBool SelectorMatches(RuleProcessorData &data, result = PR_TRUE; nsAttrSelector* attr = aSelector->mAttrList; do { - if (attr->mAttr == aAttribute) { - // XXX we should really have a namespace, not just an attr - // name, in HasAttributeDependentStyle! + if (attr->mAttr == aAttribute && + (attr->mNameSpace == aNameSpaceID || + attr->mNameSpace == kNameSpaceID_Unknown)) { result = PR_TRUE; if (aDependence) *aDependence = PR_TRUE; @@ -1396,8 +1398,9 @@ static PRBool SelectorMatches(RuleProcessorData &data, if (result && IDList) { // test for ID match result = PR_FALSE; - - if (aAttribute && aAttribute == data.mContent->GetIDAttributeName()) { + PRInt32 namespaceID; + if (aAttribute && + data.mContent->IsPotentialIDAttributeName(namespaceID, aAttribute)) { result = PR_TRUE; if (aDependence) *aDependence = PR_TRUE; @@ -1435,7 +1438,8 @@ static PRBool SelectorMatches(RuleProcessorData &data, if (result && aSelector->mClassList) { // test for class match - if (aAttribute && aAttribute == data.mContent->GetClassAttributeName()) { + if (aAttribute && aAttribute == data.mContent->GetClassAttributeName() && + aNameSpaceID == kNameSpaceID_None) { result = PR_TRUE; if (aDependence) *aDependence = PR_TRUE; @@ -1462,7 +1466,7 @@ static PRBool SelectorMatches(RuleProcessorData &data, for (nsCSSSelector *negation = aSelector->mNegations; result && negation; negation = negation->mNegations) { PRBool dependence = PR_FALSE; - result = !SelectorMatches(data, negation, aStateMask, + result = !SelectorMatches(data, negation, aStateMask, aNameSpaceID, aAttribute, &dependence); // If the selector does match due to the dependence on aStateMask // or aAttribute, then we want to keep result true so that the @@ -1536,7 +1540,7 @@ static PRBool SelectorMatchesTree(RuleProcessorData& aPrevData, if (! data) { return PR_FALSE; } - if (SelectorMatches(*data, selector, 0, nsnull)) { + if (SelectorMatches(*data, selector, 0, kNameSpaceID_Unknown, nsnull)) { // to avoid greedy matching, we need to recur if this is a // descendant combinator and the next combinator is not if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) && @@ -1573,7 +1577,7 @@ static void ContentEnumFunc(nsICSSStyleRule* aRule, nsCSSSelector* aSelector, { ElementRuleProcessorData* data = (ElementRuleProcessorData*)aData; - if (SelectorMatches(*data, aSelector, 0, nsnull)) { + if (SelectorMatches(*data, aSelector, 0, kNameSpaceID_Unknown, nsnull)) { nsCSSSelector *next = aSelector->mNext; if (!next || SelectorMatchesTree(*data, next)) { // for performance, require that every implementation of @@ -1626,7 +1630,7 @@ static void PseudoEnumFunc(nsICSSStyleRule* aRule, nsCSSSelector* aSelector, if (PRUnichar('+') == selector->mOperator) { return; // not valid here, can't match } - if (SelectorMatches(*data, selector, 0, nsnull)) { + if (SelectorMatches(*data, selector, 0, kNameSpaceID_Unknown, nsnull)) { selector = selector->mNext; } else { @@ -1697,7 +1701,8 @@ PR_STATIC_CALLBACK(PRBool) StateEnumFunc(void* aSelector, void* aData) // bother calling SelectorMatches, since even if it returns false // enumData->change won't change. if ((possibleChange & ~(enumData->change)) && - SelectorMatches(*data, selector, data->mStateMask, nsnull) && + SelectorMatches(*data, selector, data->mStateMask, kNameSpaceID_Unknown, + nsnull) && SelectorMatchesTree(*data, selector->mNext)) { enumData->change = nsReStyleHint(enumData->change | possibleChange); } @@ -1751,7 +1756,8 @@ PR_STATIC_CALLBACK(PRBool) AttributeEnumFunc(void* aSelector, void* aData) // bother calling SelectorMatches, since even if it returns false // enumData->change won't change. if ((possibleChange & ~(enumData->change)) && - SelectorMatches(*data, selector, data->mStateMask, data->mAttribute) && + SelectorMatches(*data, selector, data->mStateMask, data->mNameSpaceID, + data->mAttribute) && SelectorMatchesTree(*data, selector->mNext)) { enumData->change = nsReStyleHint(enumData->change | possibleChange); } @@ -1772,6 +1778,7 @@ nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData // and :visited rules from prefs), rather than hacking AddRule below // to add |href| to the hash, we'll just handle it here. if (aData->mAttribute == nsGkAtoms::href && + aData->mNameSpaceID == kNameSpaceID_None && aData->mIsHTMLContent && (aData->mContentTag == nsGkAtoms::a || aData->mContentTag == nsGkAtoms::area || @@ -1789,11 +1796,13 @@ nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData // we have a hashtable with a per-attribute list. if (cascade) { - if (aData->mAttribute == aData->mContent->GetIDAttributeName()) { + if (aData->mContent->IsPotentialIDAttributeName(aData->mNameSpaceID, + aData->mAttribute)) { cascade->mIDSelectors.EnumerateForwards(AttributeEnumFunc, &data); } - if (aData->mAttribute == aData->mContent->GetClassAttributeName()) { + if (aData->mNameSpaceID == kNameSpaceID_None && + aData->mAttribute == aData->mContent->GetClassAttributeName()) { cascade->mClassSelectors.EnumerateForwards(AttributeEnumFunc, &data); } diff --git a/layout/style/nsIStyleRuleProcessor.h b/layout/style/nsIStyleRuleProcessor.h index e0224d6f40c..6569470f701 100644 --- a/layout/style/nsIStyleRuleProcessor.h +++ b/layout/style/nsIStyleRuleProcessor.h @@ -153,19 +153,24 @@ struct StateRuleProcessorData : public RuleProcessorData { struct AttributeRuleProcessorData : public RuleProcessorData { AttributeRuleProcessorData(nsPresContext* aPresContext, nsIContent* aContent, + PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType, PRUint32 aStateMask) : RuleProcessorData(aPresContext, aContent, nsnull), + mNameSpaceID(aNameSpaceID), mAttribute(aAttribute), mModType(aModType), mStateMask(aStateMask) { NS_PRECONDITION(aContent, "null pointer"); } - nsIAtom* mAttribute; // |HasAttributeDependentStyle| for which attribute? - PRInt32 mModType; // The type of modification (see nsIDOMMutationEvent). - PRUint32 mStateMask; // The states that changed with the attr change. + // |HasAttributeDependentStyle| for which attribute? + PRInt32 mNameSpaceID; + nsIAtom* mAttribute; + + PRInt32 mModType; // The type of modification (see nsIDOMMutationEvent). + PRUint32 mStateMask; // The states that changed with the attr change. }; diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 3c21988e503..35133d96c5b 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -959,10 +959,10 @@ nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext, struct AttributeData : public AttributeRuleProcessorData { AttributeData(nsPresContext* aPresContext, - nsIContent* aContent, nsIAtom* aAttribute, PRInt32 aModType, - PRUint32 aStateMask) - : AttributeRuleProcessorData(aPresContext, aContent, aAttribute, aModType, - aStateMask), + nsIContent* aContent, PRInt32 aNameSpaceID, + nsIAtom* aAttribute, PRInt32 aModType, PRUint32 aStateMask) + : AttributeRuleProcessorData(aPresContext, aContent, aNameSpaceID, + aAttribute, aModType, aStateMask), mHint(nsReStyleHint(0)) {} nsReStyleHint mHint; @@ -982,6 +982,7 @@ SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData) nsReStyleHint nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext, nsIContent* aContent, + PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType, PRUint32 aStateMask) @@ -996,8 +997,8 @@ nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext, mRuleProcessors[eDocSheet] || mRuleProcessors[eStyleAttrSheet] || mRuleProcessors[eOverrideSheet])) { - AttributeData data(aPresContext, aContent, aAttribute, aModType, - aStateMask); + AttributeData data(aPresContext, aContent, aNameSpaceID, aAttribute, + aModType, aStateMask); WalkRuleProcessors(SheetHasAttributeStyle, &data); result = data.mHint; } diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 69bb6dc6af1..bbd8992fc72 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -139,6 +139,7 @@ class nsStyleSet // Test if style is dependent on the presence of an attribute. nsReStyleHint HasAttributeDependentStyle(nsPresContext* aPresContext, nsIContent* aContent, + PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType, PRUint32 aStateMask); diff --git a/layout/style/test/Makefile.in b/layout/style/test/Makefile.in index c9dc3ac1dbf..c7fada50039 100644 --- a/layout/style/test/Makefile.in +++ b/layout/style/test/Makefile.in @@ -68,6 +68,7 @@ css_properties.js: host_ListCSSProperties$(HOST_BIN_SUFFIX) css_properties_like_ _TEST_FILES = test_bug74880.html \ test_bug221428.html \ + test_bug275196.xhtml \ test_bug302186.html \ test_bug319381.html \ test_bug357614.html \ diff --git a/layout/style/test/test_bug275196.xhtml b/layout/style/test/test_bug275196.xhtml new file mode 100644 index 00000000000..747afa7692f --- /dev/null +++ b/layout/style/test/test_bug275196.xhtml @@ -0,0 +1,149 @@ + + + + + Test for Bug 275196 + + + + + + +Mozilla Bug 275196 +

+
+
Element in XHTML namespace, attribute in null namespace
+
Element in XHTML namespace, attribute in foo namespace
+ Element in foo namespace, attribute in foo namespace +
Element in XHTML namespace, id attribute
+ Element in foo namespace, xml:id attribute +
+
+
+
+ + +