зеркало из https://github.com/mozilla/pjs.git
Bug 385070. Nodes in anonymous content trees that are hidden not being shut down. Patch by Evan Yan. r=aaronlev, r+sr=roc, a=mconnor
This commit is contained in:
Родитель
be7b03a18d
Коммит
4ffa31a420
|
@ -175,12 +175,29 @@ NS_IMETHODIMP nsAccessNode::Init()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
void* uniqueID;
|
||||
GetUniqueID(&uniqueID);
|
||||
nsCOMPtr<nsPIAccessibleDocument> privateDocAccessible =
|
||||
do_QueryInterface(docAccessible);
|
||||
NS_ASSERTION(privateDocAccessible, "No private docaccessible for docaccessible");
|
||||
privateDocAccessible->CacheAccessNode(uniqueID, this);
|
||||
|
||||
// Make sure an ancestor in real content is cached
|
||||
// so that nsDocAccessible::RefreshNodes() can find the anonymous subtree to release when
|
||||
// the root node goes away
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
|
||||
if (content && (content->IsNativeAnonymous() ||
|
||||
content->GetBindingParent())) {
|
||||
// Specific examples of where this is used: <input type="file"> and <xul:findbar>
|
||||
nsCOMPtr<nsIAccessible> parentAccessible;
|
||||
docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, getter_AddRefs(parentAccessible));
|
||||
if (parentAccessible) {
|
||||
PRInt32 childCountUnused;
|
||||
parentAccessible->GetChildCount(&childCountUnused);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_A11Y
|
||||
mIsInitialized = PR_TRUE;
|
||||
#endif
|
||||
|
|
|
@ -1666,71 +1666,75 @@ void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
|
|||
|
||||
void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> iterNode(aStartNode), nextNode;
|
||||
nsCOMPtr<nsIAccessNode> accessNode;
|
||||
GetCachedAccessNode(aStartNode, getter_AddRefs(accessNode));
|
||||
nsCOMPtr<nsIDOMNode> nextNode, iterNode;
|
||||
|
||||
do {
|
||||
GetCachedAccessNode(iterNode, getter_AddRefs(accessNode));
|
||||
if (accessNode) {
|
||||
// Accessibles that implement their own subtrees,
|
||||
// like html combo boxes and xul trees must shutdown all of their own
|
||||
// children when they override Shutdown()
|
||||
// Shut down accessible subtree, which may have been created for
|
||||
// anonymous content subtree
|
||||
nsCOMPtr<nsIAccessible> accessible(do_QueryInterface(accessNode));
|
||||
if (accessible) {
|
||||
nsCOMPtr<nsPIAccessible> privateAccessible = do_QueryInterface(accessible);
|
||||
NS_ASSERTION(privateAccessible, "No nsPIAccessible for nsIAccessible");
|
||||
nsCOMPtr<nsIAccessible> childAccessible;
|
||||
privateAccessible->GetCachedFirstChild(getter_AddRefs(childAccessible));
|
||||
if (childAccessible) { // Has cached children that need to be shut down
|
||||
nsCOMPtr<nsIArray> children;
|
||||
// use GetChildren() to fetch children at one time, instead of using
|
||||
// GetNextSibling(), because after we shutdown the first child,
|
||||
// mNextSibling will be set null.
|
||||
accessible->GetChildren(getter_AddRefs(children));
|
||||
|
||||
// Don't shutdown our doc object!
|
||||
if (accessNode != static_cast<nsIAccessNode*>(this)) {
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible(do_QueryInterface(accessNode));
|
||||
if (accessible) {
|
||||
// Fire menupopupend events for menu popups that go away
|
||||
PRUint32 role = Role(accessible);
|
||||
if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
||||
nsCOMPtr<nsIDOMNode> domNode;
|
||||
accessNode->GetDOMNode(getter_AddRefs(domNode));
|
||||
nsCOMPtr<nsIDOMXULPopupElement> popup(do_QueryInterface(domNode));
|
||||
if (!popup) {
|
||||
// Popup elements already fire these via DOMMenuInactive
|
||||
// handling in nsRootAccessible::HandleEvent
|
||||
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
|
||||
accessible);
|
||||
}
|
||||
}
|
||||
PRUint32 childCount;
|
||||
children->GetLength(&childCount);
|
||||
for (PRUint32 index = 0; index < childCount; index++) {
|
||||
nsCOMPtr<nsIAccessNode> childAccessNode;
|
||||
children->QueryElementAt(index, NS_GET_IID(nsIAccessNode),
|
||||
getter_AddRefs(childAccessNode));
|
||||
childAccessNode->GetDOMNode(getter_AddRefs(iterNode));
|
||||
nsCOMPtr<nsIContent> iterContent = do_QueryInterface(iterNode);
|
||||
if (iterContent && (iterContent->IsNativeAnonymous() ||
|
||||
iterContent->GetBindingParent())) {
|
||||
// GetBindingParent() check is a perf win -- make sure we don't
|
||||
// shut down the same subtree twice since we'll reach non-anon content via
|
||||
// DOM traversal later in this method
|
||||
RefreshNodes(iterNode);
|
||||
}
|
||||
|
||||
void *uniqueID;
|
||||
accessNode->GetUniqueID(&uniqueID);
|
||||
nsCOMPtr<nsPIAccessNode> privateAccessNode(do_QueryInterface(accessNode));
|
||||
privateAccessNode->Shutdown();
|
||||
// Remove from hash table as well
|
||||
mAccessNodeCache.Remove(uniqueID);
|
||||
}
|
||||
}
|
||||
|
||||
iterNode->GetFirstChild(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
iterNode = nextNode;
|
||||
continue;
|
||||
// Shutdown ordinary content subtree as well -- there may be
|
||||
// access node children which are not full accessible objects
|
||||
aStartNode->GetFirstChild(getter_AddRefs(nextNode));
|
||||
while (nextNode) {
|
||||
nextNode.swap(iterNode);
|
||||
RefreshNodes(iterNode);
|
||||
iterNode->GetNextSibling(getter_AddRefs(nextNode));
|
||||
}
|
||||
|
||||
if (iterNode == aStartNode)
|
||||
break;
|
||||
iterNode->GetNextSibling(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
iterNode = nextNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
iterNode->GetParentNode(getter_AddRefs(nextNode));
|
||||
if (!nextNode || nextNode == aStartNode) {
|
||||
return;
|
||||
if (accessNode && accessNode != static_cast<nsIAccessNode*>(this)) {
|
||||
// Fire menupopup end if a menu goes away
|
||||
PRUint32 role = Role(accessible);
|
||||
if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
||||
nsCOMPtr<nsIDOMNode> domNode;
|
||||
accessNode->GetDOMNode(getter_AddRefs(domNode));
|
||||
nsCOMPtr<nsIDOMXULPopupElement> popup(do_QueryInterface(domNode));
|
||||
if (!popup) {
|
||||
// Popup elements already fire these via DOMMenuInactive
|
||||
// handling in nsRootAccessible::HandleEvent
|
||||
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
|
||||
accessible);
|
||||
}
|
||||
}
|
||||
nextNode->GetNextSibling(getter_AddRefs(iterNode));
|
||||
if (iterNode)
|
||||
break;
|
||||
iterNode = nextNode;
|
||||
} while (PR_TRUE);
|
||||
}
|
||||
// Shut down the actual accessible or access node
|
||||
void *uniqueID;
|
||||
accessNode->GetUniqueID(&uniqueID);
|
||||
nsCOMPtr<nsPIAccessNode> privateAccessNode(do_QueryInterface(accessNode));
|
||||
privateAccessNode->Shutdown();
|
||||
// Remove from hash table as well
|
||||
mAccessNodeCache.Remove(uniqueID);
|
||||
}
|
||||
while (iterNode && iterNode != aStartNode);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
|
||||
|
|
|
@ -603,8 +603,13 @@ nsFileControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
#ifdef ACCESSIBILITY
|
||||
NS_IMETHODIMP nsFileControlFrame::GetAccessible(nsIAccessible** aAccessible)
|
||||
{
|
||||
// No accessible object for file control, only for child text frame and button
|
||||
*aAccessible = nsnull;
|
||||
// Accessible object exists just to hold onto its children, for later shutdown
|
||||
nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
|
||||
|
||||
if (accService) {
|
||||
return accService->CreateHTMLGenericAccessible(static_cast<nsIFrame*>(this), aAccessible);
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче