mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 15:25:52 +00:00
Bug 305813. Error pages not read by screen reader
This commit is contained in:
parent
adfb499dd1
commit
d12d5c852e
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user