mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-11 18:24:02 +00:00
Bug 949518 - keep caret offset syncronized with accessible tree, r=surkov
This commit is contained in:
parent
b107d7de01
commit
fa66f8ae6a
@ -364,6 +364,11 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
|
||||
logging::FocusNotificationTarget("fire focus event", "Target", target);
|
||||
#endif
|
||||
|
||||
// Reset cached caret value. The cache will be updated upon processing the
|
||||
// next caret move event. This ensures that we will return the correct caret
|
||||
// offset before the caret move event is handled.
|
||||
SelectionMgr()->ResetCaretOffset();
|
||||
|
||||
nsRefPtr<AccEvent> focusEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, aEvent->FromUserInput());
|
||||
nsEventShell::FireEvent(focusEvent);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "mozilla/a11y/SelectionManager.h"
|
||||
|
||||
#include "DocAccessible-inl.h"
|
||||
#include "HyperTextAccessible.h"
|
||||
#include "HyperTextAccessible-inl.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsCoreUtils.h"
|
||||
@ -36,6 +38,12 @@ private:
|
||||
~SelData() {}
|
||||
};
|
||||
|
||||
SelectionManager::SelectionManager() :
|
||||
mCaretOffset(-1), mAccWithCaret(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
SelectionManager::ClearControlSelectionListener()
|
||||
{
|
||||
@ -144,10 +152,13 @@ SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent)
|
||||
if (!caretCntr)
|
||||
return;
|
||||
|
||||
int32_t caretOffset = caretCntr->CaretOffset();
|
||||
if (caretOffset != -1) {
|
||||
Selection* selection = caretCntr->DOMSelection();
|
||||
mCaretOffset = caretCntr->DOMPointToOffset(selection->GetFocusNode(),
|
||||
selection->FocusOffset());
|
||||
mAccWithCaret = caretCntr;
|
||||
if (mCaretOffset != -1) {
|
||||
nsRefPtr<AccCaretMoveEvent> caretMoveEvent =
|
||||
new AccCaretMoveEvent(caretCntr, caretOffset, aEvent->FromUserInput());
|
||||
new AccCaretMoveEvent(caretCntr, mCaretOffset, aEvent->FromUserInput());
|
||||
nsEventShell::FireEvent(caretMoveEvent);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class Element;
|
||||
namespace a11y {
|
||||
|
||||
class AccEvent;
|
||||
class HyperTextAccessible;
|
||||
|
||||
/**
|
||||
* This special accessibility class is for the caret and selection management.
|
||||
@ -81,7 +82,38 @@ public:
|
||||
*/
|
||||
void ProcessTextSelChangeEvent(AccEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Gets the current caret offset/hypertext accessible pair. If there is no
|
||||
* current pair, then returns -1 for the offset and a nullptr for the
|
||||
* accessible.
|
||||
*/
|
||||
inline HyperTextAccessible* AccessibleWithCaret(int32_t* aCaret)
|
||||
{
|
||||
if (aCaret)
|
||||
*aCaret = mCaretOffset;
|
||||
|
||||
return mAccWithCaret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update caret offset when it doesn't go through a caret move event.
|
||||
*/
|
||||
inline void UpdateCaretOffset(HyperTextAccessible* aItem, int32_t aOffset)
|
||||
{
|
||||
mAccWithCaret = aItem;
|
||||
mCaretOffset = aOffset;
|
||||
}
|
||||
|
||||
inline void ResetCaretOffset()
|
||||
{
|
||||
mCaretOffset = -1;
|
||||
mAccWithCaret = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
SelectionManager();
|
||||
|
||||
/**
|
||||
* Process DOM selection change. Fire selection and caret move events.
|
||||
*/
|
||||
@ -90,6 +122,8 @@ protected:
|
||||
private:
|
||||
// Currently focused control.
|
||||
nsWeakFrame mCurrCtrlFrame;
|
||||
int32_t mCaretOffset;
|
||||
HyperTextAccessible* mAccWithCaret;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
@ -2453,6 +2453,8 @@ Accessible::Shutdown()
|
||||
|
||||
mContent = nullptr;
|
||||
mDoc = nullptr;
|
||||
if (SelectionMgr()->AccessibleWithCaret(nullptr) == this)
|
||||
SelectionMgr()->ResetCaretOffset();
|
||||
}
|
||||
|
||||
// Accessible protected
|
||||
|
@ -32,6 +32,15 @@ HyperTextAccessible::IsValidRange(int32_t aStartOffset, int32_t aEndOffset)
|
||||
endOffset <= CharacterCount();
|
||||
}
|
||||
|
||||
inline void
|
||||
HyperTextAccessible::SetCaretOffset(int32_t aOffset)
|
||||
{
|
||||
SetSelectionRange(aOffset, aOffset);
|
||||
// XXX: Force cache refresh until a good solution for AT emulation of user
|
||||
// input is implemented (AccessFu caret movement).
|
||||
SelectionMgr()->UpdateCaretOffset(this, aOffset);
|
||||
}
|
||||
|
||||
inline bool
|
||||
HyperTextAccessible::AddToSelection(int32_t aStartOffset, int32_t aEndOffset)
|
||||
{
|
||||
|
@ -1162,6 +1162,22 @@ HyperTextAccessible::CaretOffset() const
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check cached value.
|
||||
int32_t caretOffset = -1;
|
||||
HyperTextAccessible* text = SelectionMgr()->AccessibleWithCaret(&caretOffset);
|
||||
|
||||
// Use cached value if it corresponds to this accessible.
|
||||
if (caretOffset != -1) {
|
||||
if (text == this)
|
||||
return caretOffset;
|
||||
|
||||
nsINode* textNode = text->GetNode();
|
||||
// Ignore offset if cached accessible isn't a text leaf.
|
||||
if (nsCoreUtils::IsAncestorOf(GetNode(), textNode))
|
||||
return TransformOffset(text,
|
||||
textNode->IsNodeOfType(nsINode::eTEXT) ? caretOffset : 0, false);
|
||||
}
|
||||
|
||||
// No caret if the focused node is not inside this DOM node and this DOM node
|
||||
// is not inside of focused node.
|
||||
FocusManager::FocusDisposition focusDisp =
|
||||
|
@ -302,7 +302,7 @@ public:
|
||||
* Get/set caret offset, if no caret then -1.
|
||||
*/
|
||||
int32_t CaretOffset() const;
|
||||
void SetCaretOffset(int32_t aOffset) { SetSelectionRange(aOffset, aOffset); }
|
||||
void SetCaretOffset(int32_t aOffset);
|
||||
|
||||
/**
|
||||
* Provide the line number for the caret.
|
||||
@ -406,6 +406,11 @@ public:
|
||||
*/
|
||||
virtual already_AddRefed<nsIEditor> GetEditor() const;
|
||||
|
||||
/**
|
||||
* Return DOM selection object for the accessible.
|
||||
*/
|
||||
dom::Selection* DOMSelection() const;
|
||||
|
||||
protected:
|
||||
// Accessible
|
||||
virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
|
||||
@ -486,10 +491,9 @@ protected:
|
||||
// Selection helpers
|
||||
|
||||
/**
|
||||
* Return frame/DOM selection object for the accessible.
|
||||
* Return frame selection object for the accessible.
|
||||
*/
|
||||
already_AddRefed<nsFrameSelection> FrameSelection() const;
|
||||
dom::Selection* DOMSelection() const;
|
||||
|
||||
/**
|
||||
* Return selection ranges within the accessible subtree.
|
||||
|
@ -1766,8 +1766,7 @@ function textSelectionChecker(aID, aStartOffset, aEndOffset)
|
||||
this.check = function textSelectionChecker_check(aEvent)
|
||||
{
|
||||
if (aStartOffset == aEndOffset) {
|
||||
is(getAccessible(aID, [nsIAccessibleText]).caretOffset, aStartOffset,
|
||||
"Wrong collapsed selection!");
|
||||
ok(true, "Collapsed selection triggered text selection change event.");
|
||||
} else {
|
||||
testTextGetSelection(aID, aStartOffset, aEndOffset, 0);
|
||||
}
|
||||
|
@ -46,7 +46,8 @@
|
||||
new textSelectionChecker("ta1", 0, 1),
|
||||
{ shiftKey: true }));
|
||||
gQueue.push(new synthLeftKey("ta1",
|
||||
new textSelectionChecker("ta1", 0, 0)));
|
||||
[new textSelectionChecker("ta1", 0, 0),
|
||||
new caretMoveChecker(0, "ta1")]));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user