Implement an AttrValueIs method on nsIContent which can be used to quickly

check whether a given attribute has a given value.  Use it in
nsContentList::NamedItem.  Bug 307600, r+sr=jst
This commit is contained in:
bzbarsky%mit.edu 2005-09-11 19:20:08 +00:00
parent 524307e362
commit 81a57e27f2
7 changed files with 203 additions and 13 deletions

View File

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Boris Zbarsky <bzbarsky@mit.edu> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsCaseTreatment_h___
#define nsCaseTreatment_h___
/**
* This is the enum used by functions that need to be told whether to
* do case-sensitive or case-insensitive string comparisons.
*/
enum nsCaseTreatment {
eCaseMatters,
eIgnoreCase
};
#endif /* nsCaseTreatment_h___ */

View File

@ -44,6 +44,7 @@
#include "nsAString.h"
#include "nsContentErrors.h"
#include "nsPropertyTable.h"
#include "nsCaseTreatment.h"
// Forward declarations
class nsIAtom;
@ -60,8 +61,8 @@ class nsIURI;
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0x3fecc374, 0x2839, 0x4db3, \
{ 0x8d, 0xe8, 0x6b, 0x76, 0xd1, 0xd8, 0xe6, 0xf6 } }
{ 0x66b01442, 0x75ed, 0x4605, \
{ 0x87, 0x06, 0x70, 0x22, 0x27, 0x9d, 0x19, 0x0b } }
/**
* A node of content in a document's content model. This interface
@ -327,6 +328,42 @@ public:
*/
virtual PRBool HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const = 0;
/**
* Test whether this content node's given attribute has the given value. If
* the attribute is not set at all, this will return false.
*
* @param aNameSpaceID The namespace ID of the attribute. Must not
* be kNameSpaceID_Unknown.
* @param aName The name atom of the attribute. Must not be null.
* @param aValue The value to compare to.
* @param aCaseSensitive Whether to do a case-sensitive compare on the value.
*/
virtual PRBool AttrValueIs(PRInt32 aNameSpaceID,
nsIAtom* aName,
const nsAString& aValue,
nsCaseTreatment aCaseSensitive) const
{
return PR_FALSE;
}
/**
* Test whether this content node's given attribute has the given value. If
* the attribute is not set at all, this will return false.
*
* @param aNameSpaceID The namespace ID of the attribute. Must not
* be kNameSpaceID_Unknown.
* @param aName The name atom of the attribute. Must not be null.
* @param aValue The value to compare to. Must not be null.
* @param aCaseSensitive Whether to do a case-sensitive compare on the value.
*/
virtual PRBool AttrValueIs(PRInt32 aNameSpaceID,
nsIAtom* aName,
nsIAtom* aValue,
nsCaseTreatment aCaseSensitive) const
{
return PR_FALSE;
}
/**
* Remove an attribute so that it is no longer explicitly specified.
*

View File

@ -608,6 +608,71 @@ nsAttrValue::Equals(const nsAttrValue& aOther) const
}
}
PRBool
nsAttrValue::Equals(const nsAString& aValue,
nsCaseTreatment aCaseSensitive) const
{
switch (BaseType()) {
case eStringBase:
{
nsStringBuffer* str = NS_STATIC_CAST(nsStringBuffer*, GetPtr());
if (str) {
nsDependentString dep(NS_STATIC_CAST(PRUnichar*, str->Data()),
str->StorageSize()/sizeof(PRUnichar) - 1);
return aCaseSensitive == eCaseMatters ? aValue.Equals(dep) :
aValue.Equals(dep, nsCaseInsensitiveStringComparator());
}
return aValue.IsEmpty();
}
case eAtomBase:
// Need a way to just do case-insensitive compares on atoms..
if (aCaseSensitive == eCaseMatters) {
return NS_STATIC_CAST(nsIAtom*, GetPtr())->Equals(aValue);;
}
default:
break;
}
nsAutoString val;
ToString(val);
return aCaseSensitive == eCaseMatters ? val.Equals(aValue) :
val.Equals(aValue, nsCaseInsensitiveStringComparator());
}
PRBool
nsAttrValue::Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
{
if (aCaseSensitive != eCaseMatters) {
// Need a better way to handle this!
nsAutoString value;
aValue->ToString(value);
return Equals(value, aCaseSensitive);
}
switch (BaseType()) {
case eStringBase:
{
nsStringBuffer* str = NS_STATIC_CAST(nsStringBuffer*, GetPtr());
if (str) {
nsDependentString dep(NS_STATIC_CAST(PRUnichar*, str->Data()),
str->StorageSize()/sizeof(PRUnichar) - 1);
return aValue->Equals(dep);
}
return aValue->EqualsUTF8(EmptyCString());
}
case eAtomBase:
{
return NS_STATIC_CAST(nsIAtom*, GetPtr()) == aValue;
}
default:
break;
}
nsAutoString val;
ToString(val);
return aValue->Equals(val);
}
void
nsAttrValue::ParseAtom(const nsAString& aValue)
{

View File

@ -44,6 +44,7 @@
#include "nsStringBuffer.h"
#include "nsColor.h"
#include "nsCOMArray.h"
#include "nsCaseTreatment.h"
typedef unsigned long PtrBits;
class nsAString;
@ -155,6 +156,8 @@ public:
PRUint32 HashValue() const;
PRBool Equals(const nsAttrValue& aOther) const;
PRBool Equals(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const;
PRBool Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const;
void ParseAtom(const nsAString& aValue);
void ParseAtomArray(const nsAString& aValue);

View File

@ -449,20 +449,22 @@ nsContentList::NamedItem(const nsAString& aName, PRBool aDoFlush)
PRInt32 i, count = mElements.Count();
// Typically IDs are atomized and names are not
// XXXbz this might change if we start atomizing more random attr
// values in HTML like we do in XUL!
nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
NS_ENSURE_TRUE(name, nsnull);
for (i = 0; i < count; i++) {
nsIContent *content = NS_STATIC_CAST(nsIContent *,
mElements.ElementAt(i));
if (content) {
nsAutoString name;
// XXX Should it be an EqualsIgnoreCase?
if (((content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::name,
name) == NS_CONTENT_ATTR_HAS_VALUE) &&
aName.Equals(name)) ||
((content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::id,
name) == NS_CONTENT_ATTR_HAS_VALUE) &&
aName.Equals(name))) {
return content;
}
// XXX Should this pass eIgnoreCase?
if (content &&
(content->AttrValueIs(kNameSpaceID_None, nsHTMLAtoms::name,
aName, eCaseMatters) ||
content->AttrValueIs(kNameSpaceID_None, nsHTMLAtoms::id,
name, eCaseMatters))) {
return content;
}
}

View File

@ -3691,6 +3691,33 @@ nsGenericElement::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const
return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
}
PRBool
nsGenericElement::AttrValueIs(PRInt32 aNameSpaceID,
nsIAtom* aName,
const nsAString& aValue,
nsCaseTreatment aCaseSensitive) const
{
NS_ASSERTION(aName, "Must have attr name");
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
return val && val->Equals(aValue, aCaseSensitive);
}
PRBool
nsGenericElement::AttrValueIs(PRInt32 aNameSpaceID,
nsIAtom* aName,
nsIAtom* aValue,
nsCaseTreatment aCaseSensitive) const
{
NS_ASSERTION(aName, "Must have attr name");
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
NS_ASSERTION(aValue, "Null value atom");
const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
return val && val->Equals(aValue, aCaseSensitive);
}
nsresult
nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
PRBool aNotify)

View File

@ -414,6 +414,12 @@ public:
virtual nsresult GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsAString& aResult) const;
virtual PRBool HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const;
virtual PRBool AttrValueIs(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue,
nsCaseTreatment aCaseSensitive) const;
virtual PRBool AttrValueIs(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aValue,
nsCaseTreatment aCaseSensitive) const;
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
PRBool aNotify);
virtual nsresult GetAttrNameAt(PRUint32 aIndex, PRInt32* aNameSpaceID,