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: I55ead0e87e7e298f4fae14a197716f86494334b0
Task-number: QTBUG-44479
Reviewed-by: Jan Arve Sæther <jan-arve.saether@theqtcompany.com>
This commit is contained in:
Boris Dušek 2015-02-15 23:04:51 +01:00
parent 62bcb1f4ba
commit b873043fc4

View File

@ -1924,6 +1924,124 @@ QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTex
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
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) {
QStringList items;
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;
@ -1962,7 +2082,9 @@ QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, in
foreach (const QString& attr, attributes) {
QStringList items;
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];
defined = mapped.isEmpty();