6#if QT_CONFIG(accessibility)
8#include "atspiadaptor_p.h"
9#include "qspi_constant_mappings_p.h"
13using namespace Qt::StringLiterals;
15Q_STATIC_LOGGING_CATEGORY(lcAccessibilityAtspi,
"qt.accessibility.atspi")
17QSpiMatchRuleMatcher::QSpiMatchRuleMatcher(
const QSpiMatchRule &matchRule)
18 : m_states(spiStatesFromSpiStateSet(matchRule.states)),
19 m_stateMatchType(matchRule.stateMatchType),
20 m_attributes(matchRule.attributes),
21 m_attributeMatchType(matchRule.attributeMatchType),
22 m_roleMatchType(matchRule.roleMatchType),
23 m_interfaceMatchType(matchRule.interfaceMatchType)
26 std::unordered_set<AtspiRole> atSpiRoles;
27 for (
int i = 0; i < matchRule.roles.size(); ++i) {
28 for (
int j = 0; j < 32; j++) {
29 if (matchRule.roles.at(i) & (1 << j)) {
30 const int atspiRole = i * 32 + j;
31 if (atspiRole < ATSPI_ROLE_LAST_DEFINED)
32 m_roles.insert(AtspiRole(atspiRole));
34 qCWarning(lcAccessibilityAtspi)
35 <<
"Ignoring invalid AT-SPI role value" << atspiRole;
41 for (
const QString &ifaceName : matchRule.interfaces)
42 m_interfaces.push_back(
"org.a11y.atspi."_L1 + ifaceName);
45bool QSpiMatchRuleMatcher::matchAttributes(QAccessibleInterface &iface)
const
47 switch (m_attributeMatchType) {
48 case ATSPI_Collection_MATCH_EMPTY:
49 if (m_attributes.empty())
50 return AtSpiAdaptor::getAttributes(&iface).isEmpty();
52 case ATSPI_Collection_MATCH_ALL: {
53 if (m_attributes.empty())
55 const QSpiAttributeSet attributes = AtSpiAdaptor::getAttributes(&iface);
56 for (
const auto &[key, value] : m_attributes.asKeyValueRange()) {
57 if (!attributes.contains(key) || attributes[key] != value)
62 case ATSPI_Collection_MATCH_ANY: {
63 const QSpiAttributeSet attributes = AtSpiAdaptor::getAttributes(&iface);
64 for (
const auto &[key, value] : m_attributes.asKeyValueRange()) {
65 if (attributes.contains(key) && attributes[key] == value)
70 case ATSPI_Collection_MATCH_NONE: {
71 const QSpiAttributeSet attributes = AtSpiAdaptor::getAttributes(&iface);
72 for (
const auto &[key, value] : m_attributes.asKeyValueRange()) {
73 if (attributes.contains(key) && attributes[key] == value)
79 qCWarning(lcAccessibilityAtspi)
80 <<
"QSpiMatchRuleMatcher::matchAttributes called with invalid match type "
81 << m_attributeMatchType;
86bool QSpiMatchRuleMatcher::matchInterfaces(QAccessibleInterface &iface)
const
88 switch (m_interfaceMatchType) {
89 case ATSPI_Collection_MATCH_EMPTY:
90 if (m_interfaces.empty())
91 return AtSpiAdaptor::accessibleInterfaces(&iface).isEmpty();
93 case ATSPI_Collection_MATCH_ALL: {
94 if (m_interfaces.empty())
96 const QStringList interfaces = AtSpiAdaptor::accessibleInterfaces(&iface);
97 for (
const QString &atSpiInterface : m_interfaces) {
98 if (!interfaces.contains(atSpiInterface))
103 case ATSPI_Collection_MATCH_ANY: {
104 const QStringList interfaces = AtSpiAdaptor::accessibleInterfaces(&iface);
105 for (
const QString &atSpiInterface : m_interfaces) {
106 if (interfaces.contains(atSpiInterface))
111 case ATSPI_Collection_MATCH_NONE: {
112 const QStringList interfaces = AtSpiAdaptor::accessibleInterfaces(&iface);
113 for (
const QString &atSpiInterface : m_interfaces) {
114 if (interfaces.contains(atSpiInterface))
120 qCWarning(lcAccessibilityAtspi)
121 <<
"QSpiMatchRuleMatcher::matchInterfaces called with invalid match type "
122 << m_interfaceMatchType;
127bool QSpiMatchRuleMatcher::matchRoles(QAccessibleInterface &iface)
const
129 switch (m_roleMatchType) {
130 case ATSPI_Collection_MATCH_EMPTY:
135 case ATSPI_Collection_MATCH_ALL:
138 if (m_roles.size() > 1)
142 case ATSPI_Collection_MATCH_ANY:
143 return m_roles.find(AtSpiAdaptor::getRole(&iface)) != m_roles.end();
144 case ATSPI_Collection_MATCH_NONE:
145 return m_roles.find(AtSpiAdaptor::getRole(&iface)) == m_roles.end();
147 qCWarning(lcAccessibilityAtspi)
148 <<
"QSpiMatchRuleMatcher::matchRoles called with invalid match type "
154bool QSpiMatchRuleMatcher::matchStates(QAccessibleInterface &iface)
const
156 switch (m_stateMatchType) {
157 case ATSPI_Collection_MATCH_EMPTY:
159 return spiStatesFromQState(iface.state()) == 0;
161 case ATSPI_Collection_MATCH_ALL:
162 return (spiStatesFromQState(iface.state()) & m_states) == m_states;
163 case ATSPI_Collection_MATCH_ANY:
164 return (spiStatesFromQState(iface.state()) & m_states) != 0;
165 case ATSPI_Collection_MATCH_NONE:
166 return (spiStatesFromQState(iface.state()) & m_states) == 0;
168 qCWarning(lcAccessibilityAtspi)
169 <<
"QSpiMatchRuleMatcher::matchStates called with invalid match type "
175bool QSpiMatchRuleMatcher::match(QAccessibleInterface &iface)
const
177 return matchRoles(iface) && matchStates(iface) && matchInterfaces(iface)
178 && matchAttributes(iface);