mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-10 09:19:28 +00:00
Bug 371273. Fire caret/selection events for movement within document when find bar is open. Also fixes MSAA caret position when user is typing/deleting text, and moves MSAA specific code out of cross platform code area. r=surkov
This commit is contained in:
parent
a71973dab1
commit
c2459774c9
@ -38,10 +38,40 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMNode.idl"
|
||||
|
||||
[scriptable, uuid(9124c666-6133-4be6-b3ed-dd0ec35f1e64)]
|
||||
|
||||
[scriptable, uuid(ef372cc1-0fd4-4e71-ac32-64028e680f17)]
|
||||
interface nsIAccessibleCaret : nsISupports
|
||||
{
|
||||
void attachNewSelectionListener(in nsIDOMNode aFocusedNode);
|
||||
void removeSelectionListener();
|
||||
/**
|
||||
* Listen to selection events on the focused control.
|
||||
* Only one control's selection events are listened to at a time, per top-level window.
|
||||
* This will remove the previous control's selection listener.
|
||||
* It will fail if aFocusedNode is a document node -- document selection must be listened
|
||||
* to via addDocSelectionListener().
|
||||
* @param aFocusedNode The node for the focused control
|
||||
*/
|
||||
void setControlSelectionListener(in nsIDOMNode aFocusedNode);
|
||||
|
||||
/**
|
||||
* Stop listening to selection events for any control.
|
||||
* This does not have to be called explicitly in Shutdown() procedures,
|
||||
* because the implementation of nsIAccessibleCaret will guarantee that.
|
||||
*/
|
||||
void clearControlSelectionListener();
|
||||
|
||||
/**
|
||||
* Start listening to selection events for a given document
|
||||
* More than one document's selection events can be listened to
|
||||
* at the same time, by a given nsIAccessibleCaret.
|
||||
* @param aDocument Document to listen to selection events for.
|
||||
*/
|
||||
void addDocSelectionListener(in nsIDOMDocument aDocument);
|
||||
|
||||
/**
|
||||
* Stop listening to selection events for a given document
|
||||
* If the document goes away, this method needs to be called for
|
||||
* that document by the owner of the nsIAccessibleCaret
|
||||
* @param aDocument Document to listen to selection events for.
|
||||
*/
|
||||
void removeDocSelectionListener(in nsIDOMDocument aDocument);
|
||||
};
|
||||
|
@ -56,35 +56,37 @@
|
||||
NS_IMPL_ISUPPORTS_INHERITED2(nsCaretAccessible, nsLeafAccessible, nsIAccessibleCaret, nsISelectionListener)
|
||||
|
||||
nsCaretAccessible::nsCaretAccessible(nsIDOMNode* aDocumentNode, nsIWeakReference* aShell, nsRootAccessible *aRootAccessible):
|
||||
nsLeafAccessible(aDocumentNode, aShell), mVisible(PR_TRUE), mLastCaretOffset(-1), mLastNodeWithCaret(nsnull),
|
||||
mSelectionControllerNode(nsnull), mRootAccessible(aRootAccessible)
|
||||
nsLeafAccessible(aDocumentNode, aShell), mLastCaretOffset(-1), mLastNodeWithCaret(nsnull),
|
||||
mCurrentControl(nsnull), mRootAccessible(aRootAccessible)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCaretAccessible::Shutdown()
|
||||
{
|
||||
mDomSelectionWeak = nsnull;
|
||||
// The caret accessible isn't shut down until the nsRootAccessible owning it is shut down
|
||||
// Each nsDocAccessible, including the nsRootAccessible, is responsible for clearing the
|
||||
// doc selection listeners they registeed in this nsCaretAccessible
|
||||
ClearControlSelectionListener(); // Clear the selection listener for the currently focused control
|
||||
mLastNodeWithCaret = nsnull;
|
||||
mSelectionControllerNode = nsnull;
|
||||
RemoveSelectionListener();
|
||||
mLastUsedSelection = nsnull;
|
||||
|
||||
return nsLeafAccessible::Shutdown();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCaretAccessible::RemoveSelectionListener()
|
||||
NS_IMETHODIMP nsCaretAccessible::ClearControlSelectionListener()
|
||||
{
|
||||
nsCOMPtr<nsISelection> prevDomSel(do_QueryReferent(mDomSelectionWeak));
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(prevDomSel));
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryReferent(mCurrentControlSelection));
|
||||
if (selPrivate) {
|
||||
mDomSelectionWeak = nsnull;
|
||||
mCurrentControlSelection = nsnull;
|
||||
mCurrentControl = nsnull;
|
||||
return selPrivate->RemoveSelectionListener(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCaretAccessible::AttachNewSelectionListener(nsIDOMNode *aCurrentNode)
|
||||
NS_IMETHODIMP nsCaretAccessible::SetControlSelectionListener(nsIDOMNode *aCurrentNode)
|
||||
{
|
||||
mSelectionControllerNode = aCurrentNode;
|
||||
mCurrentControl = aCurrentNode;
|
||||
mLastNodeWithCaret = nsnull;
|
||||
|
||||
// When focus moves such that the caret is part of a new frame selection
|
||||
@ -95,87 +97,74 @@ NS_IMETHODIMP nsCaretAccessible::AttachNewSelectionListener(nsIDOMNode *aCurrent
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
|
||||
if (!doc) // we also should try to QI to document instead (necessary to do when node is a document)
|
||||
doc = do_QueryInterface(aCurrentNode);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aCurrentNode));
|
||||
if (!content)
|
||||
content = doc->GetRootContent(); // If node is not content, use root content
|
||||
// The control selection listener is only for form controls, not for the document
|
||||
// When there is no document, the content will be null
|
||||
if (!content) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
nsPresContext *presContext = presShell->GetPresContext();
|
||||
if (!frame || !presContext)
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
frame->GetSelectionController(presContext, getter_AddRefs(selCon));
|
||||
if (!selCon)
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelection> domSel, prevDomSel(do_QueryReferent(mDomSelectionWeak));
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
|
||||
if (domSel == prevDomSel)
|
||||
return NS_OK; // This is already the selection we're listening to
|
||||
RemoveSelectionListener();
|
||||
|
||||
ClearControlSelectionListener();
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(domSel));
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
if (!selPrivate)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mDomSelectionWeak = do_GetWeakReference(domSel);
|
||||
mCurrentControlSelection = do_GetWeakReference(domSel);
|
||||
return selPrivate->AddSelectionListener(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCaretAccessible::AddDocSelectionListener(nsIDOMDocument *aDoc)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(doc->GetPrimaryShell());
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
return selPrivate->AddSelectionListener(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCaretAccessible::RemoveDocSelectionListener(nsIDOMDocument *aDoc)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(doc->GetPrimaryShell());
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
|
||||
|
||||
return selPrivate->RemoveSelectionListener(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel, PRInt16 aReason)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mSelectionControllerNode);
|
||||
nsCOMPtr<nsISelection> domSel(do_QueryReferent(mDomSelectionWeak));
|
||||
if (!presShell || domSel != aSel)
|
||||
return NS_OK; // Only listening to selection changes in currently focused frame
|
||||
mLastUsedSelection = do_GetWeakReference(aSel);
|
||||
|
||||
nsCOMPtr<nsICaret> caret;
|
||||
presShell->GetCaret(getter_AddRefs(caret));
|
||||
if (!caret)
|
||||
return NS_OK;
|
||||
|
||||
nsRect caretRect;
|
||||
PRBool isCollapsed;
|
||||
caret->GetCaretCoordinates(nsICaret::eTopLevelWindowCoordinates, domSel,
|
||||
&caretRect, &isCollapsed, nsnull);
|
||||
PRBool visible = !caretRect.IsEmpty();
|
||||
if (visible) // Make sure it's visible both by looking at coordinates and visible flag
|
||||
caret->GetCaretVisible(&visible);
|
||||
if (visible != mVisible) {
|
||||
mVisible = visible;
|
||||
#ifdef XP_WIN
|
||||
mRootAccessible->FireToolkitEvent(mVisible? nsIAccessibleEvent::EVENT_SHOW:
|
||||
nsIAccessibleEvent::EVENT_HIDE, this, nsnull);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Support old style MSAA caret move events, which utilize screen coodinates
|
||||
// rather than position within the text
|
||||
nsPresContext *presContext = presShell->GetPresContext();
|
||||
nsIViewManager* viewManager = presShell->GetViewManager();
|
||||
if (!presContext || !viewManager)
|
||||
return NS_OK;
|
||||
nsIView *view = nsnull;
|
||||
viewManager->GetRootView(view);
|
||||
if (!view)
|
||||
return NS_OK;
|
||||
nsIWidget* widget = view->GetWidget();
|
||||
if (!widget)
|
||||
return NS_OK;
|
||||
|
||||
caretRect.x = presContext->AppUnitsToDevPixels(caretRect.x);
|
||||
caretRect.y = presContext->AppUnitsToDevPixels(caretRect.y);
|
||||
caretRect.width = presContext->AppUnitsToDevPixels(caretRect.width);
|
||||
caretRect.height = presContext->AppUnitsToDevPixels(caretRect.height);
|
||||
|
||||
widget->WidgetToScreen(caretRect, mCaretRect);
|
||||
|
||||
mRootAccessible->FireToolkitEvent(nsIAccessibleEvent::EVENT_LOCATION_CHANGE, this, nsnull);
|
||||
#endif
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
|
||||
nsIPresShell *presShell = doc->GetPrimaryShell();
|
||||
NS_ENSURE_TRUE(presShell, NS_OK);
|
||||
|
||||
// Get first nnsIAccessibleText in parent chain and fire caret-move, selection-change event for it
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
@ -183,7 +172,7 @@ NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, ns
|
||||
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
|
||||
// Get accessible from selection's focus node or its parent
|
||||
nsCOMPtr<nsIDOMNode> focusNode;
|
||||
domSel->GetFocusNode(getter_AddRefs(focusNode));
|
||||
aSel->GetFocusNode(getter_AddRefs(focusNode));
|
||||
if (!focusNode) {
|
||||
mLastNodeWithCaret = nsnull;
|
||||
return NS_OK; // No selection
|
||||
@ -230,16 +219,72 @@ NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, ns
|
||||
focusNode, nsnull, PR_FALSE);
|
||||
}
|
||||
|
||||
/** Return the caret's bounds */
|
||||
NS_IMETHODIMP nsCaretAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
|
||||
already_AddRefed<nsICaret>
|
||||
nsCaretAccessible::GetLastCaret(nsRect *aRect, PRBool *aIsVisible)
|
||||
{
|
||||
if (mCaretRect.IsEmpty()) {
|
||||
*aIsVisible = PR_FALSE;
|
||||
if (!mLastNodeWithCaret) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mLastNodeWithCaret);
|
||||
NS_ENSURE_TRUE(presShell, nsnull);
|
||||
|
||||
nsICaret *caret;
|
||||
presShell->GetCaret(&caret);
|
||||
NS_ENSURE_TRUE(caret, nsnull);
|
||||
|
||||
nsRect caretRect;
|
||||
PRBool isCollapsed;
|
||||
nsCOMPtr<nsISelection> caretSelection(do_QueryReferent(mLastUsedSelection));
|
||||
caret->GetCaretCoordinates(nsICaret::eTopLevelWindowCoordinates, caretSelection,
|
||||
aRect, &isCollapsed, nsnull);
|
||||
if (!aRect->IsEmpty()) {
|
||||
caret->GetCaretVisible(aIsVisible);
|
||||
}
|
||||
return caret;
|
||||
}
|
||||
|
||||
/** Return the caret's bounds */
|
||||
NS_IMETHODIMP nsCaretAccessible::GetBounds(PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
|
||||
{
|
||||
*aX = *aY = *aWidth = *aHeight = 0;
|
||||
nsRect caretRect;
|
||||
PRBool isVisible;
|
||||
nsCOMPtr<nsICaret> caret = GetLastCaret(&caretRect, &isVisible);
|
||||
if (!caret || caretRect.IsEmpty()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*x = mCaretRect.x;
|
||||
*y = mCaretRect.y;
|
||||
*width = mCaretRect.width;
|
||||
*height = mCaretRect.height;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mLastNodeWithCaret);
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
|
||||
nsPresContext *presContext = presShell->GetPresContext();
|
||||
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
|
||||
|
||||
nsIViewManager* viewManager = presShell->GetViewManager();
|
||||
NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
|
||||
|
||||
nsIView *view = nsnull;
|
||||
viewManager->GetRootView(view);
|
||||
NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
|
||||
|
||||
nsIWidget* widget = view->GetWidget();
|
||||
NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
|
||||
|
||||
caretRect.x = presContext->AppUnitsToDevPixels(caretRect.x);
|
||||
caretRect.y = presContext->AppUnitsToDevPixels(caretRect.y);
|
||||
caretRect.width = presContext->AppUnitsToDevPixels(caretRect.width);
|
||||
caretRect.height = presContext->AppUnitsToDevPixels(caretRect.height);
|
||||
|
||||
nsRect caretScreenRect;
|
||||
widget->WidgetToScreen(caretRect, caretScreenRect);
|
||||
|
||||
*aX = caretScreenRect.x;
|
||||
*aY = caretScreenRect.y;
|
||||
*aWidth = caretScreenRect.width;
|
||||
*aHeight = caretScreenRect.height;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -252,10 +297,21 @@ NS_IMETHODIMP nsCaretAccessible::GetRole(PRUint32 *_retval)
|
||||
NS_IMETHODIMP
|
||||
nsCaretAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
||||
{
|
||||
*aState = 0;
|
||||
if (aExtraState)
|
||||
*aExtraState = 0;
|
||||
|
||||
*aState = mVisible? 0: nsIAccessibleStates::STATE_INVISIBLE;
|
||||
NS_ENSURE_TRUE(mLastNodeWithCaret, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShellFor(mLastNodeWithCaret);
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
|
||||
nsRect caretRect;
|
||||
PRBool isVisible;
|
||||
GetLastCaret(&caretRect, &isVisible);
|
||||
if (!isVisible) {
|
||||
*aState = nsIAccessibleStates::STATE_INVISIBLE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -49,11 +49,23 @@ class nsRootAccessible;
|
||||
|
||||
/*
|
||||
* This special accessibility class is for the caret, which is really the currently focused selection.
|
||||
* There is only 1 visible caret per top level window (nsRootAccessible)
|
||||
* There is only 1 visible caret per top level window (nsRootAccessible),
|
||||
* However, there may be several visible selections.
|
||||
*
|
||||
* The important selections are the one owned by each document, and the one in the currently focused control.
|
||||
*
|
||||
* The caret accesible does not exist within the normal accessible tree; it lives in a different world.
|
||||
* In MSAA, it is retrieved with via the WM_GETOBJECT message with lParam = OBJID_CARET,
|
||||
* (as opposed to the root accessible tree for a window which is retrieved with OBJID_CLIENT)
|
||||
* In ATK, the caret accessible is never exposed as an accessible object, but is used to fire
|
||||
* caret move and selection change events.
|
||||
*
|
||||
* The caret accessible is owned by the nsRootAccessible for the top level window that it's in.
|
||||
* The nsRootAccessible needs to tell the nsCaretAccessible about focus changes via
|
||||
* setControlSelectionListener().
|
||||
* Each nsDocAccessible needs to tell the nsCaretAccessible owned by the root to
|
||||
* listen for selection events via addDocSelectionListener() and then needs to remove the
|
||||
* selection listener when the doc goes away via removeDocSelectionListener().
|
||||
*/
|
||||
|
||||
class nsCaretAccessible : public nsLeafAccessible, public nsIAccessibleCaret, public nsISelectionListener
|
||||
@ -72,9 +84,8 @@ public:
|
||||
NS_IMETHOD GetPreviousSibling(nsIAccessible **_retval);
|
||||
|
||||
/* ----- nsIAccessibleCaret ------ */
|
||||
NS_IMETHOD AttachNewSelectionListener(nsIDOMNode *aFocusedNode);
|
||||
NS_IMETHOD RemoveSelectionListener();
|
||||
|
||||
NS_DECL_NSIACCESSIBLECARET
|
||||
|
||||
/* ----- nsISelectionListener ---- */
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
|
||||
@ -89,15 +100,22 @@ public:
|
||||
NS_IMETHOD Shutdown();
|
||||
|
||||
private:
|
||||
nsRect mCaretRect;
|
||||
PRBool mVisible;
|
||||
PRInt32 mLastCaretOffset;
|
||||
// The currently focused control -- never a document.
|
||||
// We listen to selection for one control at a time (the focused one)
|
||||
// Document selection is handled separately via additional listeners on all active documents
|
||||
// The current control is set via SetControlSelectionListener()
|
||||
nsCOMPtr<nsIDOMNode> mCurrentControl; // Selection controller for the currently focused control
|
||||
nsCOMPtr<nsIWeakReference> mCurrentControlSelection;
|
||||
|
||||
// Info for the the last selection event
|
||||
// If it was on a control, then mLastUsedSelection == mCurrentControlSelection
|
||||
// Otherwise, it's for a document where the selection changed
|
||||
nsCOMPtr<nsIWeakReference> mLastUsedSelection; // Weak ref to nsISelection
|
||||
nsCOMPtr<nsIDOMNode> mLastNodeWithCaret;
|
||||
nsCOMPtr<nsIDOMNode> mSelectionControllerNode;
|
||||
// mListener is not a com pointer. It's a copy of the listener in the nsRootAccessible owner.
|
||||
//See nsRootAccessible.h for details of the lifetime if this listener
|
||||
PRInt32 mLastCaretOffset;
|
||||
already_AddRefed<nsICaret> GetLastCaret(nsRect *aRect, PRBool *aIsVisible);
|
||||
|
||||
nsRootAccessible *mRootAccessible;
|
||||
nsCOMPtr<nsIWeakReference> mDomSelectionWeak;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -663,6 +663,19 @@ nsresult nsDocAccessible::AddEventListeners()
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
|
||||
docShellTreeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
|
||||
if (rootTreeItem) {
|
||||
nsCOMPtr<nsIAccessibleDocument> rootAccDoc = GetDocAccessibleFor(rootTreeItem, PR_TRUE);
|
||||
nsCOMPtr<nsIAccessible> caretAccessible;
|
||||
rootAccDoc->GetCaretAccessible(getter_AddRefs(caretAccessible));
|
||||
nsCOMPtr<nsIAccessibleCaret> caretAccessibleIface(do_QueryInterface(caretAccessible));
|
||||
if (caretAccessibleIface) {
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
|
||||
caretAccessibleIface->AddDocSelectionListener(domDoc);
|
||||
}
|
||||
}
|
||||
|
||||
// add document observer
|
||||
mDocument->AddObserver(this);
|
||||
return NS_OK;
|
||||
@ -682,6 +695,17 @@ nsresult nsDocAccessible::RemoveEventListeners()
|
||||
mScrollWatchTimer = nsnull;
|
||||
}
|
||||
|
||||
nsRefPtr<nsRootAccessible> rootAccessible(GetRootAccessible());
|
||||
if (rootAccessible) {
|
||||
nsCOMPtr<nsIAccessible> caretAccessible;
|
||||
rootAccessible->GetCaretAccessible(getter_AddRefs(caretAccessible));
|
||||
nsCOMPtr<nsIAccessibleCaret> caretAccessibleIface(do_QueryInterface(caretAccessible));
|
||||
if (caretAccessibleIface) {
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
|
||||
caretAccessibleIface->RemoveDocSelectionListener(domDoc);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
|
||||
NS_ENSURE_TRUE(docShellTreeItem, NS_ERROR_FAILURE);
|
||||
@ -1254,10 +1278,10 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
|
||||
PRInt32 selectionCount;
|
||||
accessibleText->GetSelectionCount(&selectionCount);
|
||||
if (selectionCount) { // There's a selection so fire selection change as well
|
||||
FireToolkitEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
|
||||
accessible, nsnull);
|
||||
FireToolkitEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
|
||||
accessible, nsnull);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
FireAccessibleEvent(accessibleEvent);
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsPIAccessibleDocument.h"
|
||||
#include "nsIAccessibleEvent.h"
|
||||
#include "nsIArray.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDocumentObserver.h"
|
||||
#include "nsIEditor.h"
|
||||
|
@ -345,8 +345,9 @@ nsresult nsRootAccessible::RemoveEventListeners()
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("pagehide"), this, PR_TRUE);
|
||||
}
|
||||
|
||||
if (mCaretAccessible) {
|
||||
mCaretAccessible->RemoveSelectionListener();
|
||||
nsCOMPtr<nsPIAccessNode> caretAccessNode(do_QueryInterface(mCaretAccessible));
|
||||
if (caretAccessNode) {
|
||||
caretAccessNode->Shutdown();
|
||||
mCaretAccessible = nsnull;
|
||||
}
|
||||
|
||||
@ -440,7 +441,7 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
|
||||
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
|
||||
nsCOMPtr<nsIDOMNode> realFocusedNode(do_QueryInterface(domEventTarget));
|
||||
if (realFocusedNode) {
|
||||
mCaretAccessible->AttachNewSelectionListener(realFocusedNode);
|
||||
mCaretAccessible->SetControlSelectionListener(realFocusedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -896,7 +897,6 @@ NS_IMETHODIMP nsRootAccessible::Shutdown()
|
||||
if (!mWeakShell) {
|
||||
return NS_OK; // Already shutdown
|
||||
}
|
||||
mCaretAccessible = nsnull;
|
||||
if (mFireFocusTimer) {
|
||||
mFireFocusTimer->Cancel();
|
||||
mFireFocusTimer = nsnull;
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsINodeInfo.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsRootAccessible.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsIView.h"
|
||||
@ -1493,55 +1494,59 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
|
||||
if (!accessible)
|
||||
return NS_OK;
|
||||
|
||||
PRInt32 childID, worldID = OBJID_CLIENT;
|
||||
PRUint32 role = ROLE_SYSTEM_TEXT; // Default value
|
||||
|
||||
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(accessible));
|
||||
NS_ENSURE_STATE(accessNode);
|
||||
|
||||
HWND hWnd = 0;
|
||||
|
||||
if (NS_SUCCEEDED(accessible->GetRole(&role)) && role == ROLE_SYSTEM_CARET) {
|
||||
childID = CHILDID_SELF;
|
||||
worldID = OBJID_CARET;
|
||||
} else {
|
||||
childID = GetChildIDFor(accessible); // get the id for the accessible
|
||||
if (!childID)
|
||||
return NS_OK; // Can't fire an event without a child ID
|
||||
|
||||
// See if we're in a scrollable area with its own window
|
||||
nsCOMPtr<nsIAccessible> newAccessible;
|
||||
if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
|
||||
// Don't use frame from current accessible when we're hiding that
|
||||
// accessible.
|
||||
accessible->GetParent(getter_AddRefs(newAccessible));
|
||||
} else {
|
||||
newAccessible = accessible;
|
||||
if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
|
||||
// Fire additional old-style MSAA caret events as well as the IA2 event
|
||||
nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible();
|
||||
if (rootAccessible) {
|
||||
nsCOMPtr<nsIAccessible> caretAccessible;
|
||||
void* handle = nsnull;
|
||||
rootAccessible->GetWindowHandle(&handle);
|
||||
NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, (HWND)handle, OBJID_CARET, CHILDID_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIAccessNode> privateAccessNode =
|
||||
do_QueryInterface(newAccessible);
|
||||
if (privateAccessNode) {
|
||||
nsIFrame *frame = privateAccessNode->GetFrame();
|
||||
if (frame) {
|
||||
nsIWidget *window = frame->GetWindow();
|
||||
PRBool isVisible;
|
||||
window->IsVisible(isVisible);
|
||||
if (isVisible) {
|
||||
// Short explanation:
|
||||
// If HWND for frame is inside a hidden window, fire the event on the
|
||||
// containing document's visible window.
|
||||
//
|
||||
// Long explanation:
|
||||
// This is really just to fix combo boxes with JAWS. Window-Eyes already worked with
|
||||
// combo boxes because they use the value change event in the closed combo box
|
||||
// case. JAWS will only pay attention to the focus events on the list items.
|
||||
// The JAWS developers haven't fixed that, so we'll use the focus events to make JAWS work.
|
||||
// However, JAWS is ignoring events on a hidden window. So, in order to fix the bug where
|
||||
// JAWS doesn't echo the current option as it changes in a closed combo box, we need to use an
|
||||
// ensure that we never fire an event with an HWND for a hidden window.
|
||||
hWnd = (HWND)frame->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
|
||||
}
|
||||
+ PRInt32 childID = GetChildIDFor(accessible); // get the id for the accessible
|
||||
+ if (!childID)
|
||||
+ return NS_OK; // Can't fire an event without a child ID
|
||||
+
|
||||
+ // See if we're in a scrollable area with its own window
|
||||
+ nsCOMPtr<nsIAccessible> newAccessible;
|
||||
+ if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
|
||||
+ // Don't use frame from current accessible when we're hiding that
|
||||
+ // accessible.
|
||||
+ accessible->GetParent(getter_AddRefs(newAccessible));
|
||||
+ } else {
|
||||
+ newAccessible = accessible;
|
||||
+ }
|
||||
|
||||
HWND hWnd = 0;
|
||||
nsCOMPtr<nsPIAccessNode> privateAccessNode =
|
||||
do_QueryInterface(newAccessible);
|
||||
if (privateAccessNode) {
|
||||
nsIFrame *frame = privateAccessNode->GetFrame();
|
||||
if (frame) {
|
||||
nsIWidget *window = frame->GetWindow();
|
||||
PRBool isVisible;
|
||||
window->IsVisible(isVisible);
|
||||
if (isVisible) {
|
||||
// Short explanation:
|
||||
// If HWND for frame is inside a hidden window, fire the event on the
|
||||
// containing document's visible window.
|
||||
//
|
||||
// Long explanation:
|
||||
// This is really just to fix combo boxes with JAWS. Window-Eyes already worked with
|
||||
// combo boxes because they use the value change event in the closed combo box
|
||||
// case. JAWS will only pay attention to the focus events on the list items.
|
||||
// The JAWS developers haven't fixed that, so we'll use the focus events to make JAWS work.
|
||||
// However, JAWS is ignoring events on a hidden window. So, in order to fix the bug where
|
||||
// JAWS doesn't echo the current option as it changes in a closed combo box, we need to use an
|
||||
// ensure that we never fire an event with an HWND for a hidden window.
|
||||
hWnd = (HWND)frame->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1562,7 +1567,7 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
|
||||
// * Client area window: text drawing window & MSAA event window
|
||||
|
||||
// Fire MSAA event for client area window.
|
||||
NotifyWinEvent(winEvent, hWnd, worldID, childID);
|
||||
NotifyWinEvent(winEvent, hWnd, OBJID_CLIENT, childID);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user