Bug 1730096 part 3: Add HyperTextAccessibleBase::TextAttributes. r=eeejay

This uses TextLeafPoint.
This patch includes support for ATK, IA2 and XPCOM.
As with TextAtOffset, HyperTextAccessible calls the base implementation if the cache is enabled, but otherwise uses the old implementation for now.

Differential Revision: https://phabricator.services.mozilla.com/D129469
This commit is contained in:
James Teh 2021-11-01 23:27:37 +00:00
parent 754058c557
commit f24390b6a8
10 changed files with 137 additions and 42 deletions

View file

@ -275,32 +275,23 @@ static AtkAttributeSet* getRunAttributesCB(AtkText* aText, gint aOffset,
*aEndOffset = -1;
int32_t startOffset = 0, endOffset = 0;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (accWrap) {
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole()) {
return nullptr;
}
RefPtr<AccAttributes> attributes =
text->TextAttributes(false, aOffset, &startOffset, &endOffset);
*aStartOffset = startOffset;
*aEndOffset = endOffset;
return ConvertToAtkTextAttributeSet(attributes);
}
RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aText));
if (!proxy) {
Accessible* acc = GetInternalObj(ATK_OBJECT(aText));
if (!acc) {
return nullptr;
}
RefPtr<AccAttributes> attrs;
proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset);
HyperTextAccessibleBase* text = acc->AsHyperTextBase();
if (!text || !acc->IsTextRole()) {
return nullptr;
}
RefPtr<AccAttributes> attributes =
text->TextAttributes(false, aOffset, &startOffset, &endOffset);
*aStartOffset = startOffset;
*aEndOffset = endOffset;
return ConvertToAtkTextAttributeSet(attrs);
return ConvertToAtkTextAttributeSet(attributes);
}
static AtkAttributeSet* getDefaultAttributesCB(AtkText* aText) {

View file

@ -5,7 +5,9 @@
#include "HyperTextAccessibleBase.h"
#include "AccAttributes.h"
#include "mozilla/a11y/Accessible.h"
#include "mozilla/a11y/HyperTextAccessible.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "nsAccUtils.h"
#include "TextLeafRange.h"
@ -292,4 +294,85 @@ Accessible* HyperTextAccessibleBase::LinkAt(uint32_t aIndex) {
return Acc()->EmbeddedChildAt(aIndex);
}
already_AddRefed<AccAttributes> HyperTextAccessibleBase::TextAttributes(
bool aIncludeDefAttrs, int32_t aOffset, int32_t* aStartOffset,
int32_t* aEndOffset) {
MOZ_ASSERT(StaticPrefs::accessibility_cache_enabled_AtStartup());
*aStartOffset = *aEndOffset = 0;
index_t offset = ConvertMagicOffset(aOffset);
if (!offset.IsValid() || offset > CharacterCount()) {
NS_ERROR("Wrong in offset!");
return RefPtr{new AccAttributes()}.forget();
}
Accessible* originAcc = GetChildAtOffset(offset);
if (!originAcc) {
// Offset 0 is correct offset when accessible has empty text. Include
// default attributes if they were requested, otherwise return empty set.
if (offset == 0) {
if (aIncludeDefAttrs) {
// XXX This will be adjusted when DefaultTextAttributes is unified.
if (LocalAccessible* acc = Acc()->AsLocal()) {
return acc->AsHyperText()->DefaultTextAttributes();
}
}
}
return RefPtr{new AccAttributes()}.forget();
}
if (!originAcc->IsText()) {
// This is an embedded object. One or more consecutive embedded objects
// form a single attrs run with no attributes.
*aStartOffset = aOffset;
*aEndOffset = aOffset + 1;
Accessible* parent = originAcc->Parent();
if (!parent) {
return RefPtr{new AccAttributes()}.forget();
}
int32_t originIdx = originAcc->IndexInParent();
if (originIdx > 0) {
// Check for embedded objects before the origin.
for (uint32_t idx = originIdx - 1;; --idx) {
Accessible* sibling = parent->ChildAt(idx);
if (sibling->IsText()) {
break;
}
--*aStartOffset;
if (idx == 0) {
break;
}
}
}
// Check for embedded objects after the origin.
for (uint32_t idx = originIdx + 1;; ++idx) {
Accessible* sibling = parent->ChildAt(idx);
if (!sibling || sibling->IsText()) {
break;
}
++*aEndOffset;
}
return RefPtr{new AccAttributes()}.forget();
}
TextLeafPoint origin = ToTextLeafPoint(static_cast<int32_t>(offset));
RefPtr<AccAttributes> attributes = origin.GetTextAttributes(aIncludeDefAttrs);
TextLeafPoint start = origin.FindTextAttrsStart(
eDirPrevious, /* aIncludeOrigin */ true, attributes, aIncludeDefAttrs);
*aStartOffset =
static_cast<int32_t>(TransformOffset(start.mAcc, start.mOffset,
/* aIsEndOffset */ false));
if (*aStartOffset == static_cast<int32_t>(CharacterCount()) &&
(*aStartOffset > static_cast<int32_t>(offset) || start != origin)) {
// start is before this HyperTextAccessible. In that case,
// Transformoffset will return CharacterCount(), but we want to
// clip to the start of this HyperTextAccessible, not the end.
*aStartOffset = 0;
}
TextLeafPoint end = origin.FindTextAttrsStart(
eDirNext, /* aIncludeOrigin */ false, attributes, aIncludeDefAttrs);
*aEndOffset = static_cast<int32_t>(TransformOffset(end.mAcc, end.mOffset,
/* aIsEndOffset */ true));
return attributes.forget();
}
} // namespace mozilla::a11y

View file

@ -6,6 +6,7 @@
#ifndef _HyperTextAccessibleBase_H_
#define _HyperTextAccessibleBase_H_
#include "AccAttributes.h"
#include "nsIAccessibleText.h"
namespace mozilla::a11y {
@ -124,6 +125,14 @@ class HyperTextAccessibleBase {
*/
Accessible* LinkAt(uint32_t aIndex);
/**
* Return text attributes for the given text range.
*/
virtual already_AddRefed<AccAttributes> TextAttributes(bool aIncludeDefAttrs,
int32_t aOffset,
int32_t* aStartOffset,
int32_t* aEndOffset);
protected:
virtual const Accessible* Acc() const = 0;
Accessible* Acc() {

View file

@ -1165,6 +1165,14 @@ void HyperTextAccessible::TextAfterOffset(int32_t aOffset,
already_AddRefed<AccAttributes> HyperTextAccessible::TextAttributes(
bool aIncludeDefAttrs, int32_t aOffset, int32_t* aStartOffset,
int32_t* aEndOffset) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
// This isn't strictly related to caching, but this new text implementation
// is being developed to make caching feasible. We put it behind this pref
// to make it easy to test while it's still under development.
return HyperTextAccessibleBase::TextAttributes(aIncludeDefAttrs, aOffset,
aStartOffset, aEndOffset);
}
// 1. Get each attribute and its ranges one after another.
// 2. As we get each new attribute, we pass the current start and end offsets
// as in/out parameters. In other words, as attributes are collected,

View file

@ -177,13 +177,9 @@ class HyperTextAccessible : public AccessibleWrap,
int32_t* aStartOffset, int32_t* aEndOffset,
nsAString& aText);
/**
* Return text attributes for the given text range.
*/
already_AddRefed<AccAttributes> TextAttributes(bool aIncludeDefAttrs,
int32_t aOffset,
int32_t* aStartOffset,
int32_t* aEndOffset);
virtual already_AddRefed<AccAttributes> TextAttributes(
bool aIncludeDefAttrs, int32_t aOffset, int32_t* aStartOffset,
int32_t* aEndOffset) override;
/**
* Return text attributes applied to the accessible.

View file

@ -94,9 +94,6 @@ void GetTextBeforeOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType,
char16_t CharAt(int32_t aOffset);
void TextAttributes(bool aIncludeDefAttrs, const int32_t aOffset,
RefPtr<AccAttributes>* aAttributes, int32_t* aStartOffset,
int32_t* aEndOffset);
void DefaultTextAttributes(RefPtr<AccAttributes>* aAttrs);
nsIntRect TextBounds(

View file

@ -226,12 +226,17 @@ char16_t RemoteAccessible::CharAt(int32_t aOffset) {
return static_cast<char16_t>(retval);
}
void RemoteAccessible::TextAttributes(bool aIncludeDefAttrs, int32_t aOffset,
RefPtr<AccAttributes>* aAttributes,
int32_t* aStartOffset,
int32_t* aEndOffset) {
Unused << mDoc->SendTextAttributes(mID, aIncludeDefAttrs, aOffset,
aAttributes, aStartOffset, aEndOffset);
already_AddRefed<AccAttributes> RemoteAccessible::TextAttributes(
bool aIncludeDefAttrs, int32_t aOffset, int32_t* aStartOffset,
int32_t* aEndOffset) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
return RemoteAccessibleBase<RemoteAccessible>::TextAttributes(
aIncludeDefAttrs, aOffset, aStartOffset, aEndOffset);
}
RefPtr<AccAttributes> attrs;
Unused << mDoc->SendTextAttributes(mID, aIncludeDefAttrs, aOffset, &attrs,
aStartOffset, aEndOffset);
return attrs.forget();
}
void RemoteAccessible::DefaultTextAttributes(RefPtr<AccAttributes>* aAttrs) {

View file

@ -35,6 +35,10 @@ class RemoteAccessible : public RemoteAccessibleBase<RemoteAccessible> {
virtual uint32_t CharacterCount() const override;
virtual already_AddRefed<AccAttributes> TextAttributes(
bool aIncludeDefAttrs, int32_t aOffset, int32_t* aStartOffset,
int32_t* aEndOffset) override;
protected:
explicit RemoteAccessible(DocAccessibleParent* aThisAsDoc)
: RemoteAccessibleBase(aThisAsDoc) {

View file

@ -65,15 +65,16 @@ ia2AccessibleText::get_attributes(long aOffset, long* aStartOffset,
*aTextAttributes = nullptr;
int32_t startOffset = 0, endOffset = 0;
auto [textAcc, hr] = LocalTextAcc();
HyperTextAccessibleBase* textAcc = TextAcc();
if (!textAcc) {
return hr;
return CO_E_OBJNOTCONNECTED;
}
RefPtr<AccAttributes> attributes =
textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset);
hr = ia2Accessible::ConvertToIA2Attributes(attributes, aTextAttributes);
HRESULT hr =
ia2Accessible::ConvertToIA2Attributes(attributes, aTextAttributes);
if (FAILED(hr)) return hr;
*aStartOffset = startOffset;

View file

@ -164,11 +164,12 @@ xpcAccessibleHyperText::GetTextAttributes(
if (!mIntl) return NS_ERROR_FAILURE;
if (mIntl->IsRemote()) {
if (mIntl->IsRemote() &&
!StaticPrefs::accessibility_cache_enabled_AtStartup()) {
return NS_ERROR_NOT_IMPLEMENTED;
}
RefPtr<AccAttributes> attributes = IntlLocal()->TextAttributes(
RefPtr<AccAttributes> attributes = Intl()->TextAttributes(
aIncludeDefAttrs, aOffset, aStartOffset, aEndOffset);
RefPtr<nsPersistentProperties> props = new nsPersistentProperties();
nsAutoString unused;