Bug 275196, xml:id, r=sicking, sr=dbaron

This commit is contained in:
Olli.Pettay@helsinki.fi 2007-07-26 05:22:01 -07:00
Родитель 91e8ee5011
Коммит 2bb3360e9f
27 изменённых файлов: 393 добавлений и 112 удалений

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

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

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

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

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

@ -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<nsINodeInfo>
nsGenericDOMDataNode::GetExistingAttrNameFromQName(const nsAString& aStr) const
{

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

@ -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<nsINodeInfo> GetExistingAttrNameFromQName(const nsAString& aStr) const;
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, PRBool aNotify)

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

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

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

@ -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<nsINodeInfo> GetExistingAttrNameFromQName(const nsAString& aStr) const;
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -0,0 +1,149 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:foo="http://example.org/2005/02/13/#foo"
xml:id="start">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=275196
-->
<head>
<title>Test for Bug 275196</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style type="text/css">
:root {
background: red;
}
:root#foo {
background: rgb(0, 255, 0);
}
:root#bar {
background: rgb(0, 0, 255);
}
*[*|green] {
background: rgb(0, 255, 0);
}
#xhtml3, #foo2 {
background: rgb(0, 255, 0);
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=275196">Mozilla Bug 275196</a>
<p id="display"></p>
<div id="content">
<div id="xhtml1" green="true">Element in XHTML namespace, attribute in null namespace</div>
<div id="xhtml2" foo:green="true">Element in XHTML namespace, attribute in foo namespace</div>
<foo:foo xml:id="foo1" foo:green="true">Element in foo namespace, attribute in foo namespace</foo:foo>
<div id="xhtml3">Element in XHTML namespace, id attribute</div>
<foo:foo xml:id="foo2">Element in foo namespace, xml:id attribute</foo:foo>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 275196 **/
// Test whether setting 'native' ID overrides xml:id
function test_1() {
try {
document.getElementById('start').setAttribute('id', 'bar');
} catch (e) {
ok(false, "Couldn't find element 'start'");
test_2();
return;
}
ok(document.defaultView.getComputedStyle(document.documentElement, null).
getPropertyValue('background-color') == "rgb(0, 0, 255)",
"The background of the documentElement should be blue.");
test_2();
}
// Test if ID 'start' was removed from the document when the ID was set to 'bar'.
function test_2() {
ok(document.getElementById('bar') != document.getElementById('start'),
"Element with ID 'bar' shouldn't be the same as 'start'");
test_3();
}
// Setting xml:id and removing 'native' ID
function test_3() {
var b = null;
try {
b = document.getElementById('bar');
b.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:id", "foo");
b.removeAttribute('id');
} catch (e) {
ok(false, e);
test_4();
return;
}
ok(document.defaultView.getComputedStyle(document.documentElement, null).
getPropertyValue('background-color') == "rgb(0, 255, 0)",
"The background of the documentElement should be green.");
test_4();
}
// Setting 'native' ID
function test_4() {
try {
document.getElementById('foo').setAttribute('id', 'bar');
} catch (e) {
ok(false, e);
test_5();
return;
}
ok(document.defaultView.getComputedStyle(document.documentElement, null).
getPropertyValue('background-color') == "rgb(0, 0, 255)",
"The background of the documentElement should be blue.");
test_5();
}
function testElementBackground(elementId) {
var el = document.getElementById(elementId);
ok(document.defaultView.getComputedStyle(el, null).
getPropertyValue('background-color') == "rgb(0, 255, 0)",
"The background of the element should be green.");
el.removeAttribute("green");
el.removeAttributeNS("http://example.org/2005/02/13/#foo", "green");
ok(document.defaultView.getComputedStyle(el, null).
getPropertyValue('background-color') == "transparent",
"The element should have transparent background.");
}
// Test *[*|green] style rule.
function test_5() {
testElementBackground("xhtml1");
testElementBackground("xhtml2");
testElementBackground("foo1");
test_6();
}
// Test #xhtml3, #foo2 style rule.
function test_6() {
var el = document.getElementById("xhtml3");
ok(document.defaultView.getComputedStyle(el, null).
getPropertyValue('background-color') == "rgb(0, 255, 0)",
"The background of the element should be green.");
el = document.getElementById("foo2");
ok(document.defaultView.getComputedStyle(el, null).
getPropertyValue('background-color') == "rgb(0, 255, 0)",
"The background of the element should be green.");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(test_1);
]]>
</script>
</pre>
</body>
</html>