From 0b5874bc96f4d1a8cba4fe14ee0b3499cc04c8cd Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Thu, 12 Sep 2024 17:21:37 +0200 Subject: [PATCH] a11y: Add new BlockQuote role Add a new QAccessible::BlockQuote role that can be used to report quoted content to assistive technology as such (e.g. by browsers or document editors like LibreOffice). This matches the role as specified in e.g. ARIA [1], IAccessible2 [2] and AT-SPI [3]. Map the role to platform APIs as described in the The W3C Core Accessibility mappings spec [4]: * Linux/AT-SPI: ATSPI_ROLE_BLOCK_QUOTE * Windows/UIA: UIA_GroupControlTypeId with a UIA_LocalizedControlTypePropertyId of "blockquote" * macOS/NSAccessibility: NSAccessibilityGroupRole In the QAccessible::Role enum, also add comments for the other IAccessible2 roles that have been added in the meantime, to match the existing approach. (Note however that Qt itself doesn't even use IAccessible2 for its Windows a11y bridge any more since 2017 commit 0cf6297c15be45d852be98c862bd0211e6de1aa2, so it's a bit unclear to me whether there's really value in keeping those IAccessible2 references there in the long run.) [1] https://w3c.github.io/aria/#blockquote [2] https://github.com/LinuxA11y/IAccessible2/blob/2b8c2c79417bad4b464761a142fab45ffde8bfa8/api/AccessibleRole.idl#L318 [3] https://docs.gtk.org/atspi2/enum.Role.html#block_quote [4] https://www.w3.org/TR/core-aam-1.2/#role-map-blockquote [ChangeLog][QtGui][QAccessible] Added new BlockQuote role that can be used to report quoted content as such to assistive technology. Fixes: QTBUG-128870 Change-Id: I8707d9d77640b67416f726d266b4cbec5ac09422 Reviewed-by: Volker Hilsheimer --- src/gui/accessible/linux/qspiaccessiblebridge.cpp | 2 ++ src/gui/accessible/qaccessible.cpp | 1 + src/gui/accessible/qaccessible_base.h | 8 ++++++++ src/plugins/platforms/cocoa/qcocoaaccessibility.mm | 1 + .../windows/uiautomation/qwindowsuiamainprovider.cpp | 6 ++++++ .../platforms/windows/uiautomation/qwindowsuiautils.cpp | 1 + 6 files changed, 19 insertions(+) diff --git a/src/gui/accessible/linux/qspiaccessiblebridge.cpp b/src/gui/accessible/linux/qspiaccessiblebridge.cpp index db8b1d949d6..1eab8846653 100644 --- a/src/gui/accessible/linux/qspiaccessiblebridge.cpp +++ b/src/gui/accessible/linux/qspiaccessiblebridge.cpp @@ -247,6 +247,8 @@ static RoleMapping map[] = { //: Role of an accessible object { QAccessible::Notification, ATSPI_ROLE_NOTIFICATION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "notification") }, //: Role of an accessible object + { QAccessible::BlockQuote, ATSPI_ROLE_BLOCK_QUOTE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "block quote") }, + //: Role of an accessible object { QAccessible::UserRole, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "unknown") } }; diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index 5c7155ab5e2..0ff9ee8afd0 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -278,6 +278,7 @@ Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); \value Animation An object that displays an animation. \value Application The application's main window. \value Assistant An object that provides interactive help. + \value [since 6.9] BlockQuote A section of content that is quoted from another source. \value Border An object that represents a border. \value ButtonDropDown A button that drops down a list of items. \value ButtonDropGrid A button that drops down a grid. diff --git a/src/gui/accessible/qaccessible_base.h b/src/gui/accessible/qaccessible_base.h index 45d5a4b53ad..27a0fd4f92e 100644 --- a/src/gui/accessible/qaccessible_base.h +++ b/src/gui/accessible/qaccessible_base.h @@ -314,6 +314,14 @@ public: // IA2_ROLE_TOGGLE_BUTTON = 0x42A, // IA2_ROLE_VIEW_PORT = 0x42B, ComplementaryContent = 0x42C, + // IA2_ROLE_LANDMARK = 0x42D, + // IA2_ROLE_LEVEL_BAR = 0x42E, + // IA2_ROLE_CONTENT_DELETION = 0x42F, + // IA2_ROLE_CONTENT_INSERTION = 0x430, + BlockQuote = 0x431, + // IA2_ROLE_MARK = 0x432, + // IA2_ROLE_SUGGESTION = 0x433, + // IA2_ROLE_COMMENT = = 0x434, UserRole = 0x0000ffff }; diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 7cab078c64c..448c5415555 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -157,6 +157,7 @@ static void populateRoleMap() roleMap[QAccessible::ComplementaryContent] = NSAccessibilityGroupRole; roleMap[QAccessible::Graphic] = NSAccessibilityImageRole; roleMap[QAccessible::Tree] = NSAccessibilityOutlineRole; + roleMap[QAccessible::BlockQuote] = NSAccessibilityGroupRole; } /* diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 56181caa215..c86fb45689c 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -588,6 +588,12 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR case UIA_FullDescriptionPropertyId: *pRetVal = QComVariant{ accessible->text(QAccessible::Description) }.release(); break; + case UIA_LocalizedControlTypePropertyId: + // see Core Accessibility API Mappings spec: + // https://www.w3.org/TR/core-aam-1.2/#role-map-blockquote + if (accessible->role() == QAccessible::BlockQuote) + *pRetVal = QComVariant{ tr("blockquote") }.release(); + break; case UIA_NamePropertyId: { QString name = accessible->text(QAccessible::Name); if (name.isEmpty() && topLevelWindow) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index 91e9cf53d31..7536ece4dbc 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -150,6 +150,7 @@ long roleToControlTypeId(QAccessible::Role role) {QAccessible::Paragraph, UIA_TextControlTypeId}, {QAccessible::WebDocument, UIA_DocumentControlTypeId}, {QAccessible::Heading, UIA_TextControlTypeId}, + {QAccessible::BlockQuote, UIA_GroupControlTypeId}, }; return mapping.value(role, UIA_CustomControlTypeId);