зеркало из https://github.com/mozilla/pjs.git
Bug 460417 - invalid handling of selection changes inside input element, r=aaronlev, marcoz, sr=neil
This commit is contained in:
Родитель
53887a1659
Коммит
7d9f6d351c
|
@ -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"));
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче