commit d9a75f13cd9862f3a9361128db9b2a4df94cb788
parent 09a7697eb69d839ef145f169859ca452799ccd7e
Author: Eitan Isaacson <eitan@monotonous.org>
Date: Thu, 13 Nov 2025 22:47:52 +0000
Bug 1999424 - Show table's child caption element as label relationship. r=morgan
Light refactor here for name calculation via labeling that is coming
soon.
Differential Revision: https://phabricator.services.mozilla.com/D272508
Diffstat:
3 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/accessible/ipc/RemoteAccessible.cpp b/accessible/ipc/RemoteAccessible.cpp
@@ -1278,41 +1278,67 @@ Relation RemoteAccessible::RelationByType(RelationType aType) const {
// the cached relations need to take precedence. For example, a <figure> with
// both aria-labelledby and a <figcaption> must return two LABELLED_BY
// targets: the aria-labelledby and then the <figcaption>.
- auto AddChildWithTag = [this, &rel](nsAtom* aTarget) {
+ if (aType == RelationType::LABELLED_BY) {
+ for (RemoteAccessible* label : LegendsOrCaptions()) {
+ rel.AppendTarget(label);
+ }
+ } else if (aType == RelationType::LABEL_FOR) {
+ if (RemoteAccessible* labelTarget = LegendOrCaptionFor()) {
+ rel.AppendTarget(labelTarget);
+ }
+ }
+
+ return rel;
+}
+
+nsTArray<RemoteAccessible*> RemoteAccessible::LegendsOrCaptions() const {
+ nsTArray<RemoteAccessible*> children;
+ auto AddChildWithTag = [this, &children](nsAtom* aTarget) {
uint32_t count = ChildCount();
for (uint32_t c = 0; c < count; ++c) {
RemoteAccessible* child = RemoteChildAt(c);
MOZ_ASSERT(child);
if (child->TagName() == aTarget) {
- rel.AppendTarget(child);
+ children.AppendElement(child);
}
}
};
- if (aType == RelationType::LABELLED_BY) {
- auto tag = TagName();
- if (tag == nsGkAtoms::figure) {
- AddChildWithTag(nsGkAtoms::figcaption);
- } else if (tag == nsGkAtoms::fieldset) {
- AddChildWithTag(nsGkAtoms::legend);
+
+ auto tag = TagName();
+ if (tag == nsGkAtoms::figure) {
+ AddChildWithTag(nsGkAtoms::figcaption);
+ } else if (tag == nsGkAtoms::fieldset) {
+ AddChildWithTag(nsGkAtoms::legend);
+ } else if (tag == nsGkAtoms::table) {
+ AddChildWithTag(nsGkAtoms::caption);
+ }
+
+ return children;
+}
+
+RemoteAccessible* RemoteAccessible::LegendOrCaptionFor() const {
+ auto tag = TagName();
+ if (tag == nsGkAtoms::figcaption) {
+ if (RemoteAccessible* parent = RemoteParent()) {
+ if (parent->TagName() == nsGkAtoms::figure) {
+ return parent;
+ }
}
- } else if (aType == RelationType::LABEL_FOR) {
- auto tag = TagName();
- if (tag == nsGkAtoms::figcaption) {
- if (RemoteAccessible* parent = RemoteParent()) {
- if (parent->TagName() == nsGkAtoms::figure) {
- rel.AppendTarget(parent);
- }
+ } else if (tag == nsGkAtoms::legend) {
+ if (RemoteAccessible* parent = RemoteParent()) {
+ if (parent->TagName() == nsGkAtoms::fieldset) {
+ return parent;
}
- } else if (tag == nsGkAtoms::legend) {
- if (RemoteAccessible* parent = RemoteParent()) {
- if (parent->TagName() == nsGkAtoms::fieldset) {
- rel.AppendTarget(parent);
- }
+ }
+ } else if (tag == nsGkAtoms::caption) {
+ if (RemoteAccessible* parent = RemoteParent()) {
+ if (parent->TagName() == nsGkAtoms::table) {
+ return parent;
}
}
}
- return rel;
+ return nullptr;
}
void RemoteAccessible::AppendTextTo(nsAString& aText, uint32_t aStartOffset,
diff --git a/accessible/ipc/RemoteAccessible.h b/accessible/ipc/RemoteAccessible.h
@@ -500,6 +500,10 @@ class RemoteAccessible : public Accessible, public HyperTextAccessibleBase {
virtual nsTArray<int32_t>& GetCachedHyperTextOffsets() override;
+ nsTArray<RemoteAccessible*> LegendsOrCaptions() const;
+
+ RemoteAccessible* LegendOrCaptionFor() const;
+
private:
/**
* Update mIndexInParent on each child starting at aStartIdx up to the last
diff --git a/accessible/tests/browser/relations/browser_relations_general_002.js b/accessible/tests/browser/relations/browser_relations_general_002.js
@@ -354,3 +354,23 @@ addAccessibleTask(
},
{ chrome: true, topLevel: true }
);
+
+/**
+ * Test table caption.
+ */
+addAccessibleTask(
+ `
+<table id="table">
+ <caption id="caption">caption</caption>
+ <tr><th>a</th></tr>
+</table>
+ `,
+ async function testTableCaption(browser, docAcc) {
+ const table = findAccessibleChildByID(docAcc, "table");
+
+ const caption = findAccessibleChildByID(docAcc, "caption");
+ await testCachedRelation(table, RELATION_LABELLED_BY, caption);
+ await testCachedRelation(caption, RELATION_LABEL_FOR, table);
+ },
+ { chrome: true, topLevel: true }
+);