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 for (qsizetype i = 0; i < matchRule.roles.size(); ++i) {
27 const auto role = matchRule.roles.at(i);
28 for (
int j = 0; j < 32; j++) {
29 if (role & (1 << j)) {
30 const auto 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 m_interfaces.reserve(matchRule.interfaces.size());
42 for (
const QString &ifaceName : matchRule.interfaces)
43 m_interfaces.push_back(
"org.a11y.atspi."_L1 + ifaceName);
46bool QSpiMatchRuleMatcher::matchAttributes(QAccessibleInterface &iface)
const
48 switch (m_attributeMatchType) {
49 case ATSPI_Collection_MATCH_EMPTY:
50 if (m_attributes.empty())
51 return AtSpiAdaptor::getAttributes(&iface).isEmpty();
53 case ATSPI_Collection_MATCH_ALL: {
54 if (m_attributes.empty())
56 const QSpiAttributeSet attributes = AtSpiAdaptor::getAttributes(&iface);
57 for (
const auto &[key, value] : m_attributes.asKeyValueRange()) {
58 if (!attributes.contains(key) || attributes[key] != value)
63 case ATSPI_Collection_MATCH_ANY: {
64 const QSpiAttributeSet attributes = AtSpiAdaptor::getAttributes(&iface);
65 for (
const auto &[key, value] : m_attributes.asKeyValueRange()) {
66 if (attributes.contains(key) && attributes[key] == value)
71 case ATSPI_Collection_MATCH_NONE: {
72 const QSpiAttributeSet attributes = AtSpiAdaptor::getAttributes(&iface);
73 for (
const auto &[key, value] : m_attributes.asKeyValueRange()) {
74 if (attributes.contains(key) && attributes[key] == value)
80 qCWarning(lcAccessibilityAtspi)
81 <<
"QSpiMatchRuleMatcher::matchAttributes called with invalid match type "
82 << m_attributeMatchType;
87bool QSpiMatchRuleMatcher::matchInterfaces(QAccessibleInterface &iface)
const
89 switch (m_interfaceMatchType) {
90 case ATSPI_Collection_MATCH_EMPTY:
91 if (m_interfaces.empty())
92 return AtSpiAdaptor::accessibleInterfaces(&iface).isEmpty();
94 case ATSPI_Collection_MATCH_ALL: {
95 if (m_interfaces.empty())
97 const QStringList interfaces = AtSpiAdaptor::accessibleInterfaces(&iface);
98 for (
const QString &atSpiInterface : m_interfaces) {
99 if (!interfaces.contains(atSpiInterface))
104 case ATSPI_Collection_MATCH_ANY: {
105 const QStringList interfaces = AtSpiAdaptor::accessibleInterfaces(&iface);
106 for (
const QString &atSpiInterface : m_interfaces) {
107 if (interfaces.contains(atSpiInterface))
112 case ATSPI_Collection_MATCH_NONE: {
113 const QStringList interfaces = AtSpiAdaptor::accessibleInterfaces(&iface);
114 for (
const QString &atSpiInterface : m_interfaces) {
115 if (interfaces.contains(atSpiInterface))
121 qCWarning(lcAccessibilityAtspi)
122 <<
"QSpiMatchRuleMatcher::matchInterfaces called with invalid match type "
123 << m_interfaceMatchType;
128bool QSpiMatchRuleMatcher::matchRoles(QAccessibleInterface &iface)
const
130 switch (m_roleMatchType) {
131 case ATSPI_Collection_MATCH_EMPTY:
136 case ATSPI_Collection_MATCH_ALL:
139 if (m_roles.size() > 1)
143 case ATSPI_Collection_MATCH_ANY:
144 return m_roles.find(AtSpiAdaptor::getRole(&iface)) != m_roles.end();
145 case ATSPI_Collection_MATCH_NONE:
146 return m_roles.find(AtSpiAdaptor::getRole(&iface)) == m_roles.end();
148 qCWarning(lcAccessibilityAtspi)
149 <<
"QSpiMatchRuleMatcher::matchRoles called with invalid match type "
155bool QSpiMatchRuleMatcher::matchStates(QAccessibleInterface &iface)
const
157 switch (m_stateMatchType) {
158 case ATSPI_Collection_MATCH_EMPTY:
160 return spiStatesFromQState(iface.state()) == 0;
162 case ATSPI_Collection_MATCH_ALL:
163 return (spiStatesFromQState(iface.state()) & m_states) == m_states;
164 case ATSPI_Collection_MATCH_ANY:
165 return (spiStatesFromQState(iface.state()) & m_states) != 0;
166 case ATSPI_Collection_MATCH_NONE:
167 return (spiStatesFromQState(iface.state()) & m_states) == 0;
169 qCWarning(lcAccessibilityAtspi)
170 <<
"QSpiMatchRuleMatcher::matchStates called with invalid match type "
176bool QSpiMatchRuleMatcher::match(QAccessibleInterface &iface)
const
178 return matchRoles(iface) && matchStates(iface) && matchInterfaces(iface)
179 && matchAttributes(iface);