Bug 1826264 - P2: Add range TextLeafRange::ScrollIntoView. r=Jamie

Use it when caching is enabled.

Differential Revision: https://phabricator.services.mozilla.com/D174977
This commit is contained in:
Eitan Isaacson 2023-04-13 20:40:19 +00:00
parent 60909e6894
commit d70f1224fa
22 changed files with 175 additions and 66 deletions

View File

@ -532,25 +532,19 @@ static gboolean setCaretOffsetCB(AtkText* aText, gint aOffset) {
static gboolean scrollSubstringToCB(AtkText* aText, gint aStartOffset,
gint aEndOffset, AtkScrollType aType) {
AtkObject* atkObject = ATK_OBJECT(aText);
AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
if (accWrap) {
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole() ||
!text->IsValidRange(aStartOffset, aEndOffset)) {
return FALSE;
}
text->ScrollSubstringTo(aStartOffset, aEndOffset, aType);
return TRUE;
Accessible* acc = GetInternalObj(ATK_OBJECT(aText));
if (!acc) {
return FALSE;
}
RemoteAccessible* proxy = GetProxy(atkObject);
if (proxy) {
proxy->ScrollSubstringTo(aStartOffset, aEndOffset, aType);
return TRUE;
HyperTextAccessibleBase* text = acc->AsHyperTextBase();
if (!text) {
return FALSE;
}
return FALSE;
text->ScrollSubstringTo(aStartOffset, aEndOffset, aType);
return TRUE;
}
static gboolean scrollSubstringToPointCB(AtkText* aText, gint aStartOffset,

View File

@ -1858,6 +1858,42 @@ bool TextLeafRange::SetSelection(int32_t aSelectionNum) const {
return false;
}
void TextLeafRange::ScrollIntoView(uint32_t aScrollType) const {
if (!mStart || !mEnd || mStart.mAcc->IsLocal() != mEnd.mAcc->IsLocal()) {
return;
}
if (mStart.mAcc->IsRemote()) {
DocAccessibleParent* doc = mStart.mAcc->AsRemote()->Document();
if (doc != mEnd.mAcc->AsRemote()->Document()) {
// Can't scroll range that spans docs.
return;
}
Unused << doc->SendScrollTextLeafRangeIntoView(
mStart.mAcc->ID(), mStart.mOffset, mEnd.mAcc->ID(), mEnd.mOffset,
aScrollType);
return;
}
auto [startContent, startContentOffset] = mStart.ToDOMPoint();
auto [endContent, endContentOffset] = mEnd.ToDOMPoint();
if (!startContent || !endContent) {
return;
}
ErrorResult er;
RefPtr<nsRange> domRange = nsRange::Create(startContent, startContentOffset,
endContent, endContentOffset, er);
if (er.Failed()) {
return;
}
nsCoreUtils::ScrollSubstringTo(mStart.mAcc->AsLocal()->GetFrame(), domRange,
aScrollType);
}
TextLeafRange::Iterator TextLeafRange::Iterator::BeginIterator(
const TextLeafRange& aRange) {
Iterator result(aRange);

View File

@ -297,6 +297,8 @@ class TextLeafRange final {
*/
MOZ_CAN_RUN_SCRIPT bool SetSelection(int32_t aSelectionNum) const;
MOZ_CAN_RUN_SCRIPT void ScrollIntoView(uint32_t aScrollType) const;
private:
TextLeafPoint mStart;
TextLeafPoint mEnd;

View File

@ -263,19 +263,6 @@ bool TextRange::Crop(Accessible* aContainer) {
return true;
}
void TextRange::ScrollIntoView(uint32_t aScrollType) const {
LocalAccessible* root = mRoot->AsLocal();
if (!root) {
MOZ_ASSERT_UNREACHABLE("Not supported for RemoteAccessible");
return;
}
RefPtr<nsRange> range = nsRange::Create(root->GetContent());
if (AssignDOMRange(range)) {
nsCoreUtils::ScrollSubstringTo(mStartContainer->AsLocal()->GetFrame(),
range, aScrollType);
}
}
/**
* Convert the given DOM point to a DOM point in non-generated contents.
*

View File

@ -111,11 +111,6 @@ class TextRange final {
*/
bool Crop(Accessible* aContainer);
/**
* Scroll the text range into view.
*/
void ScrollIntoView(uint32_t aScrollType) const;
/**
* Convert stored hypertext offsets into DOM offsets and assign it to DOM
* range.

View File

@ -789,4 +789,12 @@ bool HyperTextAccessibleBase::SetSelectionBoundsAt(int32_t aSelectionNum,
return range.SetSelection(aSelectionNum);
}
void HyperTextAccessibleBase::ScrollSubstringTo(int32_t aStartOffset,
int32_t aEndOffset,
uint32_t aScrollType) {
TextLeafRange range(ToTextLeafPoint(aStartOffset),
ToTextLeafPoint(aEndOffset, true));
range.ScrollIntoView(aScrollType);
}
} // namespace mozilla::a11y

View File

@ -233,6 +233,12 @@ class HyperTextAccessibleBase {
MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual bool RemoveFromSelection(
int32_t aSelectionNum) = 0;
/**
* Scroll the given text range into view.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void ScrollSubstringTo(
int32_t aStartOffset, int32_t aEndOffset, uint32_t aScrollType);
protected:
virtual const Accessible* Acc() const = 0;
Accessible* Acc() {

View File

@ -1943,13 +1943,6 @@ bool HyperTextAccessible::RemoveFromSelection(int32_t aSelectionNum) {
return true;
}
void HyperTextAccessible::ScrollSubstringTo(int32_t aStartOffset,
int32_t aEndOffset,
uint32_t aScrollType) {
TextRange range(this, this, aStartOffset, this, aEndOffset);
range.ScrollIntoView(aScrollType);
}
void HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartOffset,
int32_t aEndOffset,
uint32_t aCoordinateType,

View File

@ -211,12 +211,6 @@ class HyperTextAccessible : public AccessibleWrap,
MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual bool RemoveFromSelection(
int32_t aSelectionNum) override;
/**
* Scroll the given text range into view.
*/
void ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
uint32_t aScrollType);
/**
* Scroll the given text range to the given point.
*/

View File

@ -244,6 +244,19 @@ mozilla::ipc::IPCResult DocAccessibleChildBase::RecvSetTextSelection(
return IPC_OK();
}
mozilla::ipc::IPCResult DocAccessibleChildBase::RecvScrollTextLeafRangeIntoView(
const uint64_t& aStartID, const int32_t& aStartOffset,
const uint64_t& aEndID, const int32_t& aEndOffset,
const uint32_t& aScrollType) {
TextLeafRange range(TextLeafPoint(IdToAccessible(aStartID), aStartOffset),
TextLeafPoint(IdToAccessible(aEndID), aEndOffset));
if (range) {
range.ScrollIntoView(aScrollType);
}
return IPC_OK();
}
mozilla::ipc::IPCResult DocAccessibleChildBase::RecvRemoveTextSelection(
const uint64_t& aID, const int32_t& aSelectionNum) {
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);

View File

@ -84,6 +84,12 @@ class DocAccessibleChildBase : public PDocAccessibleChild {
const uint64_t& aEndID, const int32_t& aEndOffset,
const int32_t& aSelectionNum) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual mozilla::ipc::IPCResult RecvScrollTextLeafRangeIntoView(
const uint64_t& aStartID, const int32_t& aStartOffset,
const uint64_t& aEndID, const int32_t& aEndOffset,
const uint32_t& aScrollType) override;
virtual mozilla::ipc::IPCResult RecvRemoveTextSelection(
const uint64_t& aID, const int32_t& aSelectionNum) override;

View File

@ -85,8 +85,8 @@ virtual bool SetSelectionBoundsAt(int32_t aSelectionNum, int32_t aStartOffset,
virtual bool RemoveFromSelection(int32_t aSelectionNum) override;
void ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
uint32_t aScrollType);
virtual void ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
uint32_t aScrollType) override;
void ScrollSubstringToPoint(int32_t aStartOffset, int32_t aEndOffset,
uint32_t aCoordinateType, int32_t aX, int32_t aY);

View File

@ -211,6 +211,9 @@ child:
int32_t aSelectionNum);
async RemoveTextSelection(uint64_t aID, int32_t aSelectionNum);
async ScrollTextLeafRangeIntoView(uint64_t aStartID, int32_t aStartOffset,
uint64_t aEndID, int32_t aEndOffset,
uint32_t aScrollType);
async ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
uint32_t aScrollType);
async ScrollSubstringToPoint(uint64_t aID,

View File

@ -351,6 +351,13 @@ bool RemoteAccessible::RemoveFromSelection(int32_t aSelectionNum) {
void RemoteAccessible::ScrollSubstringTo(int32_t aStartOffset,
int32_t aEndOffset,
uint32_t aScrollType) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
MOZ_ASSERT(IsHyperText(), "is not hypertext?");
RemoteAccessibleBase<RemoteAccessible>::ScrollSubstringTo(
aStartOffset, aEndOffset, aScrollType);
return;
}
Unused << mDoc->SendScrollSubstringTo(mID, aStartOffset, aEndOffset,
aScrollType);
}

View File

@ -142,6 +142,10 @@ child:
int32_t aSelectionNum);
async RemoveTextSelection(uint64_t aID, int32_t aSelectionNum);
async ScrollTextLeafRangeIntoView(uint64_t aStartID, int32_t aStartOffset,
uint64_t aEndID, int32_t aEndOffset,
uint32_t aScrollType);
/*
* Verify the cache. Used for testing purposes.
*/

View File

@ -733,9 +733,12 @@ void RemoteAccessible::ScrollSubstringTo(int32_t aStartOffset,
int32_t aEndOffset,
uint32_t aScrollType) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
// Not yet supported by the cache.
MOZ_ASSERT(IsHyperText(), "is not hypertext?");
RemoteAccessibleBase<RemoteAccessible>::ScrollSubstringTo(
aStartOffset, aEndOffset, aScrollType);
return;
}
RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
if (!acc) {
return;

View File

@ -236,16 +236,9 @@ inline NSString* ToNSString(id aValue) {
return;
}
if (mGeckoAccessible->IsLocal()) {
if (HyperTextAccessible* textAcc =
mGeckoAccessible->AsLocal()->AsHyperText()) {
textAcc->ScrollSubstringTo(range.location, range.location + range.length,
nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
}
} else {
mGeckoAccessible->AsRemote()->ScrollSubstringTo(
range.location, range.location + range.length,
nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
if (HyperTextAccessibleBase* textAcc = mGeckoAccessible->AsHyperTextBase()) {
textAcc->ScrollSubstringTo(range.location, range.location + range.length,
nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
}
}

View File

@ -12,3 +12,4 @@ prefs =
skip-if = os == 'win' # bug 1372296
[browser_test_scroll_bounds.js]
[browser_test_scrollTo.js]
[browser_test_scroll_substring.js]

View File

@ -0,0 +1,67 @@
/* 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";
/* import-globals-from ../../mochitest/layout.js */
loadScripts({ name: "layout.js", dir: MOCHITESTS_DIR });
/**
* Test nsIAccessibleText::scrollSubstringTo.
*/
addAccessibleTask(
`
<style>
@font-face {
font-family: Ahem;
src: url(${CURRENT_CONTENT_DIR}e10s/fonts/Ahem.sjs);
}
pre {
font: 20px/20px Ahem;
height: 40px;
overflow-y: scroll;
}
</style>
<pre id="text">
It's a jetpack, Michael. What could possibly go wrong?
The only thing I found in the fridge was a dead dove in a bag.
</pre>`,
async function(browser, docAcc) {
let text = findAccessibleChildByID(docAcc, "text", [nsIAccessibleText]);
let [, containerY, , containerHeight] = getBounds(text);
let getCharY = () => {
let objY = {};
text.getCharacterExtents(7, {}, objY, {}, {}, COORDTYPE_SCREEN_RELATIVE);
return objY.value;
};
ok(
containerHeight < getCharY(),
"Character is outside of container bounds"
);
text.scrollSubstringTo(7, 8, SCROLL_TYPE_TOP_EDGE);
await waitForContentPaint(browser);
await untilCacheIs(
getCharY,
containerY,
"Character is scrolled to top of container"
);
},
{
topLevel: !isWinNoCache,
iframe: !isWinNoCache,
remoteIframe: !isWinNoCache,
chrome: true,
}
);

View File

@ -82,6 +82,7 @@ const SEAMONKEY = navigator.userAgent.match(/ SeaMonkey\//);
const STATE_BUSY = nsIAccessibleStates.STATE_BUSY;
const SCROLL_TYPE_TOP_EDGE = nsIAccessibleScrollType.SCROLL_TYPE_TOP_EDGE;
const SCROLL_TYPE_ANYWHERE = nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE;
const COORDTYPE_SCREEN_RELATIVE =

View File

@ -380,9 +380,9 @@ ia2AccessibleText::get_nCharacters(long* aNCharacters) {
STDMETHODIMP
ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex,
enum IA2ScrollType aScrollType) {
auto [textAcc, hr] = LocalTextAcc();
HyperTextAccessibleBase* textAcc = TextAcc();
if (!textAcc) {
return hr;
return CO_E_OBJNOTCONNECTED;
}
if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG;

View File

@ -388,11 +388,7 @@ xpcAccessibleHyperText::ScrollSubstringTo(int32_t aStartOffset,
uint32_t aScrollType) {
if (!mIntl) return NS_ERROR_FAILURE;
if (mIntl->IsLocal()) {
IntlLocal()->ScrollSubstringTo(aStartOffset, aEndOffset, aScrollType);
} else {
mIntl->AsRemote()->ScrollSubstringTo(aStartOffset, aEndOffset, aScrollType);
}
Intl()->ScrollSubstringTo(aStartOffset, aEndOffset, aScrollType);
return NS_OK;
}