Accessibility Linux: Fix text attributes
Orca expects text attributes with different names (and sometimes also different values) than IAccessible2 ones (which Qt uses). So adapt the names and values accordingly. [ChangeLog][Accessibility] We now report text attributes correctly on Linux, so ORCA+F now works properly in QTextEdit and other text controls. Change-Id: Iad6d38168b309669c00069a6167f4f54cbd64cf0 Task-number: QTBUG-44479 Reviewed-by: Jan Arve Sæther <jan-arve.saether@theqtcompany.com>
This commit is contained in:
parent
76c94be4e7
commit
f5883eb906
@ -1924,6 +1924,124 @@ QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTex
|
|||||||
return QAccessible::CharBoundary;
|
return QAccessible::CharBoundary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct AtSpiAttribute {
|
||||||
|
QString name;
|
||||||
|
QString value;
|
||||||
|
AtSpiAttribute(const QString &aName, const QString &aValue) : name(aName), value(aValue) {}
|
||||||
|
bool isNull() const { return name.isNull() || value.isNull(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
QString atspiColor(const QString &ia2Color)
|
||||||
|
{
|
||||||
|
// "rgb(%u,%u,%u)" -> "%u,%u,%u"
|
||||||
|
return ia2Color.mid(4, ia2Color.length() - (4+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString atspiSize(const QString &ia2Size)
|
||||||
|
{
|
||||||
|
// "%fpt" -> "%f"
|
||||||
|
return ia2Size.left(ia2Size.length() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
AtSpiAttribute atspiTextAttribute(const QString &ia2Name, const QString &ia2Value)
|
||||||
|
{
|
||||||
|
QString name = ia2Name;
|
||||||
|
QString value = ia2Value;
|
||||||
|
|
||||||
|
// IAccessible2: http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2/textattributes
|
||||||
|
// ATK attribute names: https://git.gnome.org/browse/orca/tree/src/orca/text_attribute_names.py
|
||||||
|
// ATK attribute values: https://developer.gnome.org/atk/unstable/AtkText.html#AtkTextAttribute
|
||||||
|
|
||||||
|
// https://bugzilla.gnome.org/show_bug.cgi?id=744553 "ATK docs provide no guidance for allowed values of some text attributes"
|
||||||
|
// specifically for "weight", "invalid", "language" and value range for colors
|
||||||
|
|
||||||
|
if (ia2Name == QStringLiteral("background-color")) {
|
||||||
|
name = QStringLiteral("bg-color");
|
||||||
|
value = atspiColor(value);
|
||||||
|
} else if (ia2Name == QStringLiteral("font-family")) {
|
||||||
|
name = QStringLiteral("family-name");
|
||||||
|
} else if (ia2Name == QStringLiteral("color")) {
|
||||||
|
name = QStringLiteral("fg-color");
|
||||||
|
value = atspiColor(value);
|
||||||
|
} else if (ia2Name == QStringLiteral("text-align")) {
|
||||||
|
name = QStringLiteral("justification");
|
||||||
|
if (value == QStringLiteral("justify")) {
|
||||||
|
value = QStringLiteral("fill");
|
||||||
|
} else {
|
||||||
|
if (value != QStringLiteral("left") &&
|
||||||
|
value != QStringLiteral("right") &&
|
||||||
|
value != QStringLiteral("center")
|
||||||
|
) {
|
||||||
|
value = QString();
|
||||||
|
qAtspiDebug() << "Unknown text-align attribute value \"" << value << "\" cannot be translated to AT-SPI.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ia2Name == QStringLiteral("font-size")) {
|
||||||
|
name = QStringLiteral("size");
|
||||||
|
value = atspiSize(value);
|
||||||
|
} else if (ia2Name == QStringLiteral("font-style")) {
|
||||||
|
name = QStringLiteral("style");
|
||||||
|
if (value != QStringLiteral("normal") &&
|
||||||
|
value != QStringLiteral("italic") &&
|
||||||
|
value != QStringLiteral("oblique")
|
||||||
|
) {
|
||||||
|
value = QString();
|
||||||
|
qAtspiDebug() << "Unknown font-style attribute value \"" << value << "\" cannot be translated to AT-SPI.";
|
||||||
|
}
|
||||||
|
} else if (ia2Name == QStringLiteral("text-underline-type")) {
|
||||||
|
name = QStringLiteral("underline");
|
||||||
|
if (value != QStringLiteral("none") &&
|
||||||
|
value != QStringLiteral("single") &&
|
||||||
|
value != QStringLiteral("double")
|
||||||
|
) {
|
||||||
|
value = QString();
|
||||||
|
qAtspiDebug() << "Unknown text-underline-type attribute value \"" << value << "\" cannot be translated to AT-SPI.";
|
||||||
|
}
|
||||||
|
} else if (ia2Name == QStringLiteral("font-weight")) {
|
||||||
|
name = QStringLiteral("weight");
|
||||||
|
if (value == QStringLiteral("normal"))
|
||||||
|
// Orca seems to accept all IAccessible2 values except for "normal"
|
||||||
|
// (on which it produces traceback and fails to read any following text attributes),
|
||||||
|
// but that is the default value, so omit it anyway
|
||||||
|
value = QString();
|
||||||
|
} else if (ia2Name == QStringLiteral("text-position")) {
|
||||||
|
name = QStringLiteral("vertical-align");
|
||||||
|
if (value != QStringLiteral("baseline") &&
|
||||||
|
value != QStringLiteral("super") &&
|
||||||
|
value != QStringLiteral("sub")
|
||||||
|
) {
|
||||||
|
value = QString();
|
||||||
|
qAtspiDebug() << "Unknown text-position attribute value \"" << value << "\" cannot be translated to AT-SPI.";
|
||||||
|
}
|
||||||
|
} else if (ia2Name == QStringLiteral("writing-mode")) {
|
||||||
|
name = QStringLiteral("direction");
|
||||||
|
if (value == QStringLiteral("lr"))
|
||||||
|
value = QStringLiteral("ltr");
|
||||||
|
else if (value == QStringLiteral("rl"))
|
||||||
|
value = QStringLiteral("rtl");
|
||||||
|
else if (value == QStringLiteral("tb")) {
|
||||||
|
// IAccessible2 docs refer to XSL, which specifies "tb" is shorthand for "tb-rl"; so at least give a hint about the horizontal direction (ATK does not support vertical direction in this attribute (yet))
|
||||||
|
value = QStringLiteral("rtl");
|
||||||
|
qAtspiDebug() << "writing-mode attribute value \"tb\" translated only w.r.t. horizontal direction; vertical direction ignored";
|
||||||
|
} else {
|
||||||
|
value = QString();
|
||||||
|
qAtspiDebug() << "Unknown writing-mode attribute value \"" << value << "\" cannot be translated to AT-SPI.";
|
||||||
|
}
|
||||||
|
} else if (ia2Name == QStringLiteral("language")) {
|
||||||
|
// OK - ATK has no docs on the format of the value, IAccessible2 has reasonable format - leave it at that now
|
||||||
|
} else if (ia2Name == QStringLiteral("invalid")) {
|
||||||
|
// OK - ATK docs are vague but suggest they support the same range of values as IAccessible2
|
||||||
|
} else {
|
||||||
|
// attribute we know nothing about
|
||||||
|
name = QString();
|
||||||
|
value = QString();
|
||||||
|
}
|
||||||
|
return AtSpiAttribute(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME all attribute methods below should share code
|
// FIXME all attribute methods below should share code
|
||||||
QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int offset, bool includeDefaults) const
|
QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int offset, bool includeDefaults) const
|
||||||
{
|
{
|
||||||
@ -1938,7 +2056,9 @@ QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int of
|
|||||||
foreach (const QString &attr, attributes) {
|
foreach (const QString &attr, attributes) {
|
||||||
QStringList items;
|
QStringList items;
|
||||||
items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
|
items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
|
||||||
set[items[0]] = items[1];
|
AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
|
||||||
|
if (!attribute.isNull())
|
||||||
|
set[attribute.name] = attribute.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantList list;
|
QVariantList list;
|
||||||
@ -1962,7 +2082,9 @@ QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, in
|
|||||||
foreach (const QString& attr, attributes) {
|
foreach (const QString& attr, attributes) {
|
||||||
QStringList items;
|
QStringList items;
|
||||||
items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
|
items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
|
||||||
map[items[0]] = items[1];
|
AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
|
||||||
|
if (!attribute.isNull())
|
||||||
|
map[attribute.name] = attribute.value;
|
||||||
}
|
}
|
||||||
mapped = map[attributeName];
|
mapped = map[attributeName];
|
||||||
defined = mapped.isEmpty();
|
defined = mapped.isEmpty();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user