Bug 573469 - part3, speed up HasRelatedContent, r=davidb, sr=neil, a=final+

This commit is contained in:
Alexander Surkov 2010-11-19 13:44:47 +08:00
parent cff1891508
commit 3f6f6cc71f
6 changed files with 118 additions and 28 deletions

View File

@ -844,15 +844,11 @@ static PRBool HasRelatedContent(nsIContent *aContent)
return PR_FALSE;
}
nsIAtom *relationAttrs[] = {nsAccessibilityAtoms::aria_labelledby,
nsAccessibilityAtoms::aria_describedby,
nsAccessibilityAtoms::aria_owns,
nsAccessibilityAtoms::aria_controls,
nsAccessibilityAtoms::aria_flowto};
if (nsCoreUtils::FindNeighbourPointingToNode(aContent, relationAttrs,
NS_ARRAY_LENGTH(relationAttrs))) {
// If the given ID is referred by relation attribute then create an accessible
// for it. Take care of HTML elements only for now.
if (aContent->IsHTML() &&
nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id))
return PR_TRUE;
}
nsIContent *ancestorContent = aContent;
while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {

View File

@ -3190,8 +3190,17 @@ nsAccessible::EnsureChildren()
// State is embedded children until text leaf accessible is appended.
mChildrenFlags = eEmbeddedChildren; // Prevent reentry
// Notify the document about caching status.
nsDocAccessible* document = GetDocAccessible();
if (document)
document->NotifyOfCachingStart(this);
CacheChildren();
if (document)
document->NotifyOfCachingEnd(this);
return PR_FALSE;
}

View File

@ -1152,25 +1152,29 @@ IDRefsIterator::NextElem()
if (id.IsEmpty())
break;
if (mXBLDocument) {
// If content is anonymous subtree then use "anonid" attribute to get
// elements, otherwise search elements in DOM by ID attribute.
nsCOMPtr<nsIDOMElement> refElm;
mXBLDocument->GetAnonymousElementByAttribute(mBindingParent,
NS_LITERAL_STRING("anonid"),
id,
getter_AddRefs(refElm));
nsCOMPtr<nsIContent> refContent = do_QueryInterface(refElm);
if (refContent)
return refContent;
} else {
nsIContent* refContent = mDocument->GetElementById(id);
if (refContent)
return refContent;
}
nsIContent* refContent = GetElem(id);
if (refContent)
return refContent;
}
return nsnull;
}
nsIContent*
IDRefsIterator::GetElem(const nsDependentSubstring& aID)
{
if (mXBLDocument) {
// If content is anonymous subtree then use "anonid" attribute to get
// elements, otherwise search elements in DOM by ID attribute.
nsCOMPtr<nsIDOMElement> refElm;
mXBLDocument->GetAnonymousElementByAttribute(mBindingParent,
NS_LITERAL_STRING("anonid"),
aID,
getter_AddRefs(refElm));
nsCOMPtr<nsIContent> refContent = do_QueryInterface(refElm);
return refContent;
}
return mDocument->GetElementById(aID);
}

View File

@ -525,6 +525,11 @@ public:
*/
nsIContent* NextElem();
/**
* Return the element with the given ID.
*/
nsIContent* GetElem(const nsDependentSubstring& aID);
private:
nsString mIDs;
nsAString::index_type mCurrIdx;

View File

@ -103,7 +103,8 @@ nsDocAccessible::
nsDocAccessible(nsIDocument *aDocument, nsIContent *aRootContent,
nsIWeakReference *aShell) :
nsHyperTextAccessibleWrap(aRootContent, aShell),
mDocument(aDocument), mScrollPositionChangedTicks(0), mIsLoaded(PR_FALSE)
mDocument(aDocument), mScrollPositionChangedTicks(0), mIsLoaded(PR_FALSE),
mCacheRoot(nsnull), mIsPostCacheProcessing(PR_FALSE)
{
mDependentIDsHash.Init();
// XXX aaronl should we use an algorithm for the initial cache size?
@ -1588,6 +1589,39 @@ nsDocAccessible::RecreateAccessible(nsINode* aNode)
}
}
void
nsDocAccessible::NotifyOfCachingStart(nsAccessible* aAccessible)
{
if (!mCacheRoot)
mCacheRoot = aAccessible;
}
void
nsDocAccessible::NotifyOfCachingEnd(nsAccessible* aAccessible)
{
if (mCacheRoot == aAccessible && !mIsPostCacheProcessing) {
// Allow invalidation list insertions while container children are recached.
mIsPostCacheProcessing = PR_TRUE;
// Invalidate children of container accessible for each element in
// invalidation list.
for (PRUint32 idx = 0; idx < mInvalidationList.Length(); idx++) {
nsIContent* content = mInvalidationList[idx];
nsAccessible* container =
GetAccService()->GetCachedContainerAccessible(content);
container->InvalidateChildren();
// Make sure we keep children updated. While we're inside of caching loop
// then we must exist it with cached children.
container->EnsureChildren();
}
mInvalidationList.Clear();
mCacheRoot = nsnull;
mIsPostCacheProcessing = PR_FALSE;
}
}
////////////////////////////////////////////////////////////////////////////////
// Protected members
@ -1620,8 +1654,18 @@ nsDocAccessible::AddDependentIDsFor(nsAccessible* aRelProvider,
if (providers) {
AttrRelProvider* provider =
new AttrRelProvider(relAttr, aRelProvider->GetContent());
if (provider)
if (provider) {
providers->AppendElement(provider);
// We've got here during the children caching. If the referenced
// content is not accessible then store it to pend its container
// children invalidation (this happens immediately after the caching
// is finished).
nsIContent* dependentContent = iter.GetElem(id);
if (dependentContent && !GetCachedAccessible(dependentContent)) {
mInvalidationList.AppendElement(dependentContent);
}
}
}
}

View File

@ -212,6 +212,16 @@ public:
*/
nsAccessible* GetCachedAccessibleByUniqueIDInSubtree(void* aUniqueID);
/**
* Return true if the given ID is referred by relation attribute.
*
* @note Different elements may share the same ID if they are hosted inside
* XBL bindings. Be careful the result of this method may be senseless
* while it's called for XUL elements (where XBL is used widely).
*/
PRBool IsDependentID(const nsAString& aID) const
{ return mDependentIDsHash.Get(aID, nsnull); }
/**
* Initialize the newly created accessible and put it into document caches.
*
@ -243,6 +253,17 @@ public:
*/
void RecreateAccessible(nsINode* aNode);
/**
* Used to notify the document that the accessible caching is started or
* finished.
*
* While children are cached we may encounter the case there's no accessible
* for referred content by related accessible. Keep the caching root and
* these related nodes to invalidate their containers after root caching.
*/
void NotifyOfCachingStart(nsAccessible* aAccessible);
void NotifyOfCachingEnd(nsAccessible* aAccessible);
protected:
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
@ -409,6 +430,17 @@ protected:
nsClassHashtable<nsStringHashKey, AttrRelProviderArray> mDependentIDsHash;
friend class RelatedAccIterator;
/**
* Used for our caching algorithm. We store the root of the tree that needs
* caching, the list of nodes that should be invalidated, and whether we are
* processing the invalidation list.
*
* @see NotifyOfCachingStart/NotifyOfCachingEnd
*/
nsAccessible* mCacheRoot;
nsTArray<nsIContent*> mInvalidationList;
PRBool mIsPostCacheProcessing;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,