gecko/accessible/src/base/nsDocAccessible.h

457 lines
15 KiB
C
Raw Normal View History

/* -*- 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):
* Original Author: Aaron Leventhal (aaronl@netscape.com)
*
* Alternatively, the contents of this file may be used under the terms of
* 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"),
* 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 ***** */
#ifndef _nsDocAccessible_H_
#define _nsDocAccessible_H_
#include "nsIAccessibleDocument.h"
#include "nsHyperTextAccessibleWrap.h"
#include "nsEventShell.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "nsIDocument.h"
#include "nsIDocumentObserver.h"
#include "nsIEditor.h"
#include "nsIObserver.h"
#include "nsIScrollPositionListener.h"
#include "nsITimer.h"
#include "nsIWeakReference.h"
#include "nsCOMArray.h"
#include "nsIDocShellTreeNode.h"
class nsIScrollableView;
const PRUint32 kDefaultCacheSize = 256;
#define NS_DOCACCESSIBLE_IMPL_CID \
{ /* 5641921c-a093-4292-9dca-0b51813db57d */ \
0x5641921c, \
0xa093, \
0x4292, \
{ 0x9d, 0xca, 0x0b, 0x51, 0x81, 0x3d, 0xb5, 0x7d } \
}
class nsDocAccessible : public nsHyperTextAccessibleWrap,
public nsIAccessibleDocument,
public nsIDocumentObserver,
public nsIObserver,
public nsIScrollPositionListener,
public nsSupportsWeakReference
{
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDocAccessible, nsAccessible)
NS_DECL_NSIACCESSIBLEDOCUMENT
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOCACCESSIBLE_IMPL_CID)
NS_DECL_NSIOBSERVER
public:
using nsAccessible::GetParent;
nsDocAccessible(nsIDocument *aDocument, nsIContent *aRootContent,
nsIWeakReference* aShell);
virtual ~nsDocAccessible();
// nsIAccessible
NS_IMETHOD GetName(nsAString& aName);
NS_IMETHOD GetDescription(nsAString& aDescription);
NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes);
NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
NS_IMETHOD TakeFocus(void);
// nsIScrollPositionListener
virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) {}
virtual void ScrollPositionDidChange(nscoord aX, nscoord aY);
// nsIDocumentObserver
NS_DECL_NSIDOCUMENTOBSERVER
// nsAccessNode
virtual PRBool Init();
virtual void Shutdown();
virtual nsIFrame* GetFrame();
virtual PRBool IsDefunct();
virtual nsINode* GetNode() const { return mDocument; }
virtual nsIDocument* GetDocumentNode() const { return mDocument; }
// nsAccessible
virtual PRUint32 NativeRole();
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState);
virtual void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry);
#ifdef DEBUG_ACCDOCMGR
virtual nsresult HandleAccEvent(AccEvent* aAccEvent);
#endif
// nsIAccessibleText
NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
// nsDocAccessible
/**
* Return true if associated DOM document was loaded and isn't unloading.
*/
PRBool IsContentLoaded() const
{
return mDocument && mDocument->IsVisible() &&
(mDocument->IsShowing() || mIsLoaded);
}
/**
* Marks this document as loaded or loading, used to expose busy state.
* The loaded flag has special meaning for error pages and used as workaround
* to make IsContentLoaded() return correct result since these pages do not
* receive pageshow event and as consequence nsIDocument::IsShowing() returns
* false.
*/
void MarkAsLoaded() { mIsLoaded = PR_TRUE; }
void MarkAsLoading() { mIsLoaded = PR_FALSE; }
/**
* Return a native window handler or pointer depending on platform.
*/
virtual void* GetNativeWindow() const;
/**
* Return the parent document.
*/
nsDocAccessible* ParentDocument() const
{ return mParent ? mParent->GetDocAccessible() : nsnull; }
/**
* Return the child document count.
*/
PRUint32 ChildDocumentCount() const
{ return mChildDocuments.Length(); }
/**
* Return the child document at the given index.
*/
nsDocAccessible* GetChildDocumentAt(PRUint32 aIndex) const
{ return mChildDocuments.SafeElementAt(aIndex, nsnull); }
/**
* Non-virtual method to fire a delayed event after a 0 length timeout.
*
* @param aEventType [in] the nsIAccessibleEvent event type
* @param aDOMNode [in] DOM node the accesible event should be fired for
* @param aAllowDupes [in] rule to process an event (see EEventRule constants)
*/
nsresult FireDelayedAccessibleEvent(PRUint32 aEventType, nsINode *aNode,
AccEvent::EEventRule aAllowDupes = AccEvent::eRemoveDupes,
Bug 540285 - stop explicit usage of nsAccEvent::prepareEvent, r=marcoz, davidb, ginn --HG-- rename : accessible/tests/mochitest/Makefile.in => accessible/tests/mochitest/events/Makefile.in rename : accessible/tests/mochitest/test_events_caretmove.html => accessible/tests/mochitest/events/test_caretmove.html rename : accessible/tests/mochitest/test_events_coalescence.html => accessible/tests/mochitest/events/test_coalescence.html rename : accessible/tests/mochitest/test_events_doc.html => accessible/tests/mochitest/events/test_doc.html rename : accessible/tests/mochitest/test_events_draganddrop.html => accessible/tests/mochitest/events/test_dragndrop.html rename : accessible/tests/mochitest/test_events_flush.html => accessible/tests/mochitest/events/test_flush.html rename : accessible/tests/mochitest/test_events_focus.html => accessible/tests/mochitest/events/test_focus.html rename : accessible/tests/mochitest/test_events_focus.xul => accessible/tests/mochitest/events/test_focus.xul rename : accessible/tests/mochitest/test_events_focusdoc.html => accessible/tests/mochitest/events/test_focusdoc.html rename : accessible/tests/mochitest/test_events_mutation.html => accessible/tests/mochitest/events/test_mutation.html rename : accessible/tests/mochitest/test_events_scroll.xul => accessible/tests/mochitest/events/test_scroll.xul rename : accessible/tests/mochitest/test_events_tree.xul => accessible/tests/mochitest/events/test_tree.xul rename : accessible/tests/mochitest/test_events_valuechange.html => accessible/tests/mochitest/events/test_valuechange.html
2010-01-20 03:16:32 -08:00
EIsFromUserInput aIsFromUserInput = eAutoDetect);
/**
* Fire accessible event after timeout.
*
* @param aEvent [in] the event to fire
*/
nsresult FireDelayedAccessibleEvent(AccEvent* aEvent);
/**
* Return the cached accessible by the given DOM node if it's in subtree of
* this document accessible or the document accessible itself, otherwise null.
*
* @return the accessible object
*/
nsAccessible* GetCachedAccessible(nsINode* aNode);
/**
* Return the cached accessible by the given unique ID within this document.
*
* @note the unique ID matches with the uniqueID() of nsAccessNode
*
* @param aUniqueID [in] the unique ID used to cache the node.
*/
nsAccessible* GetCachedAccessibleByUniqueID(void* aUniqueID)
{
return UniqueID() == aUniqueID ?
this : mAccessibleCache.GetWeak(aUniqueID);
}
/**
* Return the cached accessible by the given unique ID looking through
* this and nested documents.
*/
nsAccessible* GetCachedAccessibleByUniqueIDInSubtree(void* aUniqueID);
/**
* Return true if the given ID is referred by relation attribute.
*
* @note Different elements may share the same ID if they are hosted inside
* XBL bindings. Be careful the result of this method may be senseless
* while it's called for XUL elements (where XBL is used widely).
*/
PRBool IsDependentID(const nsAString& aID) const
{ return mDependentIDsHash.Get(aID, nsnull); }
/**
* Initialize the newly created accessible and put it into document caches.
*
* @param aAccessible [in] created accessible
* @param aRoleMapEntry [in] the role map entry role the ARIA role or nsnull
* if none
*/
bool BindToDocument(nsAccessible* aAccessible, nsRoleMapEntry* aRoleMapEntry);
/**
* Remove from document and shutdown the given accessible.
*/
void UnbindFromDocument(nsAccessible* aAccessible);
/**
* Process the event when the queue of pending events is untwisted. Fire
* accessible events as result of the processing.
*/
void ProcessPendingEvent(AccEvent* aEvent);
/**
* Update the accessible tree.
*/
void UpdateTree(nsIContent* aContainerNode, nsIContent* aStartChildNode,
nsIContent* aEndChildNode, PRBool aIsInsert);
/**
* Recreate an accessible, results in hide/show events pair.
*/
void RecreateAccessible(nsINode* aNode);
/**
* Used to notify the document that the accessible caching is started or
* finished.
*
* While children are cached we may encounter the case there's no accessible
* for referred content by related accessible. Keep the caching root and
* these related nodes to invalidate their containers after root caching.
*/
void NotifyOfCachingStart(nsAccessible* aAccessible);
void NotifyOfCachingEnd(nsAccessible* aAccessible);
protected:
// nsAccessible
virtual void CacheChildren();
// nsDocAccessible
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
virtual nsresult AddEventListeners();
virtual nsresult RemoveEventListeners();
void AddScrollListener();
void RemoveScrollListener();
/**
* Append the given document accessible to this document's child document
* accessibles.
*/
bool AppendChildDocument(nsDocAccessible* aChildDocument)
{
return mChildDocuments.AppendElement(aChildDocument);
}
/**
* Remove the given document accessible from this document's child document
* accessibles.
*/
void RemoveChildDocument(nsDocAccessible* aChildDocument)
{
mChildDocuments.RemoveElement(aChildDocument);
}
/**
* Add dependent IDs pointed by accessible element by relation attribute to
* cache. If the relation attribute is missed then all relation attributes
* are checked.
*
* @param aRelProvider [in] accessible that element has relation attribute
* @param aRelAttr [in, optional] relation attribute
*/
void AddDependentIDsFor(nsAccessible* aRelProvider,
nsIAtom* aRelAttr = nsnull);
/**
* Remove dependent IDs pointed by accessible element by relation attribute
* from cache. If the relation attribute is absent then all relation
* attributes are checked.
*
* @param aRelProvider [in] accessible that element has relation attribute
* @param aRelAttr [in, optional] relation attribute
*/
void RemoveDependentIDsFor(nsAccessible* aRelProvider,
nsIAtom* aRelAttr = nsnull);
static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
/**
* Fires accessible events when attribute is changed.
*
* @param aContent - node that attribute is changed for
* @param aNameSpaceID - namespace of changed attribute
* @param aAttribute - changed attribute
*/
void AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aAttribute);
/**
* Fires accessible events when ARIA attribute is changed.
*
* @param aContent - node that attribute is changed for
* @param aAttribute - changed attribute
*/
void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
/**
* Fire text changed event for character data changed. The method is used
* from nsIMutationObserver methods.
*
* @param aContent the text node holding changed data
* @param aInfo info structure describing how the data was changed
* @param aIsInserted the flag pointed whether removed or inserted
* characters should be cause of event
*/
void FireTextChangeEventForText(nsIContent *aContent,
CharacterDataChangeInfo* aInfo,
PRBool aIsInserted);
/**
* Fire a value change event for the the given accessible if it is a text
* field (has a ROLE_ENTRY).
*/
void FireValueChangeForTextFields(nsAccessible *aAccessible);
/**
* Helper for UpdateTree() method. Go down to DOM subtree and updates
* accessible tree. Return one of these flags.
*/
enum EUpdateTreeFlags {
eNoAccessible = 0,
eAccessible = 1,
eAlertAccessible = 2
};
PRUint32 UpdateTreeInternal(nsAccessible* aContainer,
nsIContent* aStartNode,
nsIContent* aEndNode,
PRBool aIsInsert,
PRBool aFireEvents,
EIsFromUserInput aFromUserInput);
/**
* Remove accessibles in subtree from node to accessible map.
*/
void UncacheChildrenInSubtree(nsAccessible* aRoot);
/**
* Shutdown any cached accessible in the subtree.
*
* @param aAccessible [in] the root of the subrtee to invalidate accessible
* child/parent refs in
*/
void ShutdownChildrenInSubtree(nsAccessible *aAccessible);
/**
* Cache of accessibles within this document accessible.
*/
nsAccessibleHashtable mAccessibleCache;
nsDataHashtable<nsPtrHashKey<const nsINode>, nsAccessible*>
mNodeToAccessibleMap;
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsITimer> mScrollWatchTimer;
PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
protected:
nsRefPtr<nsAccEventQueue> mEventQueue;
/**
* Specifies if the document was loaded, used for error pages only.
*/
PRPackedBool mIsLoaded;
static PRUint32 gLastFocusedAccessiblesState;
static nsIAtom *gLastFocusedFrameType;
nsTArray<nsRefPtr<nsDocAccessible> > mChildDocuments;
/**
* A storage class for pairing content with one of its relation attributes.
*/
class AttrRelProvider
{
public:
AttrRelProvider(nsIAtom* aRelAttr, nsIContent* aContent) :
mRelAttr(aRelAttr), mContent(aContent) { }
nsIAtom* mRelAttr;
nsIContent* mContent;
private:
AttrRelProvider();
AttrRelProvider(const AttrRelProvider&);
AttrRelProvider& operator =(const AttrRelProvider&);
};
/**
* The cache of IDs pointed by relation attributes.
*/
typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
nsClassHashtable<nsStringHashKey, AttrRelProviderArray> mDependentIDsHash;
friend class RelatedAccIterator;
/**
* Used for our caching algorithm. We store the root of the tree that needs
* caching, the list of nodes that should be invalidated, and whether we are
* processing the invalidation list.
*
* @see NotifyOfCachingStart/NotifyOfCachingEnd
*/
nsAccessible* mCacheRoot;
nsTArray<nsIContent*> mInvalidationList;
PRBool mIsPostCacheProcessing;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,
NS_DOCACCESSIBLE_IMPL_CID)
#endif