2003-04-01 22:18:29 +00:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version : MPL 1.1 / GPL 2.0 / LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is mozilla . org code .
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation .
* Portions created by the Initial Developer are Copyright ( C ) 2003
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
2004-04-17 21:52:36 +00:00
* Original Author : Aaron Leventhal ( aaronl @ netscape . com )
2003-04-01 22:18:29 +00:00
*
* Alternatively , the contents of this file may be used under the terms of
2004-04-17 21:52:36 +00:00
* either of the GNU General Public License Version 2 or later ( the " GPL " ) ,
* or the GNU Lesser General Public License Version 2.1 or later ( the " LGPL " ) ,
2003-04-01 22:18:29 +00:00
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above . If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL , and not to allow others to
* use your version of this file under the terms of the MPL , indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL . If you do not delete
* the provisions above , a recipient may use your version of this file under
* the terms of any one of the MPL , the GPL or the LGPL .
*
* * * * * * END LICENSE BLOCK * * * * * */
# include "nsDocAccessible.h"
2003-06-16 10:35:11 +00:00
# include "nsAccessibleEventData.h"
2003-05-15 08:37:38 +00:00
# include "nsIAccessibilityService.h"
2005-01-28 02:35:26 +00:00
# include "nsArray.h"
2003-05-15 08:37:38 +00:00
# include "nsICommandManager.h"
# include "nsIDocShell.h"
# include "nsIDocShellTreeItem.h"
2003-04-01 22:18:29 +00:00
# include "nsIDocument.h"
2005-01-28 02:35:26 +00:00
# include "nsIDOMAttr.h"
2003-05-15 08:37:38 +00:00
# include "nsIDOMCharacterData.h"
2003-04-01 22:18:29 +00:00
# include "nsIDOMDocument.h"
2003-04-28 10:24:52 +00:00
# include "nsIDOMEventTarget.h"
# include "nsIDOMEvent.h"
2003-04-01 22:18:29 +00:00
# include "nsIDOMDocument.h"
# include "nsIDOMDocumentType.h"
2003-04-28 10:24:52 +00:00
# include "nsIDOMNSDocument.h"
2003-05-15 08:37:38 +00:00
# include "nsIDOMNSHTMLDocument.h"
2003-04-28 10:24:52 +00:00
# include "nsIDOMMutationEvent.h"
2003-05-15 08:37:38 +00:00
# include "nsIDOMWindow.h"
# include "nsIEditingSession.h"
# include "nsIFrame.h"
2003-04-01 22:18:29 +00:00
# include "nsIInterfaceRequestorUtils.h"
2003-05-15 08:37:38 +00:00
# include "nsINameSpaceManager.h"
2003-06-16 10:35:11 +00:00
# include "nsIObserverService.h"
2003-05-15 08:37:38 +00:00
# include "nsIPlaintextEditor.h"
# include "nsIPresShell.h"
# include "nsIScriptGlobalObject.h"
2003-04-01 22:18:29 +00:00
# include "nsIServiceManager.h"
2003-04-15 08:45:55 +00:00
# include "nsIScrollableView.h"
2003-05-15 08:37:38 +00:00
# include "nsIURI.h"
# include "nsIWebNavigation.h"
# ifdef MOZ_XUL
# include "nsIXULDocument.h"
# endif
2003-04-01 22:18:29 +00:00
//=============================//
// nsDocAccessible //
//=============================//
//-----------------------------------------------------
// construction
//-----------------------------------------------------
nsDocAccessible : : nsDocAccessible ( nsIDOMNode * aDOMNode , nsIWeakReference * aShell ) :
2003-11-12 04:34:17 +00:00
nsBlockAccessible ( aDOMNode , aShell ) , mWnd ( nsnull ) ,
2003-05-15 08:37:38 +00:00
mWebProgress ( nsnull ) , mEditor ( nsnull ) ,
mBusy ( eBusyStateUninitialized ) ,
2003-04-15 08:45:55 +00:00
mScrollPositionChangedTicks ( 0 ) , mIsNewDocument ( PR_FALSE )
2003-04-01 22:18:29 +00:00
{
2003-04-15 08:45:55 +00:00
// 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
// there can be 2 nsDocAccessible's for the content area, although for 2 different
// pres shells.
nsCOMPtr < nsIPresShell > shell ( do_QueryReferent ( mWeakShell ) ) ;
2003-04-01 22:18:29 +00:00
if ( shell ) {
2004-08-02 04:52:55 +00:00
mDocument = shell - > GetDocument ( ) ;
2003-09-23 17:05:29 +00:00
nsIViewManager * vm = shell - > GetViewManager ( ) ;
2003-05-19 09:07:41 +00:00
if ( vm ) {
2003-09-23 17:05:29 +00:00
nsCOMPtr < nsIWidget > widget ;
2003-05-19 09:07:41 +00:00
vm - > GetWidget ( getter_AddRefs ( widget ) ) ;
if ( widget ) {
mWnd = widget - > GetNativeData ( NS_NATIVE_WINDOW ) ;
}
}
2003-04-01 22:18:29 +00:00
}
2003-04-15 08:45:55 +00:00
2003-11-12 04:34:17 +00:00
PutCacheEntry ( gGlobalDocAccessibleCache , mWeakShell , this ) ;
2003-04-15 08:45:55 +00:00
// XXX aaronl should we use an algorithm for the initial cache size?
2003-11-12 04:34:17 +00:00
mAccessNodeCache . Init ( kDefaultCacheSize ) ;
2003-04-01 22:18:29 +00:00
}
//-----------------------------------------------------
// destruction
//-----------------------------------------------------
nsDocAccessible : : ~ nsDocAccessible ( )
{
}
2003-05-15 08:37:38 +00:00
NS_INTERFACE_MAP_BEGIN ( nsDocAccessible )
NS_INTERFACE_MAP_ENTRY ( nsIAccessibleDocument )
2003-07-09 07:01:46 +00:00
NS_INTERFACE_MAP_ENTRY ( nsPIAccessibleDocument )
2003-05-15 08:37:38 +00:00
NS_INTERFACE_MAP_ENTRY ( nsIWebProgressListener )
NS_INTERFACE_MAP_ENTRY ( nsIDOMMutationListener )
NS_INTERFACE_MAP_ENTRY ( nsIScrollPositionListener )
NS_INTERFACE_MAP_ENTRY ( nsISupportsWeakReference )
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIAccessibleDocument )
NS_INTERFACE_MAP_ENTRY ( nsIObserver )
2003-06-02 08:36:44 +00:00
NS_INTERFACE_MAP_END_INHERITING ( nsBlockAccessible )
2003-05-15 08:37:38 +00:00
2003-06-02 08:36:44 +00:00
NS_IMPL_ADDREF_INHERITED ( nsDocAccessible , nsBlockAccessible )
NS_IMPL_RELEASE_INHERITED ( nsDocAccessible , nsBlockAccessible )
2003-04-01 22:18:29 +00:00
2003-07-31 08:09:39 +00:00
NS_IMETHODIMP nsDocAccessible : : GetName ( nsAString & aName )
2003-04-15 08:45:55 +00:00
{
2003-07-31 08:09:39 +00:00
return GetTitle ( aName ) ;
2003-04-15 08:45:55 +00:00
}
2003-07-31 08:09:39 +00:00
NS_IMETHODIMP nsDocAccessible : : GetRole ( PRUint32 * _retval )
2003-04-01 22:18:29 +00:00
{
* _retval = ROLE_PANE ;
return NS_OK ;
}
2003-07-31 08:09:39 +00:00
NS_IMETHODIMP nsDocAccessible : : GetValue ( nsAString & aValue )
2003-04-01 22:18:29 +00:00
{
2003-07-31 08:09:39 +00:00
return GetURL ( aValue ) ;
2003-04-01 22:18:29 +00:00
}
2003-07-31 08:09:39 +00:00
NS_IMETHODIMP nsDocAccessible : : GetState ( PRUint32 * aState )
2003-04-01 22:18:29 +00:00
{
2004-05-18 03:26:34 +00:00
nsAccessible : : GetState ( aState ) ;
* aState | = STATE_FOCUSABLE ;
2003-04-15 08:45:55 +00:00
if ( mBusy = = eBusyStateLoading )
2004-05-26 12:31:43 +00:00
* aState | = STATE_BUSY ; // If busy, not sure if visible yet or not
// Is it visible?
nsCOMPtr < nsIPresShell > shell ( do_QueryReferent ( mWeakShell ) ) ;
nsCOMPtr < nsIWidget > widget ;
if ( shell ) {
nsIViewManager * vm = shell - > GetViewManager ( ) ;
if ( vm ) {
vm - > GetWidget ( getter_AddRefs ( widget ) ) ;
}
}
PRBool isVisible = ( widget ! = nsnull ) ;
while ( widget & & isVisible ) {
widget - > IsVisible ( isVisible ) ;
widget = widget - > GetParent ( ) ;
}
if ( ! isVisible ) {
* aState | = STATE_INVISIBLE ;
}
2003-05-15 08:37:38 +00:00
PRBool isEditable ;
GetIsEditable ( & isEditable ) ;
2004-06-04 22:03:14 +00:00
if ( ! isEditable ) {
// Use STATE_READONLY when we're not in an editor pane
* aState | = STATE_READONLY ;
2003-05-15 08:37:38 +00:00
}
2003-04-15 08:45:55 +00:00
return NS_OK ;
2003-04-01 22:18:29 +00:00
}
// ------- nsIAccessibleDocument Methods (5) ---------------
NS_IMETHODIMP nsDocAccessible : : GetURL ( nsAString & aURL )
{
2003-04-15 08:45:55 +00:00
if ( ! mDocument ) {
return NS_ERROR_FAILURE ; // Document has been shut down
}
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsISupports > container = mDocument - > GetContainer ( ) ;
2003-04-01 22:18:29 +00:00
nsCOMPtr < nsIWebNavigation > webNav ( do_GetInterface ( container ) ) ;
nsCAutoString theURL ;
if ( webNav ) {
nsCOMPtr < nsIURI > pURI ;
webNav - > GetCurrentURI ( getter_AddRefs ( pURI ) ) ;
if ( pURI )
pURI - > GetSpec ( theURL ) ;
}
2003-12-23 16:48:40 +00:00
CopyUTF8toUTF16 ( theURL , aURL ) ;
2003-04-01 22:18:29 +00:00
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : GetTitle ( nsAString & aTitle )
{
2003-10-22 06:09:48 +00:00
if ( mDocument ) {
aTitle = mDocument - > GetDocumentTitle ( ) ;
return NS_OK ;
}
return NS_ERROR_FAILURE ;
2003-04-01 22:18:29 +00:00
}
NS_IMETHODIMP nsDocAccessible : : GetMimeType ( nsAString & aMimeType )
{
nsCOMPtr < nsIDOMNSDocument > domnsDocument ( do_QueryInterface ( mDocument ) ) ;
if ( domnsDocument ) {
return domnsDocument - > GetContentType ( aMimeType ) ;
}
return NS_ERROR_FAILURE ;
}
NS_IMETHODIMP nsDocAccessible : : GetDocType ( nsAString & aDocType )
{
nsCOMPtr < nsIDOMDocument > domDoc ( do_QueryInterface ( mDocument ) ) ;
nsCOMPtr < nsIDOMDocumentType > docType ;
2003-04-11 00:56:27 +00:00
# ifdef MOZ_XUL
nsCOMPtr < nsIXULDocument > xulDoc ( do_QueryInterface ( mDocument ) ) ;
2003-04-01 22:18:29 +00:00
if ( xulDoc ) {
2004-06-17 00:13:25 +00:00
aDocType . AssignLiteral ( " window " ) ; // doctype not implemented for XUL at time of writing - causes assertion
2003-04-01 22:18:29 +00:00
return NS_OK ;
2003-04-11 00:56:27 +00:00
} else
# endif
if ( domDoc & & NS_SUCCEEDED ( domDoc - > GetDoctype ( getter_AddRefs ( docType ) ) ) & & docType ) {
2003-04-01 22:18:29 +00:00
return docType - > GetName ( aDocType ) ;
}
return NS_ERROR_FAILURE ;
}
NS_IMETHODIMP nsDocAccessible : : GetNameSpaceURIForID ( PRInt16 aNameSpaceID , nsAString & aNameSpaceURI )
{
if ( mDocument ) {
nsCOMPtr < nsINameSpaceManager > nameSpaceManager =
do_GetService ( NS_NAMESPACEMANAGER_CONTRACTID ) ;
if ( nameSpaceManager )
return nameSpaceManager - > GetNameSpaceURI ( aNameSpaceID , aNameSpaceURI ) ;
}
return NS_ERROR_FAILURE ;
}
2003-07-22 14:55:22 +00:00
NS_IMETHODIMP nsDocAccessible : : GetCaretAccessible ( nsIAccessible * * aCaretAccessible )
2003-04-01 22:18:29 +00:00
{
// We only have a caret accessible on the root document
* aCaretAccessible = nsnull ;
return NS_OK ;
}
2003-06-16 10:35:11 +00:00
NS_IMETHODIMP nsDocAccessible : : GetWindowHandle ( void * * aWindow )
2003-04-01 22:18:29 +00:00
{
* aWindow = mWnd ;
return NS_OK ;
}
2003-06-16 10:35:11 +00:00
NS_IMETHODIMP nsDocAccessible : : GetWindow ( nsIDOMWindow * * aDOMWin )
{
* aDOMWin = nsnull ;
if ( ! mDocument ) {
return NS_ERROR_FAILURE ; // Accessible is Shutdown()
}
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsIDOMWindow > domWindow ( do_QueryInterface ( mDocument - > GetScriptGlobalObject ( ) ) ) ;
2003-06-16 10:35:11 +00:00
if ( ! domWindow )
return NS_ERROR_FAILURE ; // No DOM Window
NS_ADDREF ( * aDOMWin = domWindow ) ;
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : GetDocument ( nsIDOMDocument * * aDOMDoc )
{
nsCOMPtr < nsIDOMDocument > domDoc ( do_QueryInterface ( mDocument ) ) ;
* aDOMDoc = domDoc ;
if ( domDoc ) {
NS_ADDREF ( * aDOMDoc ) ;
return NS_OK ;
}
return NS_ERROR_FAILURE ;
}
2003-05-15 08:37:38 +00:00
void nsDocAccessible : : CheckForEditor ( )
{
2004-06-04 22:03:14 +00:00
if ( mEditor ) {
return ; // Already have editor, don't need to check
}
2003-07-14 09:40:21 +00:00
if ( ! mDocument ) {
return ; // No document -- we've been shut down
}
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsIDOMWindow > domWindow ( do_QueryInterface ( mDocument - > GetScriptGlobalObject ( ) ) ) ;
2003-05-15 08:37:38 +00:00
if ( ! domWindow )
return ; // No DOM Window
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsISupports > container = mDocument - > GetContainer ( ) ;
2003-05-15 08:37:38 +00:00
nsCOMPtr < nsIEditingSession > editingSession ( do_GetInterface ( container ) ) ;
if ( ! editingSession )
return ; // No editing session interface
editingSession - > GetEditorForWindow ( domWindow , getter_AddRefs ( mEditor ) ) ;
2004-06-04 22:03:14 +00:00
if ( mEditor ) {
// State readonly is now clear
# ifdef MOZ_ACCESSIBILITY_ATK
AtkStateChange stateData ;
stateData . enable = PR_TRUE ;
stateData . state = STATE_READONLY ; // Will be translated to ATK_STATE_EDITABLE
FireToolkitEvent ( nsIAccessibleEvent : : EVENT_STATE_CHANGE , this , & stateData ) ;
# else
FireToolkitEvent ( nsIAccessibleEvent : : EVENT_STATE_CHANGE , this , nsnull ) ;
# endif
}
2003-05-15 08:37:38 +00:00
}
NS_IMETHODIMP nsDocAccessible : : GetIsEditable ( PRBool * aIsEditable )
{
* aIsEditable = PR_FALSE ;
if ( mEditor ) {
PRUint32 flags ;
mEditor - > GetFlags ( & flags ) ;
* aIsEditable = ( flags & nsIPlaintextEditor : : eEditorReadonlyMask ) = = 0 ;
}
return NS_OK ;
}
2003-04-15 08:45:55 +00:00
NS_IMETHODIMP nsDocAccessible : : GetCachedAccessNode ( void * aUniqueID , nsIAccessNode * * aAccessNode )
{
2003-11-12 04:34:17 +00:00
GetCacheEntry ( mAccessNodeCache , aUniqueID , aAccessNode ) ; // Addrefs for us
2003-04-15 08:45:55 +00:00
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : CacheAccessNode ( void * aUniqueID , nsIAccessNode * aAccessNode )
2003-04-01 22:18:29 +00:00
{
2003-11-12 04:34:17 +00:00
PutCacheEntry ( mAccessNodeCache , aUniqueID , aAccessNode ) ;
2003-04-01 22:18:29 +00:00
return NS_OK ;
}
2003-05-15 08:37:38 +00:00
NS_IMETHODIMP nsDocAccessible : : Init ( )
{
// Hook up our new accessible with our parent
if ( ! mParent ) {
2003-10-22 06:09:48 +00:00
nsIDocument * parentDoc = mDocument - > GetParentDocument ( ) ;
2003-05-15 08:37:38 +00:00
if ( parentDoc ) {
2003-10-22 06:09:48 +00:00
nsIContent * ownerContent = parentDoc - > FindContentForSubDocument ( mDocument ) ;
2003-05-15 08:37:38 +00:00
nsCOMPtr < nsIDOMNode > ownerNode ( do_QueryInterface ( ownerContent ) ) ;
if ( ownerNode ) {
nsCOMPtr < nsIAccessibilityService > accService =
do_GetService ( " @mozilla.org/accessibilityService;1 " ) ;
if ( accService ) {
// XXX aaronl: ideally we would traverse the presshell chain
// Since there's no easy way to do that, we cheat and use
// the document hierarchy. GetAccessibleFor() is bad because
// it doesn't support our concept of multiple presshells per doc.
// It should be changed to use GetAccessibleInWeakShell()
nsCOMPtr < nsIAccessible > accParent ;
accService - > GetAccessibleFor ( ownerNode , getter_AddRefs ( accParent ) ) ;
2003-07-31 08:09:39 +00:00
nsCOMPtr < nsPIAccessible > privateParent ( do_QueryInterface ( accParent ) ) ;
if ( privateParent ) {
SetParent ( accParent ) ;
privateParent - > SetFirstChild ( this ) ;
2003-05-15 08:37:38 +00:00
}
}
}
}
}
2003-07-22 14:55:22 +00:00
AddEventListeners ( ) ;
2003-06-02 08:36:44 +00:00
return nsBlockAccessible : : Init ( ) ;
2003-05-15 08:37:38 +00:00
}
2003-04-28 10:24:52 +00:00
NS_IMETHODIMP nsDocAccessible : : Destroy ( )
{
2003-11-12 04:34:17 +00:00
gGlobalDocAccessibleCache . Remove ( NS_STATIC_CAST ( void * , mWeakShell ) ) ;
2003-04-28 10:24:52 +00:00
return Shutdown ( ) ;
}
2003-04-01 22:18:29 +00:00
NS_IMETHODIMP nsDocAccessible : : Shutdown ( )
{
2003-04-15 08:45:55 +00:00
if ( ! mWeakShell ) {
return NS_OK ; // Already shutdown
}
2003-05-15 08:37:38 +00:00
RemoveEventListeners ( ) ;
2003-04-15 08:45:55 +00:00
mWeakShell = nsnull ; // Avoid reentrancy
2003-05-15 08:37:38 +00:00
mEditor = nsnull ;
2003-04-28 10:24:52 +00:00
if ( mScrollWatchTimer ) {
mScrollWatchTimer - > Cancel ( ) ;
mScrollWatchTimer = nsnull ;
}
if ( mDocLoadTimer ) {
mDocLoadTimer - > Cancel ( ) ;
mDocLoadTimer = nsnull ;
}
2005-01-28 02:35:26 +00:00
if ( mFireEventTimer ) {
mFireEventTimer - > Cancel ( ) ;
mFireEventTimer = nsnull ;
}
mEventsToFire . Clear ( ) ;
2003-04-15 08:45:55 +00:00
mWebProgress = nsnull ;
2003-11-12 04:34:17 +00:00
ClearCache ( mAccessNodeCache ) ;
2003-04-15 08:45:55 +00:00
2003-04-01 22:18:29 +00:00
mDocument = nsnull ;
2003-05-15 08:37:38 +00:00
2003-06-02 08:36:44 +00:00
return nsBlockAccessible : : Shutdown ( ) ;
2003-04-01 22:18:29 +00:00
}
nsIFrame * nsDocAccessible : : GetFrame ( )
{
2003-04-15 08:45:55 +00:00
nsCOMPtr < nsIPresShell > shell ( do_QueryReferent ( mWeakShell ) ) ;
2003-04-01 22:18:29 +00:00
nsIFrame * root = nsnull ;
if ( shell )
2004-09-02 03:08:51 +00:00
root = shell - > GetRootFrame ( ) ;
2003-04-01 22:18:29 +00:00
return root ;
}
2003-07-31 08:09:39 +00:00
void nsDocAccessible : : GetBoundsRect ( nsRect & aBounds , nsIFrame * * aRelativeFrame )
2003-04-01 22:18:29 +00:00
{
* aRelativeFrame = GetFrame ( ) ;
2003-05-19 09:07:41 +00:00
2003-10-22 06:09:48 +00:00
nsIDocument * document = mDocument ;
nsIDocument * parentDoc = nsnull ;
2003-05-19 09:07:41 +00:00
while ( document ) {
2003-09-27 04:18:26 +00:00
nsIPresShell * presShell = document - > GetShellAt ( 0 ) ;
2003-05-19 09:07:41 +00:00
if ( ! presShell ) {
return ;
}
2003-09-23 17:05:29 +00:00
nsIViewManager * vm = presShell - > GetViewManager ( ) ;
2003-05-19 09:07:41 +00:00
nsIScrollableView * scrollableView = nsnull ;
if ( vm )
vm - > GetRootScrollableView ( & scrollableView ) ;
2003-09-23 17:05:29 +00:00
nsRect viewBounds ( 0 , 0 , 0 , 0 ) ;
2003-05-19 09:07:41 +00:00
if ( scrollableView ) {
2004-09-20 22:25:07 +00:00
viewBounds = scrollableView - > View ( ) - > GetBounds ( ) ;
2003-05-19 09:07:41 +00:00
}
else {
2004-05-17 16:29:13 +00:00
nsIView * view ;
vm - > GetRootView ( view ) ;
if ( view ) {
viewBounds = view - > GetBounds ( ) ;
}
2003-05-19 09:07:41 +00:00
}
if ( parentDoc ) { // After first time thru loop
aBounds . IntersectRect ( viewBounds , aBounds ) ;
}
else { // First time through loop
aBounds = viewBounds ;
}
2003-10-22 06:09:48 +00:00
document = parentDoc = document - > GetParentDocument ( ) ;
2003-05-19 09:07:41 +00:00
}
2003-04-01 22:18:29 +00:00
}
2003-05-19 09:07:41 +00:00
2003-07-22 14:55:22 +00:00
nsresult nsDocAccessible : : AddEventListeners ( )
2003-04-15 08:45:55 +00:00
{
// 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
nsCOMPtr < nsIPresShell > presShell ( GetPresShell ( ) ) ;
2003-07-22 14:55:22 +00:00
NS_ENSURE_TRUE ( presShell , NS_ERROR_FAILURE ) ;
2003-04-15 08:45:55 +00:00
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsISupports > container = mDocument - > GetContainer ( ) ;
2003-04-15 08:45:55 +00:00
nsCOMPtr < nsIDocShellTreeItem > docShellTreeItem ( do_QueryInterface ( container ) ) ;
2003-07-22 14:55:22 +00:00
NS_ENSURE_TRUE ( docShellTreeItem , NS_ERROR_FAILURE ) ;
2003-04-15 08:45:55 +00:00
// Make sure we're a content docshell
// We don't want to listen to chrome progress
PRInt32 itemType ;
docShellTreeItem - > GetItemType ( & itemType ) ;
2003-06-26 08:45:39 +00:00
PRBool isContent = ( itemType = = nsIDocShellTreeItem : : typeContent ) ;
PRBool isLoading = isContent ;
2003-04-15 08:45:55 +00:00
2003-06-26 08:45:39 +00:00
if ( isContent ) {
CheckForEditor ( ) ;
if ( ! mEditor ) {
// We're not an editor yet, but we might become one
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsICommandManager > commandManager = do_GetInterface ( docShellTreeItem ) ;
2003-06-26 08:45:39 +00:00
if ( commandManager ) {
commandManager - > AddCommandObserver ( this , " obs_documentCreated " ) ;
}
2003-05-15 08:37:38 +00:00
}
// Make sure we're the top content doc shell
// We don't want to listen to iframe progress
nsCOMPtr < nsIDocShellTreeItem > topOfContentTree ;
docShellTreeItem - > GetSameTypeRootTreeItem ( getter_AddRefs ( topOfContentTree ) ) ;
if ( topOfContentTree ! = docShellTreeItem ) {
mBusy = eBusyStateDone ;
2003-07-22 14:55:22 +00:00
return NS_OK ;
2003-05-15 08:37:38 +00:00
}
2003-06-26 08:45:39 +00:00
}
2003-04-15 08:45:55 +00:00
2003-06-26 08:45:39 +00:00
mWebProgress = do_GetInterface ( docShellTreeItem ) ;
2003-07-22 14:55:22 +00:00
NS_ENSURE_TRUE ( mWebProgress , NS_ERROR_FAILURE ) ;
2003-04-15 08:45:55 +00:00
2003-06-26 08:45:39 +00:00
mWebProgress - > AddProgressListener ( this , nsIWebProgress : : NOTIFY_LOCATION |
nsIWebProgress : : NOTIFY_STATE_DOCUMENT ) ;
2003-04-15 08:45:55 +00:00
2003-06-26 08:45:39 +00:00
mWebProgress - > GetIsLoadingDocument ( & isLoading ) ;
2003-05-15 08:37:38 +00:00
2003-04-15 08:45:55 +00:00
mIsNewDocument = PR_TRUE ;
mBusy = eBusyStateLoading ;
if ( ! isLoading ) {
// If already loaded, fire "done loading" event after short timeout
// If we fired the event here, we'd get reentrancy problems
2003-05-15 08:37:38 +00:00
// Otherwise, if the doc is still loading,
// the event will be fired from OnStateChange when the load is done
2003-04-15 08:45:55 +00:00
mDocLoadTimer = do_CreateInstance ( " @mozilla.org/timer;1 " ) ;
if ( mDocLoadTimer ) {
mDocLoadTimer - > InitWithFuncCallback ( DocLoadCallback , this , 1 ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
}
2003-04-28 10:24:52 +00:00
// add ourself as a mutation event listener
// (this slows down mozilla about 3%, but only used when accessibility APIs active)
nsCOMPtr < nsIDOMEventTarget > target ( do_QueryInterface ( mDocument ) ) ;
NS_ASSERTION ( target , " No dom event target for document " ) ;
nsresult rv = target - > AddEventListener ( NS_LITERAL_STRING ( " DOMAttrModified " ) ,
this , PR_TRUE ) ;
NS_ASSERTION ( NS_SUCCEEDED ( rv ) , " failed to register listener " ) ;
rv = target - > AddEventListener ( NS_LITERAL_STRING ( " DOMSubtreeModified " ) ,
this , PR_TRUE ) ;
NS_ASSERTION ( NS_SUCCEEDED ( rv ) , " failed to register listener " ) ;
rv = target - > AddEventListener ( NS_LITERAL_STRING ( " DOMNodeInserted " ) ,
this , PR_TRUE ) ;
NS_ASSERTION ( NS_SUCCEEDED ( rv ) , " failed to register listener " ) ;
rv = target - > AddEventListener ( NS_LITERAL_STRING ( " DOMNodeRemoved " ) ,
this , PR_TRUE ) ;
NS_ASSERTION ( NS_SUCCEEDED ( rv ) , " failed to register listener " ) ;
2005-01-28 02:35:26 +00:00
// These aren't implemented yet, and we're not using them
// rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeInsertedIntoDocument"),
// this, PR_TRUE);
// NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
// rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeRemovedFromDocument"),
// this, PR_TRUE);
// NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
2003-07-22 14:55:22 +00:00
return rv ;
2003-04-15 08:45:55 +00:00
}
2003-07-22 14:55:22 +00:00
nsresult nsDocAccessible : : RemoveEventListeners ( )
2003-04-15 08:45:55 +00:00
{
// Remove listeners associated with content documents
// Remove web progress listener
if ( mWebProgress ) {
mWebProgress - > RemoveProgressListener ( this ) ;
mWebProgress = nsnull ;
}
// Remove scroll position listener
2004-11-08 02:29:47 +00:00
RemoveScrollListener ( ) ;
2003-04-28 10:24:52 +00:00
nsCOMPtr < nsIDOMEventTarget > target ( do_QueryInterface ( mDocument ) ) ;
NS_ASSERTION ( target , " No dom event target for document " ) ;
target - > RemoveEventListener ( NS_LITERAL_STRING ( " DOMAttrModified " ) , this , PR_TRUE ) ;
target - > RemoveEventListener ( NS_LITERAL_STRING ( " DOMSubtreeModified " ) , this , PR_TRUE ) ;
target - > RemoveEventListener ( NS_LITERAL_STRING ( " DOMNodeInserted " ) , this , PR_TRUE ) ;
target - > RemoveEventListener ( NS_LITERAL_STRING ( " DOMNodeRemoved " ) , this , PR_TRUE ) ;
2005-01-28 02:35:26 +00:00
// target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeInsertedIntoDocument"), this, PR_TRUE);
// target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeRemovedFromDocument"), this, PR_TRUE);
2003-05-15 08:37:38 +00:00
2003-06-16 10:22:40 +00:00
if ( mScrollWatchTimer ) {
mScrollWatchTimer - > Cancel ( ) ;
mScrollWatchTimer = nsnull ;
}
if ( mDocLoadTimer ) {
mDocLoadTimer - > Cancel ( ) ;
mDocLoadTimer = nsnull ;
}
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsISupports > container = mDocument - > GetContainer ( ) ;
2003-06-16 10:22:40 +00:00
nsCOMPtr < nsIDocShellTreeItem > docShellTreeItem ( do_QueryInterface ( container ) ) ;
2003-07-22 14:55:22 +00:00
NS_ENSURE_TRUE ( docShellTreeItem , NS_ERROR_FAILURE ) ;
2003-06-16 10:22:40 +00:00
PRInt32 itemType ;
docShellTreeItem - > GetItemType ( & itemType ) ;
if ( itemType = = nsIDocShellTreeItem : : typeContent ) {
2003-10-22 06:09:48 +00:00
nsCOMPtr < nsICommandManager > commandManager = do_GetInterface ( docShellTreeItem ) ;
2003-06-16 10:22:40 +00:00
if ( commandManager ) {
commandManager - > RemoveCommandObserver ( this , " obs_documentCreated " ) ;
}
2003-05-15 08:37:38 +00:00
}
2003-07-22 14:55:22 +00:00
return NS_OK ;
2003-04-15 08:45:55 +00:00
}
void nsDocAccessible : : FireDocLoadFinished ( )
{
2003-04-28 10:24:52 +00:00
if ( ! mDocument | | ! mWeakShell )
return ; // Document has been shut down
2003-04-25 02:18:54 +00:00
2004-05-26 12:31:43 +00:00
PRUint32 state ;
GetState ( & state ) ;
2004-11-08 21:07:50 +00:00
if ( ( state & STATE_INVISIBLE ) = = 0 ) {
// Don't consider load finished until window unhidden
2003-04-15 08:45:55 +00:00
mIsNewDocument = PR_FALSE ;
if ( mBusy ! = eBusyStateDone ) {
2004-11-08 02:29:47 +00:00
AddScrollListener ( ) ;
2003-04-15 08:45:55 +00:00
}
2004-11-08 21:07:50 +00:00
mBusy = eBusyStateDone ;
2003-04-15 08:45:55 +00:00
}
}
void nsDocAccessible : : DocLoadCallback ( nsITimer * aTimer , void * aClosure )
{
// Doc has finished loading, fire "load finished" event
// This path is only used if the doc was already finished loading
// when the DocAccessible was created.
// Otherwise, ::OnStateChange() fires the event when doc is loaded.
nsDocAccessible * docAcc = NS_REINTERPRET_CAST ( nsDocAccessible * , aClosure ) ;
if ( docAcc )
docAcc - > FireDocLoadFinished ( ) ;
}
void nsDocAccessible : : ScrollTimerCallback ( nsITimer * aTimer , void * aClosure )
{
nsDocAccessible * docAcc = NS_REINTERPRET_CAST ( nsDocAccessible * , aClosure ) ;
if ( docAcc & & docAcc - > mScrollPositionChangedTicks & &
+ + docAcc - > mScrollPositionChangedTicks > 2 ) {
// Whenever scroll position changes, mScrollPositionChangeTicks gets reset to 1
// We only want to fire accessibilty scroll event when scrolling stops or pauses
// Therefore, we wait for no scroll events to occur between 2 ticks of this timer
// That indicates a pause in scrolling, so we fire the accessibilty scroll event
2003-07-22 14:55:22 +00:00
docAcc - > FireToolkitEvent ( nsIAccessibleEvent : : EVENT_SCROLLINGEND , docAcc , nsnull ) ;
2003-04-15 08:45:55 +00:00
docAcc - > mScrollPositionChangedTicks = 0 ;
2003-05-01 10:25:45 +00:00
if ( docAcc - > mScrollWatchTimer ) {
docAcc - > mScrollWatchTimer - > Cancel ( ) ;
docAcc - > mScrollWatchTimer = nsnull ;
}
2003-04-15 08:45:55 +00:00
}
}
2004-11-08 02:29:47 +00:00
void nsDocAccessible : : AddScrollListener ( )
2003-04-15 08:45:55 +00:00
{
2004-11-08 02:29:47 +00:00
nsCOMPtr < nsIPresShell > presShell ( do_QueryReferent ( mWeakShell ) ) ;
2003-09-23 17:05:29 +00:00
nsIViewManager * vm = nsnull ;
2004-11-08 02:29:47 +00:00
if ( presShell )
vm = presShell - > GetViewManager ( ) ;
2003-04-15 08:45:55 +00:00
nsIScrollableView * scrollableView = nsnull ;
if ( vm )
vm - > GetRootScrollableView ( & scrollableView ) ;
if ( scrollableView )
2003-05-15 08:37:38 +00:00
scrollableView - > AddScrollPositionListener ( this ) ;
2003-04-15 08:45:55 +00:00
}
2004-11-08 02:29:47 +00:00
void nsDocAccessible : : RemoveScrollListener ( )
2003-04-15 08:45:55 +00:00
{
2004-11-08 02:29:47 +00:00
nsCOMPtr < nsIPresShell > presShell ( do_QueryReferent ( mWeakShell ) ) ;
2003-09-23 17:05:29 +00:00
nsIViewManager * vm = nsnull ;
2004-11-08 02:29:47 +00:00
if ( presShell )
vm = presShell - > GetViewManager ( ) ;
2003-04-15 08:45:55 +00:00
nsIScrollableView * scrollableView = nsnull ;
if ( vm )
vm - > GetRootScrollableView ( & scrollableView ) ;
if ( scrollableView )
2003-05-15 08:37:38 +00:00
scrollableView - > RemoveScrollPositionListener ( this ) ;
2003-04-15 08:45:55 +00:00
}
NS_IMETHODIMP nsDocAccessible : : ScrollPositionWillChange ( nsIScrollableView * aView , nscoord aX , nscoord aY )
{
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : ScrollPositionDidChange ( nsIScrollableView * aScrollableView , nscoord aX , nscoord aY )
{
// Start new timer, if the timer cycles at least 1 full cycle without more scroll position changes,
// then the ::Notify() method will fire the accessibility event for scroll position changes
const PRUint32 kScrollPosCheckWait = 50 ;
if ( mScrollWatchTimer ) {
mScrollWatchTimer - > SetDelay ( kScrollPosCheckWait ) ; // Create new timer, to avoid leaks
}
else {
mScrollWatchTimer = do_CreateInstance ( " @mozilla.org/timer;1 " ) ;
if ( mScrollWatchTimer ) {
mScrollWatchTimer - > InitWithFuncCallback ( ScrollTimerCallback , this ,
kScrollPosCheckWait ,
nsITimer : : TYPE_REPEATING_SLACK ) ;
}
}
mScrollPositionChangedTicks = 1 ;
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : OnStateChange ( nsIWebProgress * aWebProgress ,
nsIRequest * aRequest , PRUint32 aStateFlags , nsresult aStatus )
{
2003-05-15 08:37:38 +00:00
if ( ( aStateFlags & STATE_IS_DOCUMENT ) & & ( aStateFlags & STATE_STOP ) ) {
2004-05-26 12:31:43 +00:00
if ( ! mDocLoadTimer ) {
mDocLoadTimer = do_CreateInstance ( " @mozilla.org/timer;1 " ) ;
}
if ( mDocLoadTimer ) {
mDocLoadTimer - > InitWithFuncCallback ( DocLoadCallback , this , 4 ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
2003-05-15 08:37:38 +00:00
}
2003-04-15 08:45:55 +00:00
return NS_OK ;
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP nsDocAccessible : : OnProgressChange ( nsIWebProgress * aWebProgress ,
nsIRequest * aRequest , PRInt32 aCurSelfProgress , PRInt32 aMaxSelfProgress ,
PRInt32 aCurTotalProgress , PRInt32 aMaxTotalProgress )
{
NS_NOTREACHED ( " notification excluded in AddProgressListener(...) " ) ;
return NS_OK ;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP nsDocAccessible : : OnLocationChange ( nsIWebProgress * aWebProgress ,
nsIRequest * aRequest , nsIURI * location )
{
2004-06-01 19:42:26 +00:00
PRBool isLoadingDocument ;
aWebProgress - > GetIsLoadingDocument ( & isLoadingDocument ) ;
if ( ! isLoadingDocument ) {
2004-11-08 02:29:47 +00:00
return NS_OK ; // Staying on the same page, jumping to a named anchor
2004-06-01 19:42:26 +00:00
}
2003-04-15 08:45:55 +00:00
// Load has been verified, it will occur, about to commence
2003-04-28 10:24:52 +00:00
// We won't fire a "doc finished loading" event on this nsDocAccessible
// Instead we fire that on the new nsDocAccessible that is created for the new doc
2003-04-15 08:45:55 +00:00
mIsNewDocument = PR_FALSE ; // We're a doc that's going away
if ( mBusy ! = eBusyStateLoading ) {
mBusy = eBusyStateLoading ;
// Fire a "new doc has started to load" event
# ifndef MOZ_ACCESSIBILITY_ATK
2003-07-22 14:55:22 +00:00
FireToolkitEvent ( nsIAccessibleEvent : : EVENT_STATE_CHANGE , this , nsnull ) ;
2003-04-15 08:45:55 +00:00
# else
AtkChildrenChange childrenData ;
childrenData . index = - 1 ;
childrenData . child = 0 ;
childrenData . add = PR_FALSE ;
2003-07-22 14:55:22 +00:00
FireToolkitEvent ( nsIAccessibleEvent : : EVENT_REORDER , this , & childrenData ) ;
2003-04-15 08:45:55 +00:00
# endif
}
return NS_OK ;
}
/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP nsDocAccessible : : OnStatusChange ( nsIWebProgress * aWebProgress ,
nsIRequest * aRequest , nsresult aStatus , const PRUnichar * aMessage )
{
NS_NOTREACHED ( " notification excluded in AddProgressListener(...) " ) ;
return NS_OK ;
}
/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */
NS_IMETHODIMP nsDocAccessible : : OnSecurityChange ( nsIWebProgress * aWebProgress ,
nsIRequest * aRequest , PRUint32 state )
{
NS_NOTREACHED ( " notification excluded in AddProgressListener(...) " ) ;
return NS_OK ;
}
2003-05-15 08:37:38 +00:00
NS_IMETHODIMP nsDocAccessible : : Observe ( nsISupports * aSubject , const char * aTopic ,
const PRUnichar * aData )
{
if ( ! nsCRT : : strcmp ( aTopic , " obs_documentCreated " ) ) {
CheckForEditor ( ) ;
NS_ASSERTION ( mEditor , " Should have editor if we see obs_documentCreated " ) ;
}
return NS_OK ;
}
void nsDocAccessible : : GetEventShell ( nsIDOMNode * aNode , nsIPresShell * * aEventShell )
{
// XXX aaronl - this is not ideal.
// We could avoid this whole section and the fallible
2003-09-27 04:18:26 +00:00
// doc->GetShellAt(0) by putting the event handler
2003-05-15 08:37:38 +00:00
// on nsDocAccessible instead.
// The disadvantage would be that we would be seeing some events
// for inner documents that we don't care about.
* aEventShell = nsnull ;
nsCOMPtr < nsIDOMDocument > domDocument ;
aNode - > GetOwnerDocument ( getter_AddRefs ( domDocument ) ) ;
nsCOMPtr < nsIDocument > doc ( do_QueryInterface ( domDocument ) ) ;
2003-09-27 04:18:26 +00:00
if ( doc ) {
* aEventShell = doc - > GetShellAt ( 0 ) ;
NS_IF_ADDREF ( * aEventShell ) ;
}
2003-05-15 08:37:38 +00:00
}
void nsDocAccessible : : GetEventDocAccessible ( nsIDOMNode * aNode ,
nsIAccessibleDocument * * aAccessibleDoc )
{
* aAccessibleDoc = nsnull ;
nsCOMPtr < nsIPresShell > eventShell ;
GetEventShell ( aNode , getter_AddRefs ( eventShell ) ) ;
nsCOMPtr < nsIWeakReference > weakEventShell ( do_GetWeakReference ( eventShell ) ) ;
if ( ! weakEventShell ) {
return ;
}
GetDocAccessibleFor ( weakEventShell , aAccessibleDoc ) ;
}
2003-04-28 10:24:52 +00:00
// ---------- Mutation event listeners ------------
NS_IMETHODIMP nsDocAccessible : : NodeInserted ( nsIDOMEvent * aEvent )
{
2003-07-22 14:55:22 +00:00
HandleMutationEvent ( aEvent , nsIAccessibleEvent : : EVENT_CREATE ) ;
2003-04-28 10:24:52 +00:00
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : NodeRemoved ( nsIDOMEvent * aEvent )
{
// The related node for the event will be the parent of the removed node or subtree
2003-07-22 14:55:22 +00:00
HandleMutationEvent ( aEvent , nsIAccessibleEvent : : EVENT_DESTROY ) ;
2003-04-28 10:24:52 +00:00
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : SubtreeModified ( nsIDOMEvent * aEvent )
{
2003-07-22 14:55:22 +00:00
HandleMutationEvent ( aEvent , nsIAccessibleEvent : : EVENT_REORDER ) ;
2003-04-28 10:24:52 +00:00
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : AttrModified ( nsIDOMEvent * aMutationEvent )
{
// XXX todo
2005-01-28 02:35:26 +00:00
// We still need to handle special HTML cases here
2003-04-28 10:24:52 +00:00
// For example, if an <img>'s usemap attribute is modified
// Otherwise it may just be a state change, for example an object changing
2005-01-28 02:35:26 +00:00
// its visibility
nsCOMPtr < nsIPresShell > shell = GetPresShell ( ) ;
if ( ! shell ) {
return NS_OK ; // Document has been shut down
}
nsCOMPtr < nsIDOMMutationEvent > mutationEvent ( do_QueryInterface ( aMutationEvent ) ) ;
NS_ASSERTION ( mutationEvent , " Not a mutation event! " ) ;
nsCOMPtr < nsIDOMEventTarget > domEventTarget ;
mutationEvent - > GetTarget ( getter_AddRefs ( domEventTarget ) ) ;
nsCOMPtr < nsIDOMNode > targetNode ( do_QueryInterface ( domEventTarget ) ) ;
NS_ASSERTION ( targetNode , " No node for attr modified " ) ;
if ( ! targetNode ) {
return NS_OK ;
}
nsCOMPtr < nsIAccessibilityService > accService =
do_GetService ( " @mozilla.org/accessibilityService;1 " ) ;
NS_ASSERTION ( accService , " How can we be here if no accessibility service? " ) ;
nsCOMPtr < nsIAccessible > changedAccessible ;
accService - > GetAccessibleInShell ( targetNode , shell ,
getter_AddRefs ( changedAccessible ) ) ;
if ( ! changedAccessible ) {
return NS_OK ; // The attribute change did not occur on a node exposed for accessibility
}
nsCOMPtr < nsIDOMNode > attributeNode ;
mutationEvent - > GetRelatedNode ( getter_AddRefs ( attributeNode ) ) ;
nsCOMPtr < nsIDOMAttr > domAttr ( do_QueryInterface ( attributeNode ) ) ;
NS_ASSERTION ( domAttr , " No related attribute node for DOMAttrModified event " ) ;
nsAutoString attrName ;
mutationEvent - > GetAttrName ( attrName ) ;
PRUint32 eventType = 0 ;
if ( attrName . EqualsLiteral ( " checked " ) ) {
nsCOMPtr < nsIContent > targetContent ( do_QueryInterface ( targetNode ) ) ;
if ( targetContent - > IsContentOfType ( nsIContent : : eXUL ) ) {
// XXX Should we remove XUL's CheckboxStateChanged event and just utilize this instead?
return NS_OK ; // XUL utilizes CheckboxStateChanged event for this. Don't fire double event
}
eventType = nsIAccessibleEvent : : EVENT_STATE_CHANGE ;
}
else if ( attrName . EqualsLiteral ( " readonly " ) | |
attrName . EqualsLiteral ( " disabled " ) | | attrName . EqualsLiteral ( " required " ) | |
attrName . EqualsLiteral ( " invalid " ) ) {
eventType = nsIAccessibleEvent : : EVENT_STATE_CHANGE ;
}
else if ( attrName . EqualsLiteral ( " valuenow " ) ) {
eventType = nsIAccessibleEvent : : EVENT_VALUE_CHANGE ;
}
else if ( attrName . EqualsLiteral ( " selected " ) ) {
nsCOMPtr < nsIContent > targetContent ( do_QueryInterface ( targetNode ) ) ;
if ( targetContent - > IsContentOfType ( nsIContent : : eXUL ) ) {
return NS_OK ; // XUL fires special events for selection
}
// XXX Do we need to differentiate between different kinds of selection events
// such as selection, selection add, selection remove?
nsAutoString attrValue ;
mutationEvent - > GetNewValue ( attrValue ) ;
if ( ! attrValue . IsEmpty ( ) & & ! attrValue . EqualsLiteral ( " false " ) ) {
eventType = nsIAccessibleEvent : : EVENT_SELECTION ;
}
}
// Fire after short timer, because we need to wait for
// DOM attribute to actually change. Otherwise, assistive technology
// will retrieve the wrong state/value/selection info.
if ( eventType ) {
PRBool isTimerStarted = PR_TRUE ;
if ( mEventsToFire . Count ( ) = = 0 ) {
if ( ! mFireEventTimer ) {
// Do not yet have a timer going for firing another event.
mFireEventTimer = do_CreateInstance ( " @mozilla.org/timer;1 " ) ;
NS_ENSURE_TRUE ( mFireEventTimer , NS_ERROR_OUT_OF_MEMORY ) ;
}
isTimerStarted = PR_FALSE ;
}
// XXX Add related data for ATK support.
// For example, state change event should provide what state has changed,
// as well as the old and new value.
nsCOMPtr < nsIAccessibleEvent > event =
new nsAccessibleEventData ( eventType , changedAccessible , this , nsnull ) ;
NS_ENSURE_TRUE ( event , NS_ERROR_OUT_OF_MEMORY ) ;
mEventsToFire . AppendObject ( event ) ;
if ( ! isTimerStarted ) {
// This is be the first delayed event in queue, start timer
// so that event gets fired via FlushEventsCallback
mFireEventTimer - > InitWithFuncCallback ( FlushEventsCallback ,
NS_STATIC_CAST ( nsPIAccessibleDocument * , this ) ,
0 , nsITimer : : TYPE_ONE_SHOT ) ;
}
}
2003-04-28 10:24:52 +00:00
return NS_OK ;
}
2005-01-28 02:35:26 +00:00
NS_IMETHODIMP nsDocAccessible : : FlushPendingEvents ( )
{
PRUint32 length = mEventsToFire . Count ( ) ;
NS_ASSERTION ( length , " How did we get here without events to fire? " ) ;
2005-01-28 03:58:10 +00:00
PRUint32 index ;
for ( index = 0 ; index < length ; index + + ) {
2005-01-28 02:35:26 +00:00
nsIAccessibleEvent * accessibleEvent = mEventsToFire [ index ] ;
NS_ASSERTION ( accessibleEvent , " Array item is not an accessible event " ) ;
nsCOMPtr < nsIAccessible > accessible ;
accessibleEvent - > GetAccessible ( getter_AddRefs ( accessible ) ) ;
PRUint32 eventType ;
accessibleEvent - > GetEventType ( & eventType ) ;
FireToolkitEvent ( eventType , accessible , nsnull ) ;
}
mEventsToFire . Clear ( ) ; // Clear out array
return NS_OK ;
}
void nsDocAccessible : : FlushEventsCallback ( nsITimer * aTimer , void * aClosure )
{
nsPIAccessibleDocument * accessibleDoc = NS_STATIC_CAST ( nsPIAccessibleDocument * , aClosure ) ;
NS_ASSERTION ( accessibleDoc , " How did we get here without an accessible document? " ) ;
accessibleDoc - > FlushPendingEvents ( ) ;
}
2003-04-28 10:24:52 +00:00
NS_IMETHODIMP nsDocAccessible : : NodeRemovedFromDocument ( nsIDOMEvent * aMutationEvent )
{
// Not implemented yet, see bug 74220
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : NodeInsertedIntoDocument ( nsIDOMEvent * aMutationEvent )
{
// Not implemented yet, see bug 74219
// This is different from NodeInserted() in that it's fired when
// a node is inserted into a document, but isn't necessarily mean that
// it's becoming part of the DOM tree.
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : HandleEvent ( nsIDOMEvent * aEvent )
{
NS_NOTREACHED ( " Should be handled by specific methods like NodeInserted, etc. " ) ;
return NS_OK ;
}
NS_IMETHODIMP nsDocAccessible : : CharacterDataModified ( nsIDOMEvent * aMutationEvent )
{
return NS_OK ;
}
2003-05-15 08:37:38 +00:00
NS_IMETHODIMP nsDocAccessible : : InvalidateCacheSubtree ( nsIDOMNode * aStartNode )
2003-04-28 10:24:52 +00:00
{
// Invalidate cache subtree
// We have to check for accessibles for each dom node by traversing DOM tree
// instead of just the accessible tree, although that would be faster
// Otherwise we might miss the nsAccessNode's that are not nsAccessible's.
if ( ! aStartNode )
2003-05-15 08:37:38 +00:00
return NS_ERROR_FAILURE ;
2003-04-28 10:24:52 +00:00
nsCOMPtr < nsIDOMNode > iterNode ( aStartNode ) , nextNode ;
nsCOMPtr < nsIAccessNode > accessNode ;
do {
2003-05-15 08:37:38 +00:00
GetCachedAccessNode ( iterNode , getter_AddRefs ( accessNode ) ) ;
2003-04-28 10:24:52 +00:00
if ( accessNode ) {
// XXX aaronl todo: accessibles that implement their own subtrees,
// like html combo boxes and xul trees, need to shutdown all of their own
// children when they override Shutdown()
2003-05-15 08:37:38 +00:00
// Don't shutdown our doc object!
if ( accessNode ! = NS_STATIC_CAST ( nsIAccessNode * , this ) ) {
void * uniqueID ;
accessNode - > GetUniqueID ( & uniqueID ) ;
2003-06-19 18:12:52 +00:00
nsCOMPtr < nsPIAccessNode > privateAccessNode ( do_QueryInterface ( accessNode ) ) ;
privateAccessNode - > Shutdown ( ) ;
2003-05-15 08:37:38 +00:00
// Remove from hash table as well
2003-11-12 04:34:17 +00:00
mAccessNodeCache . Remove ( uniqueID ) ;
2003-05-15 08:37:38 +00:00
}
2003-04-28 10:24:52 +00:00
}
iterNode - > GetFirstChild ( getter_AddRefs ( nextNode ) ) ;
if ( nextNode ) {
iterNode = nextNode ;
continue ;
}
if ( iterNode = = aStartNode )
break ;
iterNode - > GetNextSibling ( getter_AddRefs ( nextNode ) ) ;
if ( nextNode ) {
iterNode = nextNode ;
continue ;
}
do {
iterNode - > GetParentNode ( getter_AddRefs ( nextNode ) ) ;
if ( ! nextNode | | nextNode = = aStartNode ) {
2003-05-15 08:37:38 +00:00
return NS_OK ;
2003-04-28 10:24:52 +00:00
}
nextNode - > GetNextSibling ( getter_AddRefs ( iterNode ) ) ;
if ( iterNode )
break ;
iterNode = nextNode ;
} while ( PR_TRUE ) ;
}
while ( iterNode & & iterNode ! = aStartNode ) ;
2003-05-15 08:37:38 +00:00
return NS_OK ;
2003-04-28 10:24:52 +00:00
}
2003-05-15 08:37:38 +00:00
NS_IMETHODIMP
nsDocAccessible : : GetAccessibleInParentChain ( nsIDOMNode * aNode ,
nsIAccessible * * aAccessible )
2003-04-28 10:24:52 +00:00
{
2003-05-15 08:37:38 +00:00
nsCOMPtr < nsIAccessibilityService > accService =
do_GetService ( " @mozilla.org/accessibilityService;1 " ) ;
if ( ! accService )
return nsnull ;
2003-04-28 10:24:52 +00:00
2003-05-15 08:37:38 +00:00
nsCOMPtr < nsIDOMNode > currentNode ( aNode ) , parentNode ;
while ( NS_FAILED ( accService - > GetAccessibleInWeakShell ( currentNode , mWeakShell ,
aAccessible ) ) ) {
currentNode - > GetParentNode ( getter_AddRefs ( parentNode ) ) ;
NS_ASSERTION ( parentNode , " Impossible! Crawled up parent chain without "
" finding accessible. There should have at least "
" been a document accessible at the root. " ) ;
2003-07-09 07:01:46 +00:00
if ( ! parentNode ) {
// XXX Todo We need to figure out why this is happening.
// For now, return safely.
return NS_ERROR_FAILURE ;
}
2003-05-15 08:37:38 +00:00
currentNode = parentNode ;
2003-04-28 10:24:52 +00:00
}
2003-05-15 08:37:38 +00:00
return NS_OK ;
}
void nsDocAccessible : : HandleMutationEvent ( nsIDOMEvent * aEvent , PRUint32 aAccessibleEventType )
{
2003-06-26 08:45:39 +00:00
if ( mBusy = = eBusyStateLoading ) {
// We need this unless bug 90983 is fixed --
// We only want mutation events after the doc is finished loading
return ;
}
2003-05-15 08:37:38 +00:00
nsCOMPtr < nsIDOMMutationEvent > mutationEvent ( do_QueryInterface ( aEvent ) ) ;
NS_ASSERTION ( mutationEvent , " Not a mutation event! " ) ;
nsCOMPtr < nsIDOMEventTarget > domEventTarget ;
mutationEvent - > GetTarget ( getter_AddRefs ( domEventTarget ) ) ;
2003-04-28 10:24:52 +00:00
nsCOMPtr < nsIDOMNode > targetNode ( do_QueryInterface ( domEventTarget ) ) ;
2003-05-15 08:37:38 +00:00
nsCOMPtr < nsIDOMNode > subTreeToInvalidate ;
mutationEvent - > GetRelatedNode ( getter_AddRefs ( subTreeToInvalidate ) ) ;
NS_ASSERTION ( subTreeToInvalidate , " No old sub tree being replaced in DOMSubtreeModified " ) ;
2003-04-28 10:24:52 +00:00
2003-05-15 08:37:38 +00:00
if ( ! targetNode ) {
targetNode = subTreeToInvalidate ;
2003-04-28 10:24:52 +00:00
}
2003-07-22 14:55:22 +00:00
else if ( aAccessibleEventType = = nsIAccessibleEvent : : EVENT_REORDER ) {
2003-05-15 08:37:38 +00:00
subTreeToInvalidate = targetNode ; // targetNode is parent for DOMNodeRemoved event
2003-04-28 10:24:52 +00:00
}
2003-05-15 08:37:38 +00:00
nsCOMPtr < nsIAccessibleDocument > docAccessible ;
GetEventDocAccessible ( subTreeToInvalidate , getter_AddRefs ( docAccessible ) ) ;
2003-10-22 05:43:46 +00:00
if ( ! docAccessible )
return ;
2003-07-09 07:01:46 +00:00
nsCOMPtr < nsPIAccessibleDocument > privateDocAccessible =
do_QueryInterface ( docAccessible ) ;
2003-05-15 08:37:38 +00:00
2003-07-09 07:01:46 +00:00
privateDocAccessible - > InvalidateCacheSubtree ( subTreeToInvalidate ) ;
2003-05-15 08:37:38 +00:00
2003-04-28 10:24:52 +00:00
// We need to get an accessible for the mutation event's target node
// If there is no accessible for that node, we need to keep moving up the parent
// chain so there is some accessible.
// We will use this accessible to fire the accessible mutation event.
// We're guaranteed success, because we will eventually end up at the doc accessible,
// and there is always one of those.
nsCOMPtr < nsIAccessible > accessible ;
2003-05-15 08:37:38 +00:00
docAccessible - > GetAccessibleInParentChain ( targetNode , getter_AddRefs ( accessible ) ) ;
2003-07-09 07:01:46 +00:00
nsCOMPtr < nsPIAccessible > privateAccessible ( do_QueryInterface ( accessible ) ) ;
if ( ! privateAccessible )
return ;
privateAccessible - > InvalidateChildren ( ) ;
2003-04-28 10:24:52 +00:00
# ifdef XP_WIN
2003-05-15 08:37:38 +00:00
// Windows MSAA clients crash if they listen to create or destroy events
2003-07-22 14:55:22 +00:00
aAccessibleEventType = nsIAccessibleEvent : : EVENT_REORDER ;
2003-04-28 10:24:52 +00:00
# endif
2003-07-09 07:01:46 +00:00
privateAccessible - > FireToolkitEvent ( aAccessibleEventType , accessible , nsnull ) ;
2003-04-28 10:24:52 +00:00
}
2003-06-16 10:35:11 +00:00
NS_IMETHODIMP nsDocAccessible : : FireToolkitEvent ( PRUint32 aEvent , nsIAccessible * aAccessible , void * aData )
{
nsCOMPtr < nsIObserverService > obsService =
do_GetService ( " @mozilla.org/observer-service;1 " ) ;
if ( ! obsService ) {
return NS_ERROR_FAILURE ;
}
2003-06-24 08:42:31 +00:00
nsCOMPtr < nsIAccessibleEvent > accEvent = new nsAccessibleEventData ( aEvent , aAccessible , this , aData ) ;
2003-06-16 10:35:11 +00:00
NS_ENSURE_TRUE ( accEvent , NS_ERROR_OUT_OF_MEMORY ) ;
return obsService - > NotifyObservers ( accEvent , NS_ACCESSIBLE_EVENT_TOPIC , nsnull ) ;
}