Merge TextFormat attributes for identical ranges in QInputMethodEvents

IBus can hand us multiple attributes for different formatting properties
of the same text range for events. The IBus input method plugin used to
convert these straight into multiple QInputMethodEvent::Attributes, each
with their own QTextCharFormat instance.

According to the QInputMethodEvent documentation, behavior with multiple
TextFormat attributes for the same text range is undefined. In at least
one known user, KDE's Kate text editor, it causes invisible text for
pre-edit text events as the QTextCharFormats are applied in turn with
partially default-constructed foreground/background brushes:

https://bugs.kde.org/show_bug.cgi?id=339467

This patch makes an effort to merge formatting information for identical
text ranges into a single QTextCharFomat, while otherwise preserving
existing behavior (attribute order is unchanged and attributes deseria-
lized from D-Bus as having invalid QTextFormats remain untouched).

No attempt is made to cope with overlapping text ranges. Segmenting into
smaller ranges and merging for the overlaps would be conceivable, but
until a case of an input method creating events with overlapping ranges
is known seems not worth the effort.

It's worth noting that the IBus input method plugin for Qt 4 also
attempts to merge formatting information into a single QTextCharFormat,
but with a distinct implementation from this one.

Change-Id: Ie3dc38b353724ffb7b5f2d7f316393027373baf2
Task-number: 41640
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Eike Hein 2014-10-13 21:33:57 +02:00 committed by Simon Hausmann
parent 79f832594d
commit c493546a0a
2 changed files with 26 additions and 5 deletions

View File

@ -32,7 +32,6 @@
****************************************************************************/
#include "qibustypes.h"
#include <qtextformat.h>
#include <QtDBus>
#include <QHash>
@ -134,7 +133,7 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusAttribute &a
return argument;
}
QTextFormat QIBusAttribute::format() const
QTextCharFormat QIBusAttribute::format() const
{
QTextCharFormat fmt;
switch (type) {
@ -225,11 +224,32 @@ const QDBusArgument &operator>>(const QDBusArgument &arg, QIBusAttributeList &at
QList<QInputMethodEvent::Attribute> QIBusAttributeList::imAttributes() const
{
QList<QInputMethodEvent::Attribute> imAttrs;
QHash<QPair<int, int>, QTextCharFormat> rangeAttrs;
// Merge text fomats for identical ranges into a single QTextFormat.
for (int i = 0; i < attributes.size(); ++i) {
const QIBusAttribute &attr = attributes.at(i);
imAttrs += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, attr.start, attr.end - attr.start, attr.format());
const QTextCharFormat &format = attr.format();
if (format.isValid()) {
const QPair<int, int> range(attr.start, attr.end);
rangeAttrs[range].merge(format);
}
}
// Assemble list in original attribute order.
QList<QInputMethodEvent::Attribute> imAttrs;
for (int i = 0; i < attributes.size(); ++i) {
const QIBusAttribute &attr = attributes.at(i);
const QTextFormat &format = attr.format();
imAttrs += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
attr.start,
attr.end - attr.start,
format.isValid() ? rangeAttrs[QPair<int, int>(attr.start, attr.end)] : format);
}
return imAttrs;
}

View File

@ -36,6 +36,7 @@
#include <qvector.h>
#include <qevent.h>
#include <QDBusArgument>
#include <QTextCharFormat>
QT_BEGIN_NAMESPACE
@ -70,7 +71,7 @@ public:
QIBusAttribute();
~QIBusAttribute();
QTextFormat format() const;
QTextCharFormat format() const;
Type type;
quint32 value;