Bug 305813. Error pages not read by screen reader

This commit is contained in:
aaronleventhal%moonset.net 2005-08-30 22:37:16 +00:00
parent adfb499dd1
commit d12d5c852e
6 changed files with 110 additions and 41 deletions

View File

@ -160,7 +160,7 @@ NS_IMETHODIMP nsAccessibilityService::OnStateChange(nsIWebProgress *aWebProgress
{
NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
if (0 == (aStateFlags & (STATE_START | STATE_STOP))) {
if (0 == (aStateFlags & (STATE_START | STATE_STOP)) || NS_FAILED(aStatus)) {
return NS_OK;
}
@ -197,8 +197,9 @@ NS_IMETHODIMP nsAccessibilityService::OnStateChange(nsIWebProgress *aWebProgress
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
PRBool isFinished = !(aStateFlags & STATE_START);
if (sameTypeRoot != docShellTreeItem && !isFinished) {
return NS_OK; // A frame or iframe has begun to load new content
if (sameTypeRoot != docShellTreeItem) {
// Frame and iframe handling done via DOMContentLoaded in nsRootAccessible::HandleEvent()
return NS_OK;
}
docAccessible->FireDocLoadingEvent(isFinished);

View File

@ -84,7 +84,7 @@
//-----------------------------------------------------
nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
nsBlockAccessible(aDOMNode, aShell), mWnd(nsnull),
mEditor(nsnull), mScrollPositionChangedTicks(0)
mEditor(nsnull), mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE)
{
// Because of the way document loading happens, the new nsIWidget is created before
// the old one is removed. Since it creates the nsDocAccessible, for a brief moment
@ -189,15 +189,8 @@ NS_IMETHODIMP nsDocAccessible::GetState(PRUint32 *aState)
}
nsAccessible::GetState(aState);
*aState |= STATE_FOCUSABLE;
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
GetDocShellTreeItemFor(mDOMNode);
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(docShellTreeItem));
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
PRUint32 busyFlags;
docShell->GetBusyFlags(&busyFlags);
if (busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
if (!mIsContentLoaded) {
*aState |= STATE_BUSY;
}
@ -538,12 +531,7 @@ void nsDocAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aRelativeFrame)
nsresult nsDocAccessible::AddEventListeners()
{
// 1) Set up scroll position listener
// 2) Set up web progress listener - we need to know
// when page loading is finished
// That way we can send the STATE_CHANGE events for
// the MSAA root "pane" object (ROLE_PANE),
// and change the STATE_BUSY bit flag
// Do this only for top level content documents
// 2) Check for editor and listen for changes to editor
nsCOMPtr<nsIPresShell> presShell(GetPresShell());
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
@ -617,6 +605,11 @@ NS_IMETHODIMP nsDocAccessible::FireDocLoadingEvent(PRBool aIsFinished)
return NS_OK; // Document has been shut down
}
if (mIsContentLoaded == aIsFinished) {
return NS_OK;
}
mIsContentLoaded = aIsFinished;
if (aIsFinished) {
// Need to wait until scrollable view is available
AddScrollListener();
@ -1060,14 +1053,7 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
nsCOMPtr<nsIDOMNode> childNode = aChild ? do_QueryInterface(aChild) : mDOMNode;
// Don't fire any other events if doc is still loading
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
PRUint32 busyFlags;
docShell->GetBusyFlags(&busyFlags);
if (busyFlags && mAccessNodeCache.Count() <= 1) {
if (!mIsContentLoaded && mAccessNodeCache.Count() <= 1) {
return NS_OK; // Still loading and nothing to invalidate yet
}
@ -1101,7 +1087,10 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
nsCOMPtr<nsIAccessible> containerAccessible;
if (childNode == mDOMNode) {
// Don't get parent accessible if already at the root of a docshell chain like UI or content
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(docShell));
// Don't fire any other events if doc is still loading
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
NS_ENSURE_TRUE(docShellTreeItem, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
if (sameTypeRoot == docShellTreeItem) {
@ -1117,7 +1106,7 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
privateContainerAccessible->InvalidateChildren();
}
if (busyFlags) {
if (!mIsContentLoaded) {
return NS_OK;
}

View File

@ -116,6 +116,7 @@ class nsDocAccessible : public nsBlockAccessible,
nsCOMPtr<nsITimer> mFireEventTimer;
nsCOMPtr<nsIEditor> mEditor; // Editor, if there is one
PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
PRPackedBool mIsContentLoaded;
nsCOMArray<nsIAccessibleEvent> mEventsToFire;
};

View File

@ -69,6 +69,7 @@
#include "nsRootAccessible.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeNode.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIBaseWindow.h"
@ -274,6 +275,9 @@ nsresult nsRootAccessible::AddEventListeners()
rv = target->AddEventListener(NS_LITERAL_STRING("DOMMenuBarInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
rv = target->AddEventListener(NS_LITERAL_STRING("DOMContentLoaded"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
}
GetChromeEventHandler(getter_AddRefs(target));
@ -320,6 +324,7 @@ nsresult nsRootAccessible::RemoveEventListeners()
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuItemActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("DOMContentLoaded"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
}
GetChromeEventHandler(getter_AddRefs(target));
@ -352,6 +357,65 @@ NS_IMETHODIMP nsRootAccessible::GetCaretAccessible(nsIAccessible **aCaretAccessi
return NS_OK;
}
void nsRootAccessible::TryFireEarlyLoadEvent(nsIAccessible *aAccessible, nsIDOMNode *aDocNode)
{
// We can fire an early load event based on DOMContentLoaded unless we
// have subdocuments. For that we wait until WebProgressListener
// STATE_STOP handling in nsAccessibilityService.
// Note, we don't fire any page load finished events for chrome or for
// frame/iframe page loads during the initial complete page load -- that page
// load event for the entire content pane needs to stand alone.
// This also works for firing events for error pages
nsCOMPtr<nsIDocShellTreeItem> treeItem =
GetDocShellTreeItemFor(aDocNode);
NS_ASSERTION(treeItem, "No docshelltreeitem for aDocNode");
if (!treeItem) {
return;
}
PRInt32 itemType;
treeItem->GetItemType(&itemType);
if (itemType != nsIDocShellTreeItem::typeContent) {
return;
}
nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(treeItem));
if (treeNode) {
PRInt32 subDocuments;
treeNode->GetChildCount(&subDocuments);
if (subDocuments) {
return;
}
}
nsCOMPtr<nsIDocShellTreeItem> rootContentTreeItem;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(rootContentTreeItem));
NS_ASSERTION(rootContentTreeItem, "No root content tree item");
if (!rootContentTreeItem) { // Not at root of content
return;
}
if (rootContentTreeItem != treeItem) {
nsCOMPtr<nsIAccessibleDocument> rootContentDocAccessible =
GetDocAccessibleFor(rootContentTreeItem);
nsCOMPtr<nsIAccessible> rootContentAccessible =
do_QueryInterface(rootContentDocAccessible);
PRUint32 state;
rootContentAccessible->GetFinalState(&state);
if (state & STATE_BUSY) {
// Don't fire page load events on subdocuments for initial page load of entire page
return;
}
}
// No frames or iframes, so we can fire the doc load finished event early
nsCOMPtr<nsPIAccessibleDocument> docAccessible =
do_QueryInterface(aAccessible);
NS_ASSERTION(docAccessible, "No doc aAccessible for DOMContentLoaded");
if (docAccessible) {
docAccessible->FireDocLoadingEvent(PR_TRUE);
}
}
void nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
nsIDOMNode *aNode,
PRBool aForceEvent)
@ -680,6 +744,9 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
// Focus was inside of popup that's being hidden
FireCurrentFocusEvent();
}
else if (eventType.LowerCaseEqualsLiteral("domcontentloaded")) {
TryFireEarlyLoadEvent(accessible, targetNode);
}
else {
// Menu popup events
PRUint32 menuEvent = 0;

View File

@ -109,6 +109,8 @@ class nsRootAccessible : public nsDocAccessibleWrap,
nsresult AddEventListeners();
nsresult RemoveEventListeners();
static void GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode);
void TryFireEarlyLoadEvent(cnsIAccessible *focusAccessible,
nsIDOMNode *focusNode);
void FireAccessibleFocusEvent(nsIAccessible *focusAccessible,
nsIDOMNode *focusNode,
PRBool aForceEvent = PR_FALSE);

View File

@ -330,9 +330,7 @@ NS_IMETHODIMP nsDocAccessibleWrap::FireAnchorJumpEvent()
// the can only relate events back to their internal model if it's a leaf.
// There is usually an accessible for the focus node, but if it's an empty text node
// we have to move forward in the document to get one
PRUint32 state;
GetState(&state);
if (state & STATE_BUSY) {
if (!mIsContentLoaded) {
return NS_OK;
}
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
@ -418,14 +416,19 @@ void nsDocAccessibleWrap::DocLoadCallback(nsITimer *aTimer, void *aClosure)
return;
}
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
NS_ASSERTION(docShell, "No docShell for docShellTreeItem");
PRBool hasFocus;
docShell->GetHasFocus(&hasFocus);
if (hasFocus) {
docAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE,
docAcc, nsnull);
docAcc->FireAnchorJumpEvent();
// Fire STATE_CHANGE event for doc load finish if focus is in same doc tree
if (gLastFocusedNode) {
nsCOMPtr<nsIDocShellTreeItem> focusedTreeItem =
GetDocShellTreeItemFor(gLastFocusedNode);
if (focusedTreeItem) {
nsCOMPtr<nsIDocShellTreeItem> sameTypeRootOfFocus;
focusedTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRootOfFocus));
if (sameTypeRoot == sameTypeRootOfFocus) {
docAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE,
docAcc, nsnull);
docAcc->FireAnchorJumpEvent();
}
}
}
}
}
@ -435,6 +438,12 @@ NS_IMETHODIMP nsDocAccessibleWrap::FireDocLoadingEvent(PRBool aIsFinished)
if (!mDocument || !mWeakShell)
return NS_OK; // Document has been shut down
if (mIsContentLoaded == aIsFinished) {
return NS_OK; // Already fired the event
}
nsDocAccessible::FireDocLoadingEvent(aIsFinished);
if (aIsFinished) {
// Use short timer before firing state change event for finished doc,
// because the window is made visible asynchronously by Microsoft Windows
@ -450,7 +459,7 @@ NS_IMETHODIMP nsDocAccessibleWrap::FireDocLoadingEvent(PRBool aIsFinished)
FireToolkitEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, this, nsnull);
}
return nsDocAccessible::FireDocLoadingEvent(aIsFinished);
return NS_OK;
}
STDMETHODIMP nsDocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)