From 934c9cb61c5bbc27cfd2a7478d575961f84f7e43 Mon Sep 17 00:00:00 2001 From: James Teh Date: Wed, 1 Dec 2021 04:48:33 +0000 Subject: [PATCH] Bug 1741792 part 1: Cache the caret in the parent process using caret events. r=eeejay As well as the caret offset, we also need to cache whether the caret is at the end of a line. Therefore, this information has been added to caret events. Differential Revision: https://phabricator.services.mozilla.com/D132097 --- accessible/base/AccEvent.cpp | 6 ++-- accessible/base/AccEvent.h | 7 +++-- accessible/base/SelectionManager.cpp | 6 ++-- accessible/generic/LocalAccessible.cpp | 3 +- .../nsIAccessibleCaretMoveEvent.idl | 5 ++++ accessible/ipc/DocAccessibleParent.cpp | 12 ++++++-- accessible/ipc/DocAccessibleParent.h | 30 +++++++++++++++++-- accessible/ipc/other/PDocAccessible.ipdl | 3 +- accessible/ipc/win/DocAccessibleChild.cpp | 14 +++++---- accessible/ipc/win/DocAccessibleChild.h | 16 ++++++---- accessible/ipc/win/PDocAccessible.ipdl | 3 +- 11 files changed, 77 insertions(+), 28 deletions(-) diff --git a/accessible/base/AccEvent.cpp b/accessible/base/AccEvent.cpp index 4292f5afa9f0..8f8f0f750d67 100644 --- a/accessible/base/AccEvent.cpp +++ b/accessible/base/AccEvent.cpp @@ -244,9 +244,9 @@ already_AddRefed a11y::MakeXPCEvent(AccEvent* aEvent) { if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) { AccCaretMoveEvent* cm = downcast_accEvent(aEvent); - xpEvent = new xpcAccCaretMoveEvent(type, ToXPC(acc), ToXPCDocument(doc), - node, fromUser, cm->GetCaretOffset(), - cm->IsSelectionCollapsed()); + xpEvent = new xpcAccCaretMoveEvent( + type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, + cm->GetCaretOffset(), cm->IsSelectionCollapsed(), cm->IsAtEndOfLine()); return xpEvent.forget(); } diff --git a/accessible/base/AccEvent.h b/accessible/base/AccEvent.h index a57ab1b290c1..a64ec3f0ce8e 100644 --- a/accessible/base/AccEvent.h +++ b/accessible/base/AccEvent.h @@ -341,12 +341,13 @@ class AccReorderEvent : public AccTreeMutationEvent { class AccCaretMoveEvent : public AccEvent { public: AccCaretMoveEvent(LocalAccessible* aAccessible, int32_t aCaretOffset, - bool aIsSelectionCollapsed, + bool aIsSelectionCollapsed, bool aIsAtEndOfLine, EIsFromUserInput aIsFromUserInput = eAutoDetect) : AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, aIsFromUserInput), mCaretOffset(aCaretOffset), - mIsSelectionCollapsed(aIsSelectionCollapsed) {} + mIsSelectionCollapsed(aIsSelectionCollapsed), + mIsAtEndOfLine(aIsAtEndOfLine) {} virtual ~AccCaretMoveEvent() {} // AccEvent @@ -359,11 +360,13 @@ class AccCaretMoveEvent : public AccEvent { int32_t GetCaretOffset() const { return mCaretOffset; } bool IsSelectionCollapsed() const { return mIsSelectionCollapsed; } + bool IsAtEndOfLine() { return mIsAtEndOfLine; } private: int32_t mCaretOffset; bool mIsSelectionCollapsed; + bool mIsAtEndOfLine; }; /** diff --git a/accessible/base/SelectionManager.cpp b/accessible/base/SelectionManager.cpp index fbc532492172..026186affa5c 100644 --- a/accessible/base/SelectionManager.cpp +++ b/accessible/base/SelectionManager.cpp @@ -148,9 +148,9 @@ void SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent) { selection->FocusOffset()); mAccWithCaret = caretCntr; if (mCaretOffset != -1) { - RefPtr caretMoveEvent = - new AccCaretMoveEvent(caretCntr, mCaretOffset, selection->IsCollapsed(), - aEvent->FromUserInput()); + RefPtr caretMoveEvent = new AccCaretMoveEvent( + caretCntr, mCaretOffset, selection->IsCollapsed(), + caretCntr->IsCaretAtEndOfLine(), aEvent->FromUserInput()); nsEventShell::FireEvent(caretMoveEvent); } } diff --git a/accessible/generic/LocalAccessible.cpp b/accessible/generic/LocalAccessible.cpp index fd00d595ba53..c6159f4da63a 100644 --- a/accessible/generic/LocalAccessible.cpp +++ b/accessible/generic/LocalAccessible.cpp @@ -954,7 +954,8 @@ nsresult LocalAccessible::HandleAccEvent(AccEvent* aEvent) { case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: { AccCaretMoveEvent* event = downcast_accEvent(aEvent); ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset(), - event->IsSelectionCollapsed()); + event->IsSelectionCollapsed(), + event->IsAtEndOfLine()); break; } case nsIAccessibleEvent::EVENT_TEXT_INSERTED: diff --git a/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl b/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl index c31a788bfec6..26f596ce45c0 100644 --- a/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl +++ b/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl @@ -20,4 +20,9 @@ interface nsIAccessibleCaretMoveEvent: nsIAccessibleEvent * Return true if there is no selection. */ readonly attribute bool isSelectionCollapsed; + + /** + * Return true if the caret is at the end of a line. + */ + readonly attribute bool isAtEndOfLine; }; diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index 4ec99e63e6b1..4517488d739a 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -300,7 +300,8 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent( #if defined(XP_WIN) const LayoutDeviceIntRect& aCaretRect, #endif // defined (XP_WIN) - const int32_t& aOffset, const bool& aIsSelectionCollapsed) { + const int32_t& aOffset, const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine) { if (mShutdown) { return IPC_OK(); } @@ -311,6 +312,10 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent( return IPC_OK(); } + mCaretId = aID; + mCaretOffset = aOffset; + mIsCaretAtEndOfLine = aIsAtEndOfLine; + #if defined(XP_WIN) ProxyCaretMoveEvent(proxy, aCaretRect); #else @@ -326,8 +331,9 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent( nsINode* node = nullptr; bool fromUser = true; // XXX fix me uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED; - RefPtr event = new xpcAccCaretMoveEvent( - type, xpcAcc, doc, node, fromUser, aOffset, aIsSelectionCollapsed); + RefPtr event = + new xpcAccCaretMoveEvent(type, xpcAcc, doc, node, fromUser, aOffset, + aIsSelectionCollapsed, aIsAtEndOfLine); nsCoreUtils::DispatchAccEvent(std::move(event)); return IPC_OK(); diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index bb87360e5ea4..17f9f3d5b987 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -42,7 +42,10 @@ class DocAccessibleParent : public RemoteAccessible, mTopLevel(false), mTopLevelInContentProcess(false), mShutdown(false), - mFocus(0) { + mFocus(0), + mCaretId(0), + mCaretOffset(-1), + mIsCaretAtEndOfLine(false) { sMaxDocID++; mActorID = sMaxDocID; MOZ_ASSERT(!LiveDocs().Get(mActorID)); @@ -103,7 +106,8 @@ class DocAccessibleParent : public RemoteAccessible, #if defined(XP_WIN) const LayoutDeviceIntRect& aCaretRect, #endif - const int32_t& aOffset, const bool& aIsSelectionCollapsed) final; + const int32_t& aOffset, const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine) final; virtual mozilla::ipc::IPCResult RecvTextChangeEvent( const uint64_t& aID, const nsString& aStr, const int32_t& aStart, @@ -288,6 +292,25 @@ class DocAccessibleParent : public RemoteAccessible, return const_cast(this)->GetAccessible(mFocus); } + /** + * Get the HyperText Accessible containing the caret and the offset of the + * caret within. If there is no caret in this document, returns + * {nullptr, -1}. + */ + std::pair GetCaret() const { + if (mCaretOffset == -1) { + return {nullptr, -1}; + } + RemoteAccessible* acc = + const_cast(this)->GetAccessible(mCaretId); + if (!acc) { + return {nullptr, -1}; + } + return {acc, mCaretOffset}; + } + + bool IsCaretAtEndOfLine() const { return mIsCaretAtEndOfLine; } + private: ~DocAccessibleParent() { LiveDocs().Remove(mActorID); @@ -352,6 +375,9 @@ class DocAccessibleParent : public RemoteAccessible, nsTHashSet> mPendingOOPChildDocs; uint64_t mFocus; + uint64_t mCaretId; + int32_t mCaretOffset; + bool mIsCaretAtEndOfLine; static uint64_t sMaxDocID; static nsTHashMap& LiveDocs() { diff --git a/accessible/ipc/other/PDocAccessible.ipdl b/accessible/ipc/other/PDocAccessible.ipdl index 4f6699052f68..3145eca9ee26 100644 --- a/accessible/ipc/other/PDocAccessible.ipdl +++ b/accessible/ipc/other/PDocAccessible.ipdl @@ -96,7 +96,8 @@ parent: async ShowEvent(ShowEventData data, bool aFromuser); 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); + async CaretMoveEvent(uint64_t aID, int32_t aOffset, + bool aIsSelectionCollapsed, bool aIsAtEndOfLine); 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); diff --git a/accessible/ipc/win/DocAccessibleChild.cpp b/accessible/ipc/win/DocAccessibleChild.cpp index d04384f790d4..6299c80188b1 100644 --- a/accessible/ipc/win/DocAccessibleChild.cpp +++ b/accessible/ipc/win/DocAccessibleChild.cpp @@ -199,21 +199,23 @@ bool DocAccessibleChild::SendFocusEvent(const uint64_t& aID, bool DocAccessibleChild::SendCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset, - const bool& aIsSelectionCollapsed) { + const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine) { return SendCaretMoveEvent(aID, GetCaretRectFor(aID), aOffset, - aIsSelectionCollapsed); + aIsSelectionCollapsed, aIsAtEndOfLine); } bool DocAccessibleChild::SendCaretMoveEvent( const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect, - const int32_t& aOffset, const bool& aIsSelectionCollapsed) { + const int32_t& aOffset, const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine) { if (IsConstructedInParentProcess()) { - return PDocAccessibleChild::SendCaretMoveEvent(aID, aCaretRect, aOffset, - aIsSelectionCollapsed); + return PDocAccessibleChild::SendCaretMoveEvent( + aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine); } PushDeferredEvent(MakeUnique( - this, aID, aCaretRect, aOffset, aIsSelectionCollapsed)); + this, aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine)); return true; } diff --git a/accessible/ipc/win/DocAccessibleChild.h b/accessible/ipc/win/DocAccessibleChild.h index e3844def5643..5576991fd582 100644 --- a/accessible/ipc/win/DocAccessibleChild.h +++ b/accessible/ipc/win/DocAccessibleChild.h @@ -51,11 +51,13 @@ class DocAccessibleChild : public DocAccessibleChildBase { bool SendStateChangeEvent(const uint64_t& aID, const uint64_t& aState, const bool& aEnabled); bool SendCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset, - const bool& aIsSelectionCollapsed); + const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine); bool SendCaretMoveEvent(const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect, const int32_t& aOffset, - const bool& aIsSelectionCollapsed); + const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine); bool SendFocusEvent(const uint64_t& aID); bool SendFocusEvent(const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect); @@ -173,22 +175,24 @@ class DocAccessibleChild : public DocAccessibleChildBase { struct SerializedCaretMove final : public DeferredEvent { SerializedCaretMove(DocAccessibleChild* aTarget, uint64_t aID, const LayoutDeviceIntRect& aCaretRect, int32_t aOffset, - bool aIsSelectionCollapsed) + bool aIsSelectionCollapsed, bool aIsAtEndOfLine) : DeferredEvent(aTarget), mID(aID), mCaretRect(aCaretRect), mOffset(aOffset), - mIsSelectionCollapsed(aIsSelectionCollapsed) {} + mIsSelectionCollapsed(aIsSelectionCollapsed), + mIsAtEndOfLine(aIsAtEndOfLine) {} void Dispatch(DocAccessibleChild* aIPCDoc) override { - Unused << aIPCDoc->SendCaretMoveEvent(mID, mCaretRect, mOffset, - mIsSelectionCollapsed); + Unused << aIPCDoc->SendCaretMoveEvent( + mID, mCaretRect, mOffset, mIsSelectionCollapsed, mIsAtEndOfLine); } uint64_t mID; LayoutDeviceIntRect mCaretRect; int32_t mOffset; bool mIsSelectionCollapsed; + bool mIsAtEndOfLine; }; struct SerializedFocus final : public DeferredEvent { diff --git a/accessible/ipc/win/PDocAccessible.ipdl b/accessible/ipc/win/PDocAccessible.ipdl index e38ee8ca9af2..574976ae286e 100644 --- a/accessible/ipc/win/PDocAccessible.ipdl +++ b/accessible/ipc/win/PDocAccessible.ipdl @@ -59,7 +59,8 @@ parent: async HideEvent(uint64_t aRootID, bool aFromUser); async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled); async CaretMoveEvent(uint64_t aID, LayoutDeviceIntRect aCaretRect, - int32_t aOffset, bool aIsSelectionCollapsed); + int32_t aOffset, bool aIsAtEndOfLine, + bool aIsSelectionCollapsed); 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,