Bug 460417 - invalid handling of selection changes inside input element, r=aaronlev, marcoz, sr=neil

This commit is contained in:
Alexander Surkov 2008-10-28 16:43:07 +08:00
Родитель 53887a1659
Коммит 7d9f6d351c
4 изменённых файлов: 136 добавлений и 83 удалений

Просмотреть файл

@ -442,6 +442,78 @@ nsAccUtils::GetARIATreeItemParent(nsIAccessible *aStartTreeItem,
}
}
already_AddRefed<nsIAccessibleText>
nsAccUtils::GetTextAccessibleFromSelection(nsISelection *aSelection,
nsIDOMNode **aNode)
{
// Get accessible from selection's focus DOM point (the DOM point where
// selection is ended).
nsCOMPtr<nsIDOMNode> resultNode;
aSelection->GetFocusNode(getter_AddRefs(resultNode));
if (!resultNode)
return nsnull;
// Get DOM node that focus DOM point points to.
nsCOMPtr<nsIContent> content(do_QueryInterface(resultNode));
if (content && content->IsNodeOfType(nsINode::eELEMENT)) {
PRInt32 offset = 0;
aSelection->GetFocusOffset(&offset);
PRInt32 childCount = static_cast<PRInt32>(content->GetChildCount());
NS_ASSERTION(offset >= 0 && offset <= childCount,
"Wrong focus offset in selection!");
// The offset can be after last child of container node that means DOM point
// is placed immediately after the last child. In this case use focusNode
// as result node.
if (offset != childCount) {
nsCOMPtr<nsIContent> child = content->GetChildAt(offset);
resultNode = do_QueryInterface(child);
}
}
nsIAccessibilityService *accService = nsAccessNode::GetAccService();
// Get text accessible containing the result node.
while (resultNode) {
// Make sure to get the correct starting node for selection events inside
// XBL content trees.
nsCOMPtr<nsIDOMNode> relevantNode;
nsresult rv = accService->
GetRelevantContentNodeFor(resultNode, getter_AddRefs(relevantNode));
if (NS_FAILED(rv))
return nsnull;
if (relevantNode)
resultNode.swap(relevantNode);
nsCOMPtr<nsIContent> content = do_QueryInterface(resultNode);
if (!content || !content->IsNodeOfType(nsINode::eTEXT)) {
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleFor(resultNode, getter_AddRefs(accessible));
if (accessible) {
nsIAccessibleText *textAcc = nsnull;
CallQueryInterface(accessible, &textAcc);
if (textAcc) {
if (aNode)
NS_ADDREF(*aNode = resultNode);
return textAcc;
}
}
}
nsCOMPtr<nsIDOMNode> parentNode;
resultNode->GetParentNode(getter_AddRefs(parentNode));
resultNode.swap(parentNode);
}
NS_NOTREACHED("No nsIAccessibleText for selection change event!");
return nsnull;
}
nsresult
nsAccUtils::ConvertToScreenCoords(PRInt32 aX, PRInt32 aY,
PRUint32 aCoordinateType,

Просмотреть файл

@ -42,6 +42,7 @@
#include "nsIAccessible.h"
#include "nsIAccessNode.h"
#include "nsIAccessibleRole.h"
#include "nsIAccessibleText.h"
#include "nsARIAMap.h"
#include "nsIDOMNode.h"
@ -160,6 +161,18 @@ public:
nsIContent *aStartTreeItemContent,
nsIAccessible **aTreeItemParent);
/**
* Return text accessible containing focus point of the given selection.
* Used for normal and misspelling selection changes processing.
*
* @param aSelection [in] the given selection
* @param aNode [out, optional] the DOM node of text accessible
* @return text accessible
*/
static already_AddRefed<nsIAccessibleText>
GetTextAccessibleFromSelection(nsISelection *aSelection,
nsIDOMNode **aNode = nsnull);
/**
* Converts the given coordinates to coordinates relative screen.
*

Просмотреть файл

@ -195,6 +195,20 @@ nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc,
nsISelection *aSel,
PRInt16 aReason)
{
NS_ENSURE_ARG(aDoc);
nsCOMPtr<nsIDOMNode> docNode(do_QueryInterface(aDoc));
nsCOMPtr<nsIAccessibleDocument> accDoc =
nsAccessNode::GetDocAccessibleFor(docNode);
// Don't fire events until document is loaded.
if (!accDoc)
return NS_OK;
nsCOMPtr<nsIAccessible> accForDoc(do_QueryInterface(accDoc));
if (nsAccUtils::State(accForDoc) & nsIAccessibleStates::STATE_BUSY)
return NS_OK;
nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSel));
PRInt16 type = 0;
@ -217,72 +231,22 @@ nsCaretAccessible::NormalSelectionChanged(nsIDOMDocument *aDoc,
mLastUsedSelection = do_GetWeakReference(aSel);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_ENSURE_TRUE(doc, NS_OK);
nsIPresShell *presShell = doc->GetPrimaryShell();
NS_ENSURE_TRUE(presShell, NS_OK);
PRInt32 rangeCount = 0;
nsresult rv = aSel->GetRangeCount(&rangeCount);
NS_ENSURE_SUCCESS(rv, rv);
// Get first nsIAccessibleText in parent chain and fire caret-move, selection-change event for it
nsCOMPtr<nsIAccessible> accessible;
nsIAccessibilityService *accService = mRootAccessible->GetAccService();
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
// Get accessible from selection's focus node or its parent
nsCOMPtr<nsIDOMNode> focusNode;
aSel->GetFocusNode(getter_AddRefs(focusNode));
if (!focusNode) {
if (rangeCount == 0) {
mLastTextAccessible = nsnull;
return NS_OK; // No selection
}
nsCOMPtr<nsIAccessibleDocument> docAccessible =
nsAccessNode::GetDocAccessibleFor(focusNode);
nsCOMPtr<nsIAccessible> accessibleForDoc =
do_QueryInterface(docAccessible);
if (!accessibleForDoc) {
return NS_OK;
}
PRUint32 docState;
accessibleForDoc->GetFinalState(&docState, nsnull);
if (docState & nsIAccessibleStates::STATE_BUSY) {
return NS_OK; // Don't fire caret moves until doc loaded
}
// Get focused node.
nsCOMPtr<nsIContent> focusContainer(do_QueryInterface(focusNode));
if (focusContainer && focusContainer->IsNodeOfType(nsINode::eELEMENT)) {
PRInt32 focusOffset = 0;
aSel->GetFocusOffset(&focusOffset);
nsCOMPtr<nsIContent> focusContent = focusContainer->GetChildAt(focusOffset);
focusNode = do_QueryInterface(focusContent);
}
// Get relevant accessible for the focused node.
nsCOMPtr<nsIAccessibleText> textAcc;
while (focusNode) {
// Make sure to get the correct starting node for selection events inside XBL content trees
nsCOMPtr<nsIDOMNode> relevantNode;
if (NS_SUCCEEDED(accService->GetRelevantContentNodeFor(focusNode, getter_AddRefs(relevantNode))) && relevantNode) {
focusNode = relevantNode;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(focusNode);
if (!content || !content->IsNodeOfType(nsINode::eTEXT)) {
accService->GetAccessibleInShell(focusNode, presShell, getter_AddRefs(accessible));
textAcc = do_QueryInterface(accessible);
if (textAcc) {
break;
}
}
nsCOMPtr<nsIDOMNode> parentNode;
focusNode->GetParentNode(getter_AddRefs(parentNode));
focusNode.swap(parentNode);
}
NS_ASSERTION(textAcc, "No nsIAccessibleText for caret move event!"); // No nsIAccessibleText for caret move event!
NS_ENSURE_TRUE(textAcc, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNode> textNode;
nsCOMPtr<nsIAccessibleText> textAcc =
nsAccUtils::GetTextAccessibleFromSelection(aSel, getter_AddRefs(textNode));
NS_ENSURE_STATE(textAcc);
PRInt32 caretOffset;
nsresult rv = textAcc->GetCaretOffset(&caretOffset);
rv = textAcc->GetCaretOffset(&caretOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (textAcc == mLastTextAccessible && caretOffset == mLastCaretOffset) {
@ -296,7 +260,7 @@ nsCaretAccessible::NormalSelectionChanged(nsIDOMDocument *aDoc,
mLastTextAccessible = textAcc;
nsCOMPtr<nsIAccessibleCaretMoveEvent> event =
new nsAccCaretMoveEvent(focusNode);
new nsAccCaretMoveEvent(textNode);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return mRootAccessible->FireDelayedAccessibleEvent(event);
@ -311,34 +275,16 @@ nsCaretAccessible::SpellcheckSelectionChanged(nsIDOMDocument *aDoc,
// the same accessible for newly appended range of the selection (for every
// misspelled word). If spellchecking is disabled (for example,
// @spellcheck="false" on html:body) then we won't fire any event.
nsCOMPtr<nsIDOMNode> targetNode;
aSel->GetFocusNode(getter_AddRefs(targetNode));
if (!targetNode)
return NS_OK;
// Get focused node.
nsCOMPtr<nsIContent> focusContainer(do_QueryInterface(targetNode));
if (focusContainer && focusContainer->IsNodeOfType(nsINode::eELEMENT)) {
PRInt32 focusOffset = 0;
aSel->GetFocusOffset(&focusOffset);
nsCOMPtr<nsIContent> focusContent = focusContainer->GetChildAt(focusOffset);
targetNode = do_QueryInterface(focusContent);
}
nsCOMPtr<nsIAccessibleText> textAcc =
nsAccUtils::GetTextAccessibleFromSelection(aSel);
NS_ENSURE_STATE(textAcc);
nsCOMPtr<nsIAccessibleDocument> docAccessible =
nsAccessNode::GetDocAccessibleFor(targetNode);
NS_ENSURE_STATE(docAccessible);
nsCOMPtr<nsIAccessible> containerAccessible;
nsresult rv =
docAccessible->GetAccessibleInParentChain(targetNode, PR_TRUE,
getter_AddRefs(containerAccessible));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAccessible> acc(do_QueryInterface(textAcc));
nsCOMPtr<nsIAccessibleEvent> event =
new nsAccEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
containerAccessible, nsnull);
acc, nsnull);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return mRootAccessible->FireAccessibleEvent(event);

Просмотреть файл

@ -44,6 +44,26 @@
}
}
function synthFocusTest(aNode)
{
// bug 460417
this.node = aNode;
this.testFunc = function testFunc()
{
this.node.focus();
}
}
function synthSelectAllTest(aNode)
{
// bug 460417
this.node = aNode;
this.testFunc = function testFunc()
{
this.node.select();
}
}
var gTestsArray = [];
var gTestIdx = -1;
@ -83,6 +103,8 @@
function doTests()
{
var textbox = document.getElementById("textbox");
gTestsArray.push(new synthFocusTest(textbox));
gTestsArray.push(new synthSelectAllTest(textbox));
gTestsArray.push(new synthMouseTest(textbox));
gTestsArray.push(new synthKeyTest(textbox, "VK_RIGHT"));