Bug 1901461: Implement UIA_StyleIdAttributeId, r=Jamie

This revision implements supportable styles covered by
UIA_StyleIdAttributeId. Namely, this includes the heading levels,
quotes, and emphasis. These are implemented with Accessible role checks.
To get the levels, this revision makes GetLevel a public function. It
also adds constant definitions for MinGW builds. Finally, this revision
adds tests to the existing GetAttributeValue tests.

Differential Revision: https://phabricator.services.mozilla.com/D229082
This commit is contained in:
Nathan LaPre 2024-11-15 19:36:43 +00:00
parent 547f6b3491
commit 8a253fd1ef
5 changed files with 183 additions and 9 deletions

View File

@ -732,6 +732,14 @@ class Accessible {
static void TranslateString(const nsString& aKey, nsAString& aStringOut,
const nsTArray<nsString>& aParams = {});
/*
* Return calculated group level based on accessible hierarchy.
*
* @param aFast [in] Don't climb up tree. Calculate level from aria and
* roles.
*/
virtual int32_t GetLevel(bool aFast) const;
protected:
// Some abstracted group utility methods.
@ -751,14 +759,6 @@ class Accessible {
*/
virtual AccGroupInfo* GetOrCreateGroupInfo() = 0;
/*
* Return calculated group level based on accessible hierarchy.
*
* @param aFast [in] Don't climb up tree. Calculate level from aria and
* roles.
*/
virtual int32_t GetLevel(bool aFast) const;
/**
* Calculate position in group and group size ('posinset' and 'setsize') based
* on accessible hierarchy.

View File

@ -539,6 +539,9 @@ addUiaTask(
<div id="grammar-error-container">a <span aria-invalid="grammar">bcd</span> ef</div>
<div id="data-validation-error-container">a <span aria-invalid="true">bcd</span> ef</div>
<div id="highlight-container">a highlighted phrase ef</div>
<div id="heading-container">ab<h3>h3</h3>cd</div>
<div id="blockquote-container">ab<blockquote>quote</blockquote>cd</div>
<div id="emphasis-container">ab<em>emph</em>cd</div>
`,
async function testTextRangeGetAttributeValue() {
// ================== UIA_FontWeightAttributeId ==================
@ -924,6 +927,110 @@ addUiaTask(
"Highlighted correct"
);
}
// The IA2 -> UIA bridge does not work correctly here.
if (gIsUiaEnabled) {
// ================== UIA_StyleIdAttributeId - StyleId_Heading* ==================
await runPython(`
global range
headingContainerAcc = findUiaByDomId(doc, "heading-container")
range = docText.RangeFromChild(headingContainerAcc)
`);
is(await runPython(`range.GetText(-1)`), "abh3cd", "range text correct");
info("checking mixed StyleId properties");
ok(
await runPython(`
val = range.GetAttributeValue(UIA_StyleIdAttributeId)
return val == uiaClient.ReservedMixedAttributeValue
`),
"StyleId correct (mixed)"
);
info("Moving to h3 text run");
is(
await runPython(`range.Move(TextUnit_Format, 1)`),
1,
"Move return correct"
);
is(await runPython(`range.GetText(-1)`), "h3", "range text correct");
info("checking StyleId");
ok(
await runPython(`
styleId = range.GetAttributeValue(UIA_StyleIdAttributeId)
return styleId == StyleId_Heading3
`),
"StyleId correct"
);
// ================== UIA_StyleIdAttributeId - StyleId_Quote ==================
await runPython(`
global range
blockquoteContainerAcc = findUiaByDomId(doc, "blockquote-container")
range = docText.RangeFromChild(blockquoteContainerAcc)
`);
is(
await runPython(`range.GetText(-1)`),
"abquotecd",
"range text correct"
);
info("checking mixed StyleId properties");
ok(
await runPython(`
val = range.GetAttributeValue(UIA_StyleIdAttributeId)
return val == uiaClient.ReservedMixedAttributeValue
`),
"StyleId correct (mixed)"
);
info("Moving to blockquote text run");
is(
await runPython(`range.Move(TextUnit_Format, 1)`),
1,
"Move return correct"
);
is(await runPython(`range.GetText(-1)`), "quote", "range text correct");
info("checking StyleId");
ok(
await runPython(`
styleId = range.GetAttributeValue(UIA_StyleIdAttributeId)
return styleId == StyleId_Quote
`),
"StyleId correct"
);
// ================== UIA_StyleIdAttributeId - StyleId_Emphasis ==================
await runPython(`
global range
emphasisContainerAcc = findUiaByDomId(doc, "emphasis-container")
range = docText.RangeFromChild(emphasisContainerAcc)
`);
is(
await runPython(`range.GetText(-1)`),
"abemphcd",
"range text correct"
);
info("checking mixed StyleId properties");
ok(
await runPython(`
val = range.GetAttributeValue(UIA_StyleIdAttributeId)
return val == uiaClient.ReservedMixedAttributeValue
`),
"StyleId correct (mixed)"
);
info("Moving to emphasized text run");
is(
await runPython(`range.Move(TextUnit_Format, 1)`),
1,
"Move return correct"
);
is(await runPython(`range.GetText(-1)`), "emph", "range text correct");
info("checking StyleId");
ok(
await runPython(`
styleId = range.GetAttributeValue(UIA_StyleIdAttributeId)
return styleId == StyleId_Emphasis
`),
"StyleId correct"
);
}
},
{ urlSuffix: "#:~:text=highlighted%20phrase" }
);

View File

@ -437,6 +437,8 @@ UiaTextRange::GetAttributeValue(TEXTATTRIBUTEID aAttributeId,
return GetAttribute<UIA_IsItalicAttributeId>(range, *aRetVal);
case UIA_IsReadOnlyAttributeId:
return GetAttribute<UIA_IsReadOnlyAttributeId>(range, *aRetVal);
case UIA_StyleIdAttributeId:
return GetAttribute<UIA_StyleIdAttributeId>(range, *aRetVal);
case UIA_IsSubscriptAttributeId:
return GetAttribute<UIA_IsSubscriptAttributeId>(range, *aRetVal);
case UIA_IsSuperscriptAttributeId:
@ -899,6 +901,52 @@ struct AttributeTraits<UIA_IsItalicAttributeId> {
}
};
template <>
struct AttributeTraits<UIA_StyleIdAttributeId> {
using AttrType = int32_t;
static Maybe<AttrType> GetValue(TextLeafPoint aPoint) {
Accessible* acc = aPoint.mAcc;
if (!acc || !acc->Parent()) {
return {};
}
acc = acc->Parent();
const role role = acc->Role();
if (role == roles::HEADING) {
switch (acc->GetLevel(true)) {
case 1:
return Some(StyleId_Heading1);
case 2:
return Some(StyleId_Heading2);
case 3:
return Some(StyleId_Heading3);
case 4:
return Some(StyleId_Heading4);
case 5:
return Some(StyleId_Heading5);
case 6:
return Some(StyleId_Heading6);
default:
return {};
}
}
if (role == roles::BLOCKQUOTE) {
return Some(StyleId_Quote);
}
if (role == roles::EMPHASIS) {
return Some(StyleId_Emphasis);
}
return {};
}
static AttrType DefaultValue() { return 0; }
static HRESULT WriteToVariant(VARIANT& aVariant, const AttrType& aValue) {
aVariant.vt = VT_I4;
aVariant.lVal = aValue;
return S_OK;
}
};
template <>
struct AttributeTraits<UIA_IsSubscriptAttributeId> {
using AttrType = bool;

View File

@ -85,4 +85,23 @@ const long AnnotationType_CircularReferenceError = 60022;
const long AnnotationType_Mathematics = 60023;
const long AnnotationType_Sensitive = 60024;
// UIA Style Identifiers
const long StyleId_Custom = 70000;
const long StyleId_Heading1 = 70001;
const long StyleId_Heading2 = 70002;
const long StyleId_Heading3 = 70003;
const long StyleId_Heading4 = 70004;
const long StyleId_Heading5 = 70005;
const long StyleId_Heading6 = 70006;
const long StyleId_Heading7 = 70007;
const long StyleId_Heading8 = 70008;
const long StyleId_Heading9 = 70009;
const long StyleId_Title = 70010;
const long StyleId_Subtitle = 70011;
const long StyleId_Normal = 70012;
const long StyleId_Emphasis = 70013;
const long StyleId_Quote = 70014;
const long StyleId_BulletedList = 70015;
const long StyleId_NumberedList = 70016;
#endif // mozilla_a11y_supplementalMinGWDefinitions_h__

View File

@ -26,6 +26,7 @@ class XULMenuitemAccessible : public AccessibleWrap {
virtual a11y::role NativeRole() const override;
virtual uint64_t NativeState() const override;
virtual uint64_t NativeInteractiveState() const override;
virtual int32_t GetLevel(bool aFast) const override;
// ActionAccessible
virtual bool HasPrimaryAction() const override;
@ -41,7 +42,6 @@ class XULMenuitemAccessible : public AccessibleWrap {
protected:
// LocalAccessible
virtual ENameValueFlag NativeName(nsString& aName) const override;
virtual int32_t GetLevel(bool aFast) const override;
};
/**