Bug 606924 - deal with cached accessible tree only, r=davidb, a=blocking2.0final+

This commit is contained in:
Alexander Surkov 2011-01-27 11:38:50 +08:00
parent fed942f0b3
commit 6e1f0abc17
4 changed files with 35 additions and 159 deletions

View File

@ -559,15 +559,6 @@ nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
document->RecreateAccessible(aContent);
}
// nsAccessibilityService protected
nsAccessible *
nsAccessibilityService::GetCachedAccessible(nsINode *aNode,
nsIWeakReference *aWeakShell)
{
nsDocAccessible *docAccessible = GetDocAccessible(aNode->GetOwnerDoc());
return docAccessible ? docAccessible->GetCachedAccessible(aNode) : nsnull;
}
////////////////////////////////////////////////////////////////////////////////
// nsIAccessibleRetrieval
@ -783,7 +774,7 @@ nsAccessibilityService::GetAccessibleInShell(nsINode* aNode,
return nsnull;
nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell));
return GetAccessibleByRule(aNode, weakShell, eGetAccForNode);
return GetAccessibleInWeakShell(aNode, weakShell);
}
////////////////////////////////////////////////////////////////////////////////
@ -792,33 +783,20 @@ nsAccessibilityService::GetAccessibleInShell(nsINode* aNode,
nsAccessible*
nsAccessibilityService::GetAccessible(nsINode* aNode)
{
if (aNode) {
nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(aNode));
if (weakShell)
return GetAccessibleByRule(aNode, weakShell, eGetAccForNode);
}
return nsnull;
nsDocAccessible* document = GetDocAccessible(aNode->GetOwnerDoc());
return document ? document->GetCachedAccessible(aNode) : nsnull;
}
nsAccessible*
nsAccessibilityService::GetCachedAccessibleOrContainer(nsINode* aNode)
nsAccessibilityService::GetAccessibleOrContainer(nsINode* aNode,
nsIWeakReference* aWeakShell)
{
if (!aNode)
if (!aNode || !aNode->IsInDoc())
return nsnull;
nsIDocument *document = aNode->GetCurrentDoc();
if (!document)
return nsnull;
nsIPresShell *presShell = document->GetShell();
if (!presShell)
return nsnull;
nsINode *currNode = aNode;
nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
nsAccessible *accessible = nsnull;
while (!(accessible = GetCachedAccessible(currNode, weakShell)) &&
nsINode* currNode = aNode;
nsAccessible* accessible = nsnull;
while (!(accessible = GetAccessibleInWeakShell(currNode, aWeakShell)) &&
(currNode = currNode->GetNodeParent()));
return accessible;
@ -861,7 +839,7 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
*aIsSubtreeHidden = false;
// Check to see if we already have an accessible for this node in the cache.
nsAccessible *cachedAccessible = GetCachedAccessible(aNode, aWeakShell);
nsAccessible* cachedAccessible = GetAccessibleInWeakShell(aNode, aWeakShell);
if (cachedAccessible) {
NS_ADDREF(cachedAccessible);
return cachedAccessible;
@ -1237,69 +1215,6 @@ nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent)
nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_relevant);
}
nsAccessible*
nsAccessibilityService::GetAccessibleByRule(nsINode* aNode,
nsIWeakReference* aWeakShell,
EWhatAccToGet aWhatToGet)
{
if (!aNode || !aWeakShell)
return nsnull;
if (aWhatToGet & eGetAccForNode) {
nsAccessible* cachedAcc = GetCachedAccessible(aNode, aWeakShell);
if (cachedAcc && (cachedAcc->IsBoundToParent() || cachedAcc->IsDocument()))
return cachedAcc;
}
// Go up looking for the nearest accessible container having cached children.
nsTArray<nsINode*> nodes;
nsINode* node = aNode;
nsAccessible* cachedAcc = nsnull;
while ((node = node->GetNodeParent())) {
cachedAcc = GetCachedAccessible(node, aWeakShell);
if (cachedAcc && cachedAcc->IsBoundToParent())
break;
nodes.AppendElement(node);
}
// Node is not in accessible document.
if (!cachedAcc)
return nsnull;
// If children of the cached accessible weren't initialized then go down to
// the given node and create accessible tree.
nsAccessible* containerAcc = cachedAcc;
if (!cachedAcc->AreChildrenCached()) {
cachedAcc->EnsureChildren();
for (PRInt32 idx = nodes.Length() - 1; idx >= 0; idx--) {
cachedAcc = GetCachedAccessible(nodes[idx], aWeakShell);
if (cachedAcc) {
cachedAcc->EnsureChildren();
containerAcc = cachedAcc;
}
}
}
// If the given node is accessible then it should be cached at this point.
// Exception is an area element because area and imagemap nodes aren't in
// the same parent chain.
cachedAcc = GetCachedAccessible(aNode, aWeakShell);
if (!cachedAcc && aNode->IsElement()) {
nsIFrame* frame = aNode->AsElement()->GetPrimaryFrame();
if (frame && frame->GetContent() != aNode)
cachedAcc = GetAreaAccessible(frame, aNode, aWeakShell, &containerAcc);
}
if ((aWhatToGet & eGetAccForNode) && cachedAcc)
return cachedAcc;
else if (aWhatToGet & eGetAccForContainer)
return containerAcc;
return nsnull;
}
nsAccessible*
nsAccessibilityService::GetAreaAccessible(nsIFrame* aImageFrame,
nsINode* aAreaNode,
@ -1317,8 +1232,8 @@ nsAccessibilityService::GetAreaAccessible(nsIFrame* aImageFrame,
// Try to get image map accessible from the global cache or create it
// if failed.
nsRefPtr<nsAccessible> image = GetCachedAccessible(aImageFrame->GetContent(),
aWeakShell);
nsRefPtr<nsAccessible> image =
GetAccessibleInWeakShell(aImageFrame->GetContent(), aWeakShell);
if (!image) {
image = CreateHTMLImageAccessible(aImageFrame->GetContent(),
aImageFrame->PresContext()->PresShell());
@ -1341,7 +1256,7 @@ nsAccessibilityService::GetAreaAccessible(nsIFrame* aImageFrame,
// that they should be available in global cache.
image->EnsureChildren();
return GetCachedAccessible(aAreaNode, aWeakShell);
return GetAccessibleInWeakShell(aAreaNode, aWeakShell);
}
already_AddRefed<nsAccessible>

View File

@ -163,57 +163,27 @@ public:
inline nsAccessible* GetAccessibleInWeakShell(nsINode* aNode,
nsIWeakReference* aWeakShell)
{
return GetAccessibleByRule(aNode, aWeakShell, eGetAccForNode);
// XXX: weak shell is ignored until multiple shell documents are supported.
return GetAccessible(aNode);
}
/**
* Return an accessible for the given DOM node or container accessible if
* the node is not accessible.
*/
inline nsAccessible* GetAccessibleOrContainer(nsINode* aNode,
nsIWeakReference* aWeakShell)
{
return GetAccessibleByRule(aNode, aWeakShell, eGetAccForNodeOrContainer);
}
nsAccessible* GetAccessibleOrContainer(nsINode* aNode,
nsIWeakReference* aWeakShell);
/**
* Return a container accessible for the given DOM node.
*/
inline nsAccessible* GetContainerAccessible(nsINode* aNode,
nsIWeakReference* aWeakShell)
{
return GetAccessibleByRule(aNode, aWeakShell, eGetAccForContainer);
}
/**
* Return cached accessible for the given DOM node or cached container
* accessible if there's no cached accessible for the given node.
*/
nsAccessible* GetCachedAccessibleOrContainer(nsINode* aNode);
/**
* Return the first cached accessible parent of a DOM node.
*
* @param aDOMNode [in] the DOM node to get an accessible for
*/
inline nsAccessible* GetCachedContainerAccessible(nsINode *aNode)
{
return aNode ?
GetCachedAccessibleOrContainer(aNode->GetNodeParent()) : nsnull;
GetAccessibleOrContainer(aNode->GetNodeParent(), aWeakShell) : nsnull;
}
protected:
/**
* Return an accessible for the DOM node in the given presentation shell if
* the accessible already exists, otherwise null.
*
* @param aNode [in] the DOM node to get an access node for
* @param aPresShell [in] the presentation shell which contains layout info
* for the DOM node
*/
nsAccessible *GetCachedAccessible(nsINode *aNode,
nsIWeakReference *aShell);
private:
// nsAccessibilityService creation is controlled by friend
// NS_GetAccessibilityService, keep constructors private.
@ -232,19 +202,6 @@ private:
*/
void Shutdown();
enum EWhatAccToGet {
eGetAccForNode = 0x1,
eGetAccForContainer = 0x2,
eGetAccForNodeOrContainer = eGetAccForNode | eGetAccForContainer
};
/**
* Return accessible or accessible container for the given node in presshell.
*/
nsAccessible* GetAccessibleByRule(nsINode* aNode,
nsIWeakReference* aWeakShell,
EWhatAccToGet aWhatToGet);
/**
* Return accessible for HTML area element associated with an image map.
*

View File

@ -225,6 +225,15 @@ public:
*/
virtual void SetRoleMapEntry(nsRoleMapEntry *aRoleMapEntry);
/**
* Update the children cache.
*/
inline bool UpdateChildren()
{
InvalidateChildren();
return EnsureChildren();
}
/**
* Cache children if necessary. Return true if the accessible is defunct.
*/

View File

@ -1390,7 +1390,7 @@ nsDocAccessible::ContentInserted(nsIContent* aContainerNode,
// Update the whole tree of this document accessible when the container is
// null (document element is inserted or removed).
nsAccessible* container = aContainerNode ?
GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
this;
mNotificationController->ScheduleContentInsertion(container,
@ -1406,7 +1406,7 @@ nsDocAccessible::ContentRemoved(nsIContent* aContainerNode,
// Update the whole tree of this document accessible when the container is
// null (document element is removed).
nsAccessible* container = aContainerNode ?
GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
this;
UpdateTree(container, aChildNode, PR_FALSE);
@ -1452,7 +1452,7 @@ nsDocAccessible::RecreateAccessible(nsINode* aNode)
}
// Get new accessible and fire show event.
parent->InvalidateChildren();
parent->UpdateChildren();
nsAccessible* newAccessible =
GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell);
@ -1492,12 +1492,11 @@ nsDocAccessible::NotifyOfCachingEnd(nsAccessible* aAccessible)
for (PRUint32 idx = 0; idx < mInvalidationList.Length(); idx++) {
nsIContent* content = mInvalidationList[idx];
nsAccessible* container =
GetAccService()->GetCachedContainerAccessible(content);
container->InvalidateChildren();
GetAccService()->GetContainerAccessible(content, mWeakShell);
// Make sure we keep children updated. While we're inside of caching loop
// then we must exist it with cached children.
container->EnsureChildren();
container->UpdateChildren();
}
mInvalidationList.Clear();
@ -1860,16 +1859,14 @@ nsDocAccessible::ProcessContentInserted(nsAccessible* aContainer,
// accessibles into accessible tree. We need to invalidate children even
// there's no inserted accessibles in the end because accessible children
// are created while parent recaches child accessibles.
aContainer->InvalidateChildren();
aContainer->UpdateChildren();
// The container might be changed, for example, because of the subsequent
// overlapping content insertion (i.e. other content was inserted between this
// inserted content and its container or the content was reinserted into
// different container of unrelated part of tree). These cases result in
// double processing, however generated events are coalesced and we don't
// harm an AT. On the another hand container can be different because direct
// container wasn't cached yet when we handled content insertion notification
// and therefore we can't ignore the case when container has been changed.
// harm an AT.
// Theoretically the element might be not in tree at all at this point what
// means there's no container.
for (PRUint32 idx = 0; idx < aInsertedContent->Length(); idx++) {
@ -1945,9 +1942,7 @@ nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
if (aIsInsert && !node->GetPrimaryFrame())
continue;
nsAccessible* accessible = aIsInsert ?
GetAccService()->GetAccessibleInWeakShell(node, mWeakShell) :
GetCachedAccessible(node);
nsAccessible* accessible = GetCachedAccessible(node);
if (!accessible) {
updateFlags |= UpdateTreeInternal(aContainer, node->GetFirstChild(),