зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1713050 - P2: Add granularity to a11y caret move events. r=morgan
Differential Revision: https://phabricator.services.mozilla.com/D139746
This commit is contained in:
Родитель
d4418e9378
Коммит
a479c8f191
|
@ -127,11 +127,13 @@ AccShowEvent::AccShowEvent(LocalAccessible* aTarget)
|
|||
|
||||
AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
|
||||
dom::Selection* aSelection,
|
||||
int32_t aReason)
|
||||
int32_t aReason,
|
||||
int32_t aGranularity)
|
||||
: AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget,
|
||||
eAutoDetect, eCoalesceTextSelChange),
|
||||
mSel(aSelection),
|
||||
mReason(aReason) {}
|
||||
mReason(aReason),
|
||||
mGranularity(aGranularity) {}
|
||||
|
||||
AccTextSelChangeEvent::~AccTextSelChangeEvent() {}
|
||||
|
||||
|
@ -246,7 +248,8 @@ already_AddRefed<nsIAccessibleEvent> a11y::MakeXPCEvent(AccEvent* aEvent) {
|
|||
AccCaretMoveEvent* cm = downcast_accEvent(aEvent);
|
||||
xpEvent = new xpcAccCaretMoveEvent(
|
||||
type, ToXPC(acc), ToXPCDocument(doc), node, fromUser,
|
||||
cm->GetCaretOffset(), cm->IsSelectionCollapsed(), cm->IsAtEndOfLine());
|
||||
cm->GetCaretOffset(), cm->IsSelectionCollapsed(), cm->IsAtEndOfLine(),
|
||||
cm->GetGranularity());
|
||||
return xpEvent.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -348,12 +348,14 @@ class AccCaretMoveEvent : public AccEvent {
|
|||
public:
|
||||
AccCaretMoveEvent(LocalAccessible* aAccessible, int32_t aCaretOffset,
|
||||
bool aIsSelectionCollapsed, bool aIsAtEndOfLine,
|
||||
int32_t aGranularity,
|
||||
EIsFromUserInput aIsFromUserInput = eAutoDetect)
|
||||
: AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible,
|
||||
aIsFromUserInput),
|
||||
mCaretOffset(aCaretOffset),
|
||||
mIsSelectionCollapsed(aIsSelectionCollapsed),
|
||||
mIsAtEndOfLine(aIsAtEndOfLine) {}
|
||||
mIsAtEndOfLine(aIsAtEndOfLine),
|
||||
mGranularity(aGranularity) {}
|
||||
virtual ~AccCaretMoveEvent() {}
|
||||
|
||||
// AccEvent
|
||||
|
@ -368,11 +370,14 @@ class AccCaretMoveEvent : public AccEvent {
|
|||
bool IsSelectionCollapsed() const { return mIsSelectionCollapsed; }
|
||||
bool IsAtEndOfLine() { return mIsAtEndOfLine; }
|
||||
|
||||
int32_t GetGranularity() const { return mGranularity; }
|
||||
|
||||
private:
|
||||
int32_t mCaretOffset;
|
||||
|
||||
bool mIsSelectionCollapsed;
|
||||
bool mIsAtEndOfLine;
|
||||
int32_t mGranularity;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -381,7 +386,8 @@ class AccCaretMoveEvent : public AccEvent {
|
|||
class AccTextSelChangeEvent : public AccEvent {
|
||||
public:
|
||||
AccTextSelChangeEvent(HyperTextAccessible* aTarget,
|
||||
dom::Selection* aSelection, int32_t aReason);
|
||||
dom::Selection* aSelection, int32_t aReason,
|
||||
int32_t aGranularity);
|
||||
virtual ~AccTextSelChangeEvent();
|
||||
|
||||
// AccEvent
|
||||
|
@ -397,6 +403,8 @@ class AccTextSelChangeEvent : public AccEvent {
|
|||
*/
|
||||
bool IsCaretMoveOnly() const;
|
||||
|
||||
int32_t GetGranularity() const { return mGranularity; }
|
||||
|
||||
/**
|
||||
* Return selection ranges in document/control.
|
||||
*/
|
||||
|
@ -405,6 +413,7 @@ class AccTextSelChangeEvent : public AccEvent {
|
|||
private:
|
||||
RefPtr<dom::Selection> mSel;
|
||||
int32_t mReason;
|
||||
int32_t mGranularity;
|
||||
|
||||
friend class EventQueue;
|
||||
friend class SelectionManager;
|
||||
|
|
|
@ -24,10 +24,12 @@ using namespace mozilla::a11y;
|
|||
using mozilla::dom::Selection;
|
||||
|
||||
struct mozilla::a11y::SelData final {
|
||||
SelData(Selection* aSel, int32_t aReason) : mSel(aSel), mReason(aReason) {}
|
||||
SelData(Selection* aSel, int32_t aReason, int32_t aGranularity)
|
||||
: mSel(aSel), mReason(aReason), mGranularity(aGranularity) {}
|
||||
|
||||
RefPtr<Selection> mSel;
|
||||
int16_t mReason;
|
||||
int32_t mGranularity;
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(SelData)
|
||||
|
||||
|
@ -148,9 +150,10 @@ void SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent) {
|
|||
selection->FocusOffset());
|
||||
mAccWithCaret = caretCntr;
|
||||
if (mCaretOffset != -1) {
|
||||
RefPtr<AccCaretMoveEvent> caretMoveEvent = new AccCaretMoveEvent(
|
||||
caretCntr, mCaretOffset, selection->IsCollapsed(),
|
||||
caretCntr->IsCaretAtEndOfLine(), aEvent->FromUserInput());
|
||||
RefPtr<AccCaretMoveEvent> caretMoveEvent =
|
||||
new AccCaretMoveEvent(caretCntr, mCaretOffset, selection->IsCollapsed(),
|
||||
caretCntr->IsCaretAtEndOfLine(),
|
||||
event->GetGranularity(), aEvent->FromUserInput());
|
||||
nsEventShell::FireEvent(caretMoveEvent);
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +178,7 @@ SelectionManager::NotifySelectionChanged(dom::Document* aDocument,
|
|||
// Selection manager has longer lifetime than any document accessible,
|
||||
// so that we are guaranteed that the notification is processed before
|
||||
// the selection manager is destroyed.
|
||||
RefPtr<SelData> selData = new SelData(aSelection, aReason);
|
||||
RefPtr<SelData> selData = new SelData(aSelection, aReason, aAmount);
|
||||
document->HandleNotification<SelectionManager, SelData>(
|
||||
this, &SelectionManager::ProcessSelectionChanged, selData);
|
||||
}
|
||||
|
@ -211,8 +214,8 @@ void SelectionManager::ProcessSelectionChanged(SelData* aSelData) {
|
|||
}
|
||||
|
||||
if (selection->GetType() == SelectionType::eNormal) {
|
||||
RefPtr<AccEvent> event =
|
||||
new AccTextSelChangeEvent(text, selection, aSelData->mReason);
|
||||
RefPtr<AccEvent> event = new AccTextSelChangeEvent(
|
||||
text, selection, aSelData->mReason, aSelData->mGranularity);
|
||||
text->Document()->FireDelayedEvent(event);
|
||||
|
||||
} else if (selection->GetType() == SelectionType::eSpellCheck) {
|
||||
|
|
|
@ -934,9 +934,9 @@ nsresult LocalAccessible::HandleAccEvent(AccEvent* aEvent) {
|
|||
}
|
||||
case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
|
||||
AccCaretMoveEvent* event = downcast_accEvent(aEvent);
|
||||
ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset(),
|
||||
event->IsSelectionCollapsed(),
|
||||
event->IsAtEndOfLine());
|
||||
ipcDoc->SendCaretMoveEvent(
|
||||
id, event->GetCaretOffset(), event->IsSelectionCollapsed(),
|
||||
event->IsAtEndOfLine(), event->GetGranularity());
|
||||
break;
|
||||
}
|
||||
case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
|
||||
|
|
|
@ -25,4 +25,9 @@ interface nsIAccessibleCaretMoveEvent: nsIAccessibleEvent
|
|||
* Return true if the caret is at the end of a line.
|
||||
*/
|
||||
readonly attribute bool isAtEndOfLine;
|
||||
|
||||
/**
|
||||
* Return caret move granularity.
|
||||
*/
|
||||
readonly attribute long granularity;
|
||||
};
|
||||
|
|
|
@ -341,7 +341,7 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent(
|
|||
const LayoutDeviceIntRect& aCaretRect,
|
||||
#endif // defined (XP_WIN)
|
||||
const int32_t& aOffset, const bool& aIsSelectionCollapsed,
|
||||
const bool& aIsAtEndOfLine) {
|
||||
const bool& aIsAtEndOfLine, const int32_t& aGranularity) {
|
||||
if (mShutdown) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -378,9 +378,9 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent(
|
|||
nsINode* node = nullptr;
|
||||
bool fromUser = true; // XXX fix me
|
||||
uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED;
|
||||
RefPtr<xpcAccCaretMoveEvent> event =
|
||||
new xpcAccCaretMoveEvent(type, xpcAcc, doc, node, fromUser, aOffset,
|
||||
aIsSelectionCollapsed, aIsAtEndOfLine);
|
||||
RefPtr<xpcAccCaretMoveEvent> event = new xpcAccCaretMoveEvent(
|
||||
type, xpcAcc, doc, node, fromUser, aOffset, aIsSelectionCollapsed,
|
||||
aIsAtEndOfLine, aGranularity);
|
||||
nsCoreUtils::DispatchAccEvent(std::move(event));
|
||||
|
||||
return IPC_OK();
|
||||
|
|
|
@ -108,7 +108,7 @@ class DocAccessibleParent : public RemoteAccessible,
|
|||
const LayoutDeviceIntRect& aCaretRect,
|
||||
#endif
|
||||
const int32_t& aOffset, const bool& aIsSelectionCollapsed,
|
||||
const bool& aIsAtEndOfLine) final;
|
||||
const bool& aIsAtEndOfLine, const int32_t& aGranularity) final;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvTextChangeEvent(
|
||||
const uint64_t& aID, const nsString& aStr, const int32_t& aStart,
|
||||
|
|
|
@ -99,7 +99,8 @@ parent:
|
|||
async HideEvent(uint64_t aRootID, bool aFromUser);
|
||||
async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
|
||||
async CaretMoveEvent(uint64_t aID, int32_t aOffset,
|
||||
bool aIsSelectionCollapsed, bool aIsAtEndOfLine);
|
||||
bool aIsSelectionCollapsed, bool aIsAtEndOfLine,
|
||||
int32_t aGranularity);
|
||||
async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
|
||||
bool aIsInsert, bool aFromUser);
|
||||
async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);
|
||||
|
|
|
@ -200,22 +200,26 @@ bool DocAccessibleChild::SendFocusEvent(const uint64_t& aID,
|
|||
bool DocAccessibleChild::SendCaretMoveEvent(const uint64_t& aID,
|
||||
const int32_t& aOffset,
|
||||
const bool& aIsSelectionCollapsed,
|
||||
const bool& aIsAtEndOfLine) {
|
||||
const bool& aIsAtEndOfLine,
|
||||
const int32_t& aGranularity) {
|
||||
return SendCaretMoveEvent(aID, GetCaretRectFor(aID), aOffset,
|
||||
aIsSelectionCollapsed, aIsAtEndOfLine);
|
||||
aIsSelectionCollapsed, aIsAtEndOfLine,
|
||||
aGranularity);
|
||||
}
|
||||
|
||||
bool DocAccessibleChild::SendCaretMoveEvent(
|
||||
const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect,
|
||||
const int32_t& aOffset, const bool& aIsSelectionCollapsed,
|
||||
const bool& aIsAtEndOfLine) {
|
||||
const bool& aIsAtEndOfLine, const int32_t& aGranularity) {
|
||||
if (IsConstructedInParentProcess()) {
|
||||
return PDocAccessibleChild::SendCaretMoveEvent(
|
||||
aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine);
|
||||
aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine,
|
||||
aGranularity);
|
||||
}
|
||||
|
||||
PushDeferredEvent(MakeUnique<SerializedCaretMove>(
|
||||
this, aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine));
|
||||
this, aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine,
|
||||
aGranularity));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,12 +52,14 @@ class DocAccessibleChild : public DocAccessibleChildBase {
|
|||
const bool& aEnabled);
|
||||
bool SendCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset,
|
||||
const bool& aIsSelectionCollapsed,
|
||||
const bool& aIsAtEndOfLine);
|
||||
const bool& aIsAtEndOfLine,
|
||||
const int32_t& aGranularity);
|
||||
bool SendCaretMoveEvent(const uint64_t& aID,
|
||||
const LayoutDeviceIntRect& aCaretRect,
|
||||
const int32_t& aOffset,
|
||||
const bool& aIsSelectionCollapsed,
|
||||
const bool& aIsAtEndOfLine);
|
||||
const bool& aIsAtEndOfLine,
|
||||
const int32_t& aGranularity);
|
||||
bool SendFocusEvent(const uint64_t& aID);
|
||||
bool SendFocusEvent(const uint64_t& aID,
|
||||
const LayoutDeviceIntRect& aCaretRect);
|
||||
|
@ -175,17 +177,20 @@ class DocAccessibleChild : public DocAccessibleChildBase {
|
|||
struct SerializedCaretMove final : public DeferredEvent {
|
||||
SerializedCaretMove(DocAccessibleChild* aTarget, uint64_t aID,
|
||||
const LayoutDeviceIntRect& aCaretRect, int32_t aOffset,
|
||||
bool aIsSelectionCollapsed, bool aIsAtEndOfLine)
|
||||
bool aIsSelectionCollapsed, bool aIsAtEndOfLine,
|
||||
int32_t aGranularity)
|
||||
: DeferredEvent(aTarget),
|
||||
mID(aID),
|
||||
mCaretRect(aCaretRect),
|
||||
mOffset(aOffset),
|
||||
mIsSelectionCollapsed(aIsSelectionCollapsed),
|
||||
mIsAtEndOfLine(aIsAtEndOfLine) {}
|
||||
mIsAtEndOfLine(aIsAtEndOfLine),
|
||||
mGranularity(aGranularity) {}
|
||||
|
||||
void Dispatch(DocAccessibleChild* aIPCDoc) override {
|
||||
Unused << aIPCDoc->SendCaretMoveEvent(
|
||||
mID, mCaretRect, mOffset, mIsSelectionCollapsed, mIsAtEndOfLine);
|
||||
Unused << aIPCDoc->SendCaretMoveEvent(mID, mCaretRect, mOffset,
|
||||
mIsSelectionCollapsed,
|
||||
mIsAtEndOfLine, mGranularity);
|
||||
}
|
||||
|
||||
uint64_t mID;
|
||||
|
@ -193,6 +198,7 @@ class DocAccessibleChild : public DocAccessibleChildBase {
|
|||
int32_t mOffset;
|
||||
bool mIsSelectionCollapsed;
|
||||
bool mIsAtEndOfLine;
|
||||
int32_t mGranularity;
|
||||
};
|
||||
|
||||
struct SerializedFocus final : public DeferredEvent {
|
||||
|
|
|
@ -70,7 +70,7 @@ parent:
|
|||
async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
|
||||
async CaretMoveEvent(uint64_t aID, LayoutDeviceIntRect aCaretRect,
|
||||
int32_t aOffset, bool aIsAtEndOfLine,
|
||||
bool aIsSelectionCollapsed);
|
||||
bool aIsSelectionCollapsed, int32_t aGranularity);
|
||||
async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
|
||||
bool aIsInsert, bool aFromUser);
|
||||
sync SyncTextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart,
|
||||
|
|
|
@ -8,6 +8,7 @@ support-files =
|
|||
environment =
|
||||
A11YLOG=doclifecycle,events,notifications
|
||||
|
||||
[browser_test_caret_move_granularity.js]
|
||||
[browser_test_docload.js]
|
||||
skip-if = e10s
|
||||
[browser_test_scrolling.js]
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const CLUSTER_AMOUNT = Ci.nsISelectionListener.CLUSTER_AMOUNT;
|
||||
const WORD_AMOUNT = Ci.nsISelectionListener.WORD_AMOUNT;
|
||||
const LINE_AMOUNT = Ci.nsISelectionListener.LINE_AMOUNT;
|
||||
const BEGINLINE_AMOUNT = Ci.nsISelectionListener.BEGINLINE_AMOUNT;
|
||||
const ENDLINE_AMOUNT = Ci.nsISelectionListener.ENDLINE_AMOUNT;
|
||||
|
||||
const isMac = AppConstants.platform == "macosx";
|
||||
|
||||
function matchCaretMoveEvent(id, caretOffset) {
|
||||
return evt => {
|
||||
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
return (
|
||||
getAccessibleDOMNodeID(evt.accessible) == id &&
|
||||
evt.caretOffset == caretOffset
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
addAccessibleTask(
|
||||
`<textarea id="textarea" style="scrollbar-width: none;" cols="15">` +
|
||||
`one two three four five six seven eight` +
|
||||
`</textarea>`,
|
||||
async function(browser, accDoc) {
|
||||
const textarea = findAccessibleChildByID(accDoc, "textarea");
|
||||
let caretMoved = waitForEvent(
|
||||
EVENT_TEXT_CARET_MOVED,
|
||||
matchCaretMoveEvent("textarea", 0)
|
||||
);
|
||||
textarea.takeFocus();
|
||||
let evt = await caretMoved;
|
||||
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
|
||||
|
||||
caretMoved = waitForEvent(
|
||||
EVENT_TEXT_CARET_MOVED,
|
||||
matchCaretMoveEvent("textarea", 1)
|
||||
);
|
||||
EventUtils.synthesizeKey("KEY_ArrowRight");
|
||||
evt = await caretMoved;
|
||||
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
|
||||
is(evt.granularity, CLUSTER_AMOUNT, "Caret moved by cluster");
|
||||
|
||||
caretMoved = waitForEvent(
|
||||
EVENT_TEXT_CARET_MOVED,
|
||||
matchCaretMoveEvent("textarea", 15)
|
||||
);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
evt = await caretMoved;
|
||||
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
todo(!evt.isAtEndOfLine, "Caret is not at end of line");
|
||||
is(evt.granularity, LINE_AMOUNT, "Caret moved by line");
|
||||
|
||||
caretMoved = waitForEvent(
|
||||
EVENT_TEXT_CARET_MOVED,
|
||||
matchCaretMoveEvent("textarea", 14)
|
||||
);
|
||||
if (isMac) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", { metaKey: true });
|
||||
} else {
|
||||
EventUtils.synthesizeKey("KEY_Home");
|
||||
}
|
||||
evt = await caretMoved;
|
||||
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
|
||||
is(evt.granularity, BEGINLINE_AMOUNT, "Caret moved to line start");
|
||||
|
||||
caretMoved = waitForEvent(
|
||||
EVENT_TEXT_CARET_MOVED,
|
||||
matchCaretMoveEvent("textarea", 28)
|
||||
);
|
||||
if (isMac) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowRight", { metaKey: true });
|
||||
} else {
|
||||
EventUtils.synthesizeKey("KEY_End");
|
||||
}
|
||||
evt = await caretMoved;
|
||||
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
ok(evt.isAtEndOfLine, "Caret is at end of line");
|
||||
is(evt.granularity, ENDLINE_AMOUNT, "Caret moved to line end");
|
||||
|
||||
caretMoved = waitForEvent(
|
||||
EVENT_TEXT_CARET_MOVED,
|
||||
matchCaretMoveEvent("textarea", 24)
|
||||
);
|
||||
if (isMac) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", { altKey: true });
|
||||
} else {
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", { ctrlKey: true });
|
||||
}
|
||||
evt = await caretMoved;
|
||||
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
|
||||
is(evt.granularity, WORD_AMOUNT, "Caret moved by word");
|
||||
}
|
||||
);
|
Загрузка…
Ссылка в новой задаче