mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 564569. Speed up the cache-hit case of getElementsBy(Class)Name. r=jst
This commit is contained in:
parent
6eadfd73c1
commit
2abd027435
@ -313,7 +313,7 @@ already_AddRefed<nsContentList>
|
||||
NS_GetFuncStringContentList(nsINode* aRootNode,
|
||||
nsContentListMatchFunc aFunc,
|
||||
nsContentListDestroyFunc aDestroyFunc,
|
||||
void* aData,
|
||||
nsFuncStringContentListDataAllocator aDataAllocator,
|
||||
const nsAString& aString)
|
||||
{
|
||||
NS_ASSERTION(aRootNode, "content list has to have a root");
|
||||
@ -361,7 +361,14 @@ NS_GetFuncStringContentList(nsINode* aRootNode,
|
||||
if (!list) {
|
||||
// We need to create a ContentList and add it to our new entry, if
|
||||
// we have an entry
|
||||
list = new nsCacheableFuncStringContentList(aRootNode, aFunc, aDestroyFunc, aData, aString);
|
||||
list = new nsCacheableFuncStringContentList(aRootNode, aFunc, aDestroyFunc,
|
||||
aDataAllocator, aString);
|
||||
if (list && !list->AllocatedData()) {
|
||||
// Failed to allocate the data
|
||||
delete list;
|
||||
list = nsnull;
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
if (list)
|
||||
entry->mContentList = list;
|
||||
@ -370,11 +377,6 @@ NS_GetFuncStringContentList(nsINode* aRootNode,
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(list, nsnull);
|
||||
} else {
|
||||
// List was already in the hashtable; clean up our new aData
|
||||
if (aDestroyFunc) {
|
||||
(*aDestroyFunc)(aData);
|
||||
}
|
||||
}
|
||||
|
||||
NS_ADDREF(list);
|
||||
|
@ -432,7 +432,7 @@ public:
|
||||
PRUint32 GetHash(void) const
|
||||
{
|
||||
return NS_PTR_TO_INT32(mRootNode) ^ (NS_PTR_TO_INT32(mFunc) << 12) ^
|
||||
nsCRT::HashCode(PromiseFlatString(mString).get());
|
||||
nsCRT::HashCode(mString.BeginReading(), mString.Length());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -443,16 +443,27 @@ private:
|
||||
const nsAString& mString;
|
||||
};
|
||||
|
||||
/**
|
||||
* A function that allocates the matching data for this
|
||||
* FuncStringContentList. Returning aString is perfectly fine; in
|
||||
* that case the destructor function should be a no-op.
|
||||
*/
|
||||
typedef void* (*nsFuncStringContentListDataAllocator)(nsINode* aRootNode,
|
||||
const nsString* aString);
|
||||
|
||||
// aDestroyFunc is allowed to be null
|
||||
class nsCacheableFuncStringContentList : public nsContentList {
|
||||
public:
|
||||
nsCacheableFuncStringContentList(nsINode* aRootNode,
|
||||
nsContentListMatchFunc aFunc,
|
||||
nsContentListDestroyFunc aDestroyFunc,
|
||||
void* aData,
|
||||
nsFuncStringContentListDataAllocator aDataAllocator,
|
||||
const nsAString& aString) :
|
||||
nsContentList(aRootNode, aFunc, aDestroyFunc, aData),
|
||||
nsContentList(aRootNode, aFunc, aDestroyFunc, nsnull),
|
||||
mString(aString)
|
||||
{}
|
||||
{
|
||||
mData = (*aDataAllocator)(aRootNode, &mString);
|
||||
}
|
||||
|
||||
virtual ~nsCacheableFuncStringContentList();
|
||||
|
||||
@ -460,6 +471,8 @@ public:
|
||||
return mRootNode == aKey->mRootNode && mFunc == aKey->mFunc &&
|
||||
mString == aKey->mString;
|
||||
}
|
||||
|
||||
PRBool AllocatedData() const { return !!mData; }
|
||||
protected:
|
||||
virtual void RemoveFromCaches() {
|
||||
RemoveFromFuncStringHashtable();
|
||||
@ -477,6 +490,6 @@ already_AddRefed<nsContentList>
|
||||
NS_GetFuncStringContentList(nsINode* aRootNode,
|
||||
nsContentListMatchFunc aFunc,
|
||||
nsContentListDestroyFunc aDestroyFunc,
|
||||
void* aData,
|
||||
nsFuncStringContentListDataAllocator aDataAllocator,
|
||||
const nsAString& aString);
|
||||
#endif // nsContentList_h___
|
||||
|
@ -5784,6 +5784,10 @@ MatchClassNames(nsIContent* aContent, PRInt32 aNamespaceID, nsIAtom* aAtom,
|
||||
// need to match *all* of the classes
|
||||
ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
|
||||
PRInt32 length = info->mClasses.Count();
|
||||
if (!length) {
|
||||
// If we actually had no classes, don't match.
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRInt32 i;
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (!classAttr->Contains(info->mClasses.ObjectAt(i),
|
||||
@ -5802,19 +5806,15 @@ DestroyClassNameArray(void* aData)
|
||||
delete info;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsContentUtils::GetElementsByClassName(nsINode* aRootNode,
|
||||
const nsAString& aClasses,
|
||||
nsIDOMNodeList** aReturn)
|
||||
static void*
|
||||
AllocClassMatchingInfo(nsINode* aRootNode,
|
||||
const nsString* aClasses)
|
||||
{
|
||||
NS_PRECONDITION(aRootNode, "Must have root node");
|
||||
|
||||
nsAttrValue attrValue;
|
||||
attrValue.ParseAtomArray(aClasses);
|
||||
attrValue.ParseAtomArray(*aClasses);
|
||||
// nsAttrValue::Equals is sensitive to order, so we'll send an array
|
||||
ClassMatchingInfo* info = new ClassMatchingInfo;
|
||||
NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ENSURE_TRUE(info, nsnull);
|
||||
|
||||
if (attrValue.Type() == nsAttrValue::eAtomArray) {
|
||||
info->mClasses.AppendObjects(*(attrValue.GetAtomArrayValue()));
|
||||
@ -5822,27 +5822,27 @@ nsContentUtils::GetElementsByClassName(nsINode* aRootNode,
|
||||
info->mClasses.AppendObject(attrValue.GetAtomValue());
|
||||
}
|
||||
|
||||
nsBaseContentList* elements;
|
||||
if (info->mClasses.Count() > 0) {
|
||||
info->mCaseTreatment =
|
||||
aRootNode->GetOwnerDoc()->GetCompatibilityMode() ==
|
||||
eCompatibility_NavQuirks ?
|
||||
eIgnoreCase : eCaseMatters;
|
||||
info->mCaseTreatment =
|
||||
aRootNode->GetOwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks ?
|
||||
eIgnoreCase : eCaseMatters;
|
||||
return info;
|
||||
}
|
||||
|
||||
elements =
|
||||
NS_GetFuncStringContentList(aRootNode, MatchClassNames,
|
||||
DestroyClassNameArray, info,
|
||||
aClasses).get();
|
||||
} else {
|
||||
delete info;
|
||||
info = nsnull;
|
||||
elements = new nsBaseContentList();
|
||||
NS_IF_ADDREF(elements);
|
||||
}
|
||||
if (!elements) {
|
||||
delete info;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
// static
|
||||
|
||||
nsresult
|
||||
nsContentUtils::GetElementsByClassName(nsINode* aRootNode,
|
||||
const nsAString& aClasses,
|
||||
nsIDOMNodeList** aReturn)
|
||||
{
|
||||
NS_PRECONDITION(aRootNode, "Must have root node");
|
||||
|
||||
nsContentList* elements =
|
||||
NS_GetFuncStringContentList(aRootNode, MatchClassNames,
|
||||
DestroyClassNameArray,
|
||||
AllocClassMatchingInfo,
|
||||
aClasses).get();
|
||||
NS_ENSURE_TRUE(elements, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Transfer ownership
|
||||
*aReturn = elements;
|
||||
|
@ -2291,6 +2291,13 @@ nsHTMLDocument::MatchNameAttribute(nsIContent* aContent, PRInt32 aNamespaceID,
|
||||
*elementName, eCaseMatters);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void*
|
||||
nsHTMLDocument::UseExistingNameString(nsINode* aRootNode, const nsString* aName)
|
||||
{
|
||||
return const_cast<nsString*>(aName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLDocument::GetElementsByName(const nsAString& aElementName,
|
||||
nsIDOMNodeList** aReturn)
|
||||
|
@ -163,13 +163,8 @@ public:
|
||||
nsIContent *GetBody(nsresult *aResult);
|
||||
already_AddRefed<nsContentList> GetElementsByName(const nsAString & aName)
|
||||
{
|
||||
nsString* elementNameData = new nsString(aName);
|
||||
|
||||
return NS_GetFuncStringContentList(this,
|
||||
MatchNameAttribute,
|
||||
nsContentUtils::DestroyMatchString,
|
||||
elementNameData,
|
||||
*elementNameData);
|
||||
return NS_GetFuncStringContentList(this, MatchNameAttribute, nsnull,
|
||||
UseExistingNameString, aName);
|
||||
}
|
||||
|
||||
// nsIDOMNSHTMLDocument interface
|
||||
@ -259,6 +254,7 @@ protected:
|
||||
nsIAtom* aAtom, void* aData);
|
||||
static PRBool MatchNameAttribute(nsIContent* aContent, PRInt32 aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData);
|
||||
static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName);
|
||||
|
||||
static void DocumentWriteTerminationFunc(nsISupports *aRef);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user