mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1766546: Implement SetCaretOffset for cached Windows RemoteAccessible. r=morgan
We implement setting of the caret using HyperText rather than TextLeafPoint because caret stuff, including events, still uses HyperText internally for now. This moves the async IPDL method already used on non-Windows into the base classes so Windows can use it. We keep the COM implementation for Windows RemoteAccessible without the cache. SetCaretOffset was moved into HyperTextAccessibleBase and platform methods were updated accordingly. Finally, I did some drive-by cleanup (no user impact) and changed GetCaretOffset in ATK and XPCOM to use HyperTextAccessibleBase. GetCaretOffset was moved to the base some time ago, but ATK and XPCOM weren't updated at the time. Differential Revision: https://phabricator.services.mozilla.com/D147852
This commit is contained in:
parent
2be1e8212c
commit
52b0b92e8d
@ -271,21 +271,17 @@ static gchar* getTextBeforeOffsetCB(AtkText* aText, gint aOffset,
|
||||
}
|
||||
|
||||
static gint getCaretOffsetCB(AtkText* aText) {
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||
if (accWrap) {
|
||||
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||
if (!text || !text->IsTextRole()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<gint>(text->CaretOffset());
|
||||
Accessible* acc = GetInternalObj(ATK_OBJECT(aText));
|
||||
if (!acc) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
return static_cast<gint>(proxy->CaretOffset());
|
||||
HyperTextAccessibleBase* text = acc->AsHyperTextBase();
|
||||
if (!text || !acc->IsTextRole()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return static_cast<gint>(text->CaretOffset());
|
||||
}
|
||||
|
||||
static AtkAttributeSet* getRunAttributesCB(AtkText* aText, gint aOffset,
|
||||
@ -540,23 +536,18 @@ static gboolean setTextSelectionCB(AtkText* aText, gint aSelectionNum,
|
||||
}
|
||||
|
||||
static gboolean setCaretOffsetCB(AtkText* aText, gint aOffset) {
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||
if (accWrap) {
|
||||
HyperTextAccessible* text = accWrap->AsHyperText();
|
||||
if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
text->SetCaretOffset(aOffset);
|
||||
return TRUE;
|
||||
Accessible* acc = GetInternalObj(ATK_OBJECT(aText));
|
||||
if (!acc) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
proxy->SetCaretOffset(aOffset);
|
||||
return TRUE;
|
||||
HyperTextAccessibleBase* text = acc->AsHyperTextBase();
|
||||
if (!text || !acc->IsTextRole()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
text->SetCaretOffset(aOffset);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean scrollSubstringToCB(AtkText* aText, gint aStartOffset,
|
||||
|
@ -79,9 +79,10 @@ class HyperTextAccessibleBase {
|
||||
virtual uint32_t CharacterCount() const;
|
||||
|
||||
/**
|
||||
* Get caret offset, if no caret then -1.
|
||||
* Get/set caret offset, if no caret then -1.
|
||||
*/
|
||||
virtual int32_t CaretOffset() const;
|
||||
virtual void SetCaretOffset(int32_t aOffset) = 0;
|
||||
|
||||
/**
|
||||
* Transform magic offset into text offset.
|
||||
|
@ -190,7 +190,7 @@ class HyperTextAccessible : public AccessibleWrap,
|
||||
* Get/set caret offset, if no caret then -1.
|
||||
*/
|
||||
virtual int32_t CaretOffset() const override;
|
||||
void SetCaretOffset(int32_t aOffset);
|
||||
virtual void SetCaretOffset(int32_t aOffset) override;
|
||||
|
||||
/**
|
||||
* Provide the line number for the caret.
|
||||
|
@ -220,6 +220,15 @@ mozilla::ipc::IPCResult DocAccessibleChildBase::RecvDoActionAsync(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessibleChildBase::RecvSetCaretOffset(
|
||||
const uint64_t& aID, const int32_t& aOffset) {
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
if (acc && acc->IsTextRole() && acc->IsValidOffset(aOffset)) {
|
||||
acc->SetCaretOffset(aOffset);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
LocalAccessible* DocAccessibleChildBase::IdToAccessible(
|
||||
const uint64_t& aID) const {
|
||||
if (!aID) return mDoc;
|
||||
@ -229,5 +238,11 @@ LocalAccessible* DocAccessibleChildBase::IdToAccessible(
|
||||
return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID));
|
||||
}
|
||||
|
||||
HyperTextAccessible* DocAccessibleChildBase::IdToHyperTextAccessible(
|
||||
const uint64_t& aID) const {
|
||||
LocalAccessible* acc = IdToAccessible(aID);
|
||||
return acc && acc->IsHyperText() ? acc->AsHyperText() : nullptr;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
@ -75,6 +75,9 @@ class DocAccessibleChildBase : public PDocAccessibleChild {
|
||||
virtual mozilla::ipc::IPCResult RecvDoActionAsync(
|
||||
const uint64_t& aID, const uint8_t& aIndex) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSetCaretOffset(
|
||||
const uint64_t& aID, const int32_t& aOffset) override;
|
||||
|
||||
protected:
|
||||
static void FlattenTree(LocalAccessible* aRoot,
|
||||
nsTArray<LocalAccessible*>& aTree);
|
||||
@ -97,6 +100,7 @@ class DocAccessibleChildBase : public PDocAccessibleChild {
|
||||
void SetConstructedInParentProcess() { mIsRemoteConstructed = true; }
|
||||
|
||||
LocalAccessible* IdToAccessible(const uint64_t& aID) const;
|
||||
HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
|
||||
|
||||
DocAccessible* mDoc;
|
||||
bool mIsRemoteConstructed;
|
||||
|
@ -1080,6 +1080,11 @@ RemoteAccessibleBase<Derived>::GetCachedHyperTextOffsets() const {
|
||||
return *mCachedFields->GetAttribute<nsTArray<int32_t>>(nsGkAtoms::offset);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void RemoteAccessibleBase<Derived>::SetCaretOffset(int32_t aOffset) {
|
||||
Unused << mDoc->SendSetCaretOffset(mID, aOffset);
|
||||
}
|
||||
|
||||
template class RemoteAccessibleBase<RemoteAccessible>;
|
||||
|
||||
} // namespace a11y
|
||||
|
@ -224,6 +224,7 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
|
||||
|
||||
virtual void TakeFocus() const override;
|
||||
virtual void ScrollTo(uint32_t aHow) const override;
|
||||
virtual void SetCaretOffset(int32_t aOffset) override;
|
||||
|
||||
/**
|
||||
* Allow the platform to store a pointers worth of data on us.
|
||||
|
@ -70,7 +70,6 @@ void Announce(const nsString& aAnnouncement, uint16_t aPriority);
|
||||
|
||||
int32_t CaretLineNumber();
|
||||
virtual int32_t CaretOffset() const override;
|
||||
void SetCaretOffset(int32_t aOffset);
|
||||
|
||||
virtual void TextSubstring(int32_t aStartOffset, int32_t aEndOfset,
|
||||
nsAString& aText) const override;
|
||||
|
@ -39,12 +39,6 @@ LocalAccessible* DocAccessibleChild::IdToAccessibleSelect(
|
||||
return acc && acc->IsSelect() ? acc : nullptr;
|
||||
}
|
||||
|
||||
HyperTextAccessible* DocAccessibleChild::IdToHyperTextAccessible(
|
||||
const uint64_t& aID) const {
|
||||
LocalAccessible* acc = IdToAccessible(aID);
|
||||
return acc && acc->IsHyperText() ? acc->AsHyperText() : nullptr;
|
||||
}
|
||||
|
||||
TextLeafAccessible* DocAccessibleChild::IdToTextLeafAccessible(
|
||||
const uint64_t& aID) const {
|
||||
LocalAccessible* acc = IdToAccessible(aID);
|
||||
@ -277,15 +271,6 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvCaretOffset(const uint64_t& aID,
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessibleChild::RecvSetCaretOffset(
|
||||
const uint64_t& aID, const int32_t& aOffset) {
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
if (acc && acc->IsTextRole() && acc->IsValidOffset(aOffset)) {
|
||||
acc->SetCaretOffset(aOffset);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult DocAccessibleChild::RecvCharacterCount(
|
||||
const uint64_t& aID, int32_t* aCount) {
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
|
@ -104,8 +104,6 @@ class DocAccessibleChild : public DocAccessibleChildBase {
|
||||
const uint64_t& aID, int32_t* aLineNumber) override;
|
||||
virtual mozilla::ipc::IPCResult RecvCaretOffset(const uint64_t& aID,
|
||||
int32_t* aOffset) override;
|
||||
virtual mozilla::ipc::IPCResult RecvSetCaretOffset(
|
||||
const uint64_t& aID, const int32_t& aOffset) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvCharacterCount(const uint64_t& aID,
|
||||
int32_t* aCount) override;
|
||||
@ -465,7 +463,6 @@ class DocAccessibleChild : public DocAccessibleChildBase {
|
||||
private:
|
||||
LocalAccessible* IdToAccessibleLink(const uint64_t& aID) const;
|
||||
LocalAccessible* IdToAccessibleSelect(const uint64_t& aID) const;
|
||||
HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
|
||||
TextLeafAccessible* IdToTextLeafAccessible(const uint64_t& aID) const;
|
||||
ImageAccessible* IdToImageAccessible(const uint64_t& aID) const;
|
||||
TableCellAccessible* IdToTableCellAccessible(const uint64_t& aID) const;
|
||||
|
@ -177,10 +177,6 @@ int32_t RemoteAccessible::CaretOffset() const {
|
||||
return offset;
|
||||
}
|
||||
|
||||
void RemoteAccessible::SetCaretOffset(int32_t aOffset) {
|
||||
Unused << mDoc->SendSetCaretOffset(mID, aOffset);
|
||||
}
|
||||
|
||||
uint32_t RemoteAccessible::CharacterCount() const {
|
||||
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
|
||||
return RemoteAccessibleBase<RemoteAccessible>::CharacterCount();
|
||||
|
@ -140,6 +140,8 @@ child:
|
||||
|
||||
async DoActionAsync(uint64_t aID, uint8_t aIndex);
|
||||
|
||||
async SetCaretOffset(uint64_t aID, int32_t aOffset);
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
|
@ -683,6 +683,10 @@ int32_t RemoteAccessible::CaretOffset() const {
|
||||
}
|
||||
|
||||
void RemoteAccessible::SetCaretOffset(int32_t aOffset) {
|
||||
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
|
||||
return RemoteAccessibleBase<RemoteAccessible>::SetCaretOffset(aOffset);
|
||||
}
|
||||
|
||||
RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
|
||||
if (!acc) {
|
||||
return;
|
||||
|
@ -35,6 +35,7 @@ class RemoteAccessible : public RemoteAccessibleBase<RemoteAccessible> {
|
||||
#include "mozilla/a11y/RemoteAccessibleShared.h"
|
||||
|
||||
virtual void TakeFocus() const override;
|
||||
virtual void SetCaretOffset(int32_t aOffset) override;
|
||||
|
||||
bool GetCOMInterface(void** aOutAccessible) const;
|
||||
void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible) {
|
||||
|
@ -827,6 +827,63 @@ addAccessibleTask(
|
||||
{ chrome: true, topLevel: true, iframe: true, remoteIframe: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* Test setting the caret.
|
||||
*/
|
||||
addAccessibleTask(
|
||||
`
|
||||
<textarea id="textarea">ab\nc</textarea>
|
||||
<div id="editable" contenteditable>
|
||||
<p id="p">a<a id="link" href="https://example.com/">b</a></p>
|
||||
</div>
|
||||
`,
|
||||
async function(browser, docAcc) {
|
||||
const textarea = findAccessibleChildByID(docAcc, "textarea", [
|
||||
nsIAccessibleText,
|
||||
]);
|
||||
info("textarea: Set caret offset to 0");
|
||||
let focused = waitForEvent(EVENT_FOCUS, textarea);
|
||||
let caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea);
|
||||
textarea.caretOffset = 0;
|
||||
await focused;
|
||||
await caretMoved;
|
||||
is(textarea.caretOffset, 0, "textarea caret correct");
|
||||
// Test setting caret to another line.
|
||||
info("textarea: Set caret offset to 3");
|
||||
caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea);
|
||||
textarea.caretOffset = 3;
|
||||
await caretMoved;
|
||||
is(textarea.caretOffset, 3, "textarea caret correct");
|
||||
// Test setting caret to the end.
|
||||
info("textarea: Set caret offset to 4 (end)");
|
||||
caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, textarea);
|
||||
textarea.caretOffset = 4;
|
||||
await caretMoved;
|
||||
is(textarea.caretOffset, 4, "textarea caret correct");
|
||||
|
||||
const editable = findAccessibleChildByID(docAcc, "editable", [
|
||||
nsIAccessibleText,
|
||||
]);
|
||||
focused = waitForEvent(EVENT_FOCUS, editable);
|
||||
editable.takeFocus();
|
||||
await focused;
|
||||
const p = findAccessibleChildByID(docAcc, "p", [nsIAccessibleText]);
|
||||
info("p: Set caret offset to 0");
|
||||
caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, p);
|
||||
p.caretOffset = 0;
|
||||
await focused;
|
||||
await caretMoved;
|
||||
is(p.caretOffset, 0, "p caret correct");
|
||||
const link = findAccessibleChildByID(docAcc, "link", [nsIAccessibleText]);
|
||||
info("link: Set caret offset to 0");
|
||||
caretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, link);
|
||||
link.caretOffset = 0;
|
||||
await caretMoved;
|
||||
is(link.caretOffset, 0, "link caret correct");
|
||||
},
|
||||
{ chrome: true, topLevel: true, iframe: true, remoteIframe: true }
|
||||
);
|
||||
|
||||
function waitForSelectionChange(selectionAcc, caretAcc) {
|
||||
if (!caretAcc) {
|
||||
caretAcc = selectionAcc;
|
||||
|
@ -340,9 +340,9 @@ ia2AccessibleText::removeSelection(long aSelectionIndex) {
|
||||
|
||||
STDMETHODIMP
|
||||
ia2AccessibleText::setCaretOffset(long aOffset) {
|
||||
auto [textAcc, hr] = LocalTextAcc();
|
||||
HyperTextAccessibleBase* textAcc = TextAcc();
|
||||
if (!textAcc) {
|
||||
return hr;
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
|
||||
if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
|
||||
|
@ -277,11 +277,7 @@ xpcAccessibleHyperText::GetCaretOffset(int32_t* aCaretOffset) {
|
||||
|
||||
if (!mIntl) return NS_ERROR_FAILURE;
|
||||
|
||||
if (mIntl->IsLocal()) {
|
||||
*aCaretOffset = IntlLocal()->CaretOffset();
|
||||
} else {
|
||||
*aCaretOffset = mIntl->AsRemote()->CaretOffset();
|
||||
}
|
||||
*aCaretOffset = Intl()->CaretOffset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -289,11 +285,7 @@ NS_IMETHODIMP
|
||||
xpcAccessibleHyperText::SetCaretOffset(int32_t aCaretOffset) {
|
||||
if (!mIntl) return NS_ERROR_FAILURE;
|
||||
|
||||
if (mIntl->IsLocal()) {
|
||||
IntlLocal()->SetCaretOffset(aCaretOffset);
|
||||
} else {
|
||||
mIntl->AsRemote()->SetCaretOffset(aCaretOffset);
|
||||
}
|
||||
Intl()->SetCaretOffset(aCaretOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user