Bug 550819 - A11y test suite crash [@ nsTArray_base::Length], r=marcoz, davidb

This commit is contained in:
Alexander Surkov 2010-04-08 15:43:08 +09:00
parent aff371e5cb
commit dbc0c64242
6 changed files with 97 additions and 157 deletions

View File

@ -1404,33 +1404,11 @@ nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
}
if (weakFrame.GetFrame()->GetContent() != content) {
// Not the main content for this frame!
// For example, this happens because <area> elements return the
// image frame as their primary frame. The main content for the
// image frame is the image content.
// Check if frame is an image frame, and content is <area>.
nsIImageFrame *imageFrame = do_QueryFrame(weakFrame.GetFrame());
nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(content);
if (imageFrame && areaElmt) {
// XXX: it's a hack we should try the cache before or if failed cache
// the image accessible.
nsCOMPtr<nsIAccessible> imageAcc;
CreateHTMLImageAccessible(weakFrame.GetFrame(), getter_AddRefs(imageAcc));
if (imageAcc) {
// Cache children.
PRInt32 childCount;
imageAcc->GetChildCount(&childCount);
// <area> accessible should be in cache now.
nsAccessNode* cachedAreaAcc = GetCachedAccessNode(aNode, aWeakShell);
if (cachedAreaAcc) {
newAcc = nsAccUtils::QueryObject<nsAccessible>(cachedAreaAcc);
return newAcc.forget();
}
}
}
return nsnull;
// Not the main content for this frame. This happens because <area>
// elements return the image frame as their primary frame. The main content
// for the image frame is the image content. If the frame is not an image
// frame or the node is not an area element then null is returned.
return GetAreaAccessible(weakFrame.GetFrame(), aNode, aWeakShell);
}
// Attempt to create an accessible based on what we know.
@ -1769,6 +1747,52 @@ nsAccessibilityService::GetRelevantContentNodeFor(nsIDOMNode *aNode,
return NS_OK;
}
already_AddRefed<nsAccessible>
nsAccessibilityService::GetAreaAccessible(nsIFrame *aImageFrame,
nsIDOMNode *aAreaNode,
nsIWeakReference *aWeakShell)
{
// Check if frame is an image frame, and content is <area>.
nsIImageFrame *imageFrame = do_QueryFrame(aImageFrame);
if (!imageFrame)
return nsnull;
nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(aAreaNode);
if (!areaElmt)
return nsnull;
// Try to get image map accessible from the global cache or create it
// if failed.
nsRefPtr<nsAccessible> imageAcc;
nsCOMPtr<nsIDOMNode> imageNode(do_QueryInterface(aImageFrame->GetContent()));
nsAccessNode *cachedImgAcc = GetCachedAccessNode(imageNode, aWeakShell);
if (cachedImgAcc)
imageAcc = nsAccUtils::QueryObject<nsAccessible>(cachedImgAcc);
if (!imageAcc) {
nsCOMPtr<nsIAccessible> imageAccessible;
CreateHTMLImageAccessible(aImageFrame,
getter_AddRefs(imageAccessible));
imageAcc = nsAccUtils::QueryObject<nsAccessible>(imageAccessible);
if (!InitAccessible(imageAcc, nsnull))
return nsnull;
}
// Make sure <area> accessible children of the image map are cached so
// that they should be available in global cache.
imageAcc->EnsureChildren();
nsAccessNode *cachedAreaAcc = GetCachedAccessNode(aAreaNode, aWeakShell);
if (!cachedAreaAcc)
return nsnull;
nsRefPtr<nsAccessible> areaAcc =
nsAccUtils::QueryObject<nsAccessible>(cachedAreaAcc);
return areaAcc.forget();
}
already_AddRefed<nsAccessible>
nsAccessibilityService::CreateAccessibleByType(nsIDOMNode *aNode,
nsIWeakReference *aWeakShell)

View File

@ -149,6 +149,13 @@ private:
PRBool InitAccessible(nsAccessible *aAccessible,
nsRoleMapEntry *aRoleMapEntry);
/**
* Return accessible for HTML area element associated with an image map.
*/
already_AddRefed<nsAccessible>
GetAreaAccessible(nsIFrame *aImageFrame, nsIDOMNode *aAreaNode,
nsIWeakReference *aWeakShell);
/**
* Create accessible for the element implementing nsIAccessibleProvider
* interface.

View File

@ -3012,6 +3012,7 @@ nsAccessible::TestChildCache(nsAccessible *aCachedChild)
#endif
}
// nsAccessible public
PRBool
nsAccessible::EnsureChildren()
{

View File

@ -231,6 +231,11 @@ public:
*/
void SetParent(nsAccessible *aParent);
/**
* Cache children if necessary. Return true if the accessible is defunct.
*/
PRBool EnsureChildren();
/**
* Set the child count to -1 (unknown) and null out cached child pointers.
* Should be called when accessible tree is changed because document has
@ -317,11 +322,6 @@ protected:
*/
virtual void CacheChildren();
/**
* Cache children if necessary. Return true if the accessible is defunct.
*/
PRBool EnsureChildren();
/**
* Return sibling accessible at the given offset.
*/

View File

@ -51,36 +51,17 @@
// nsHTMLImageMapAccessible
////////////////////////////////////////////////////////////////////////////////
const PRUint32 kDefaultImageMapCacheSize = 256;
nsHTMLImageMapAccessible::
nsHTMLImageMapAccessible(nsIDOMNode *aDOMNode, nsIWeakReference *aShell,
nsIDOMHTMLMapElement *aMapElm) :
nsHTMLImageAccessibleWrap(aDOMNode, aShell), mMapElement(aMapElm)
{
mAreaAccCache.Init(kDefaultImageMapCacheSize);
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLImageMapAccessible: nsISupports and cycle collector
// nsHTMLImageMapAccessible: nsISupports
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLImageMapAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLImageMapAccessible,
nsAccessible)
CycleCollectorTraverseCache(tmp->mAreaAccCache, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLImageMapAccessible,
nsAccessible)
ClearCache(tmp->mAreaAccCache);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsHTMLImageMapAccessible)
NS_INTERFACE_MAP_END_INHERITING(nsHTMLImageAccessible)
NS_IMPL_ADDREF_INHERITED(nsHTMLImageMapAccessible, nsHTMLImageAccessible)
NS_IMPL_RELEASE_INHERITED(nsHTMLImageMapAccessible, nsHTMLImageAccessible)
NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLImageMapAccessible, nsHTMLImageAccessible)
////////////////////////////////////////////////////////////////////////////////
// nsHTMLImageMapAccessible: nsIAccessibleHyperLink
@ -99,16 +80,14 @@ nsHTMLImageMapAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI)
NS_ENSURE_ARG_POINTER(aURI);
*aURI = nsnull;
nsCOMPtr<nsIDOMHTMLCollection> mapAreas = GetAreaCollection();
if (!mapAreas)
return NS_OK;
nsCOMPtr<nsIDOMNode> domNode;
mapAreas->Item(aIndex, getter_AddRefs(domNode));
if (!domNode)
nsAccessible *areaAcc = GetChildAt(aIndex);
if (!areaAcc)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIContent> link(do_QueryInterface(domNode));
nsCOMPtr<nsIDOMNode> areaNode;
areaAcc->GetDOMNode(getter_AddRefs(areaNode));
nsCOMPtr<nsIContent> link(do_QueryInterface(areaNode));
if (link)
*aURI = link->GetHrefURI().get();
@ -121,27 +100,11 @@ nsHTMLImageMapAccessible::GetAnchor(PRInt32 aIndex, nsIAccessible **aAccessible)
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
nsCOMPtr<nsIDOMHTMLCollection> mapAreas = GetAreaCollection();
if (mapAreas) {
nsRefPtr<nsIAccessible> accessible = GetAreaAccessible(mapAreas, aIndex);
if (!accessible)
return NS_ERROR_INVALID_ARG;
nsAccessible *areaAcc = GetChildAt(aIndex);
if (!areaAcc)
return NS_ERROR_INVALID_ARG;
NS_ADDREF(*aAccessible = accessible);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLImageAccessible: nsAccessNode
nsresult
nsHTMLImageMapAccessible::Shutdown()
{
nsLinkableAccessible::Shutdown();
ClearCache(mAreaAccCache);
NS_ADDREF(*aAccessible = areaAcc);
return NS_OK;
}
@ -161,79 +124,47 @@ nsHTMLImageMapAccessible::GetRoleInternal(PRUint32 *aRole)
void
nsHTMLImageMapAccessible::CacheChildren()
{
nsCOMPtr<nsIDOMHTMLCollection> mapAreas = GetAreaCollection();
if (!mMapElement)
return;
nsCOMPtr<nsIDOMHTMLCollection> mapAreas;
mMapElement->GetAreas(getter_AddRefs(mapAreas));
if (!mapAreas)
return;
PRUint32 areaCount = 0;
mapAreas->GetLength(&areaCount);
nsRefPtr<nsAccessible> areaAcc;
for (PRUint32 areaIdx = 0; areaIdx < areaCount; areaIdx++) {
areaAcc = GetAreaAccessible(mapAreas, areaIdx);
nsCOMPtr<nsIDOMNode> areaNode;
mapAreas->Item(areaIdx, getter_AddRefs(areaNode));
if (!areaNode)
return;
nsRefPtr<nsAccessible> areaAcc =
new nsHTMLAreaAccessible(areaNode, mWeakShell);
if (!areaAcc)
return;
nsresult rv = areaAcc->Init();
if (NS_FAILED(rv)) {
areaAcc->Shutdown();
return;
}
mChildren.AppendElement(areaAcc);
areaAcc->SetParent(this);
}
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLImageAccessible
already_AddRefed<nsIDOMHTMLCollection>
nsHTMLImageMapAccessible::GetAreaCollection()
{
if (!mMapElement)
return nsnull;
nsIDOMHTMLCollection *mapAreas = nsnull;
mMapElement->GetAreas(&mapAreas);
return mapAreas;
}
already_AddRefed<nsAccessible>
nsHTMLImageMapAccessible::GetAreaAccessible(nsIDOMHTMLCollection *aAreaCollection,
PRInt32 aAreaNum)
{
if (!aAreaCollection)
return nsnull;
nsCOMPtr<nsIDOMNode> domNode;
aAreaCollection->Item(aAreaNum,getter_AddRefs(domNode));
if (!domNode)
return nsnull;
void *key = reinterpret_cast<void*>(aAreaNum);
nsRefPtr<nsAccessible> accessible = mAreaAccCache.GetWeak(key);
if (!accessible) {
accessible = new nsHTMLAreaAccessible(domNode, this, mWeakShell);
if (!accessible)
return nsnull;
nsresult rv = accessible->Init();
if (NS_FAILED(rv)) {
accessible->Shutdown();
return nsnull;
}
mAreaAccCache.Put(key, accessible);
}
return accessible.forget();
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLAreaAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLAreaAccessible::
nsHTMLAreaAccessible(nsIDOMNode *aDomNode, nsIAccessible *aParent,
nsIWeakReference* aShell):
nsHTMLLinkAccessible(aDomNode, aShell)
nsHTMLAreaAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell) :
nsHTMLLinkAccessible(aNode, aShell)
{
}

View File

@ -57,9 +57,6 @@ public:
// nsISupports and cycle collector
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLImageMapAccessible,
nsAccessible)
// nsIAccessibleHyperLink
NS_IMETHOD GetAnchorCount(PRInt32 *aAnchorCount);
NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI);
@ -69,32 +66,13 @@ public:
virtual nsresult GetRoleInternal(PRUint32 *aRole);
protected:
// nsAccessNode
virtual nsresult Shutdown();
// nsAccessible
virtual void CacheChildren();
// nsHTMLImageAccessible
/**
* Return collection of HTML area elements associated with the image map.
*/
already_AddRefed<nsIDOMHTMLCollection> GetAreaCollection();
/**
* Return an accessible for HTML area element at the given index.
*/
already_AddRefed<nsAccessible>
GetAreaAccessible(nsIDOMHTMLCollection* aAreaNodes, PRInt32 aAreaNum);
private:
// Reference on linked map element if any.
nsCOMPtr<nsIDOMHTMLMapElement> mMapElement;
// Cache of area accessibles. We do not use common cache because images can
// share area elements but we need to have separate area accessibles for
// each image accessible.
nsAccessibleHashtable mAreaAccCache;
};
@ -105,8 +83,7 @@ class nsHTMLAreaAccessible : public nsHTMLLinkAccessible
{
public:
nsHTMLAreaAccessible(nsIDOMNode *domNode, nsIAccessible *accParent,
nsIWeakReference* aShell);
nsHTMLAreaAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell);
// nsIAccessible
NS_IMETHOD GetDescription(nsAString& aDescription);