Introduce QChar::JoiningType enum and QChar::joiningType() method

This aimed to disctinct joining types "L", "T", and "U" from just "U".
Unicode 6.3.0 has introduced a character with joining type "L" and
Unicode 7.0 will add a few more characters of joining type "L", so
we'll have to deal with it anyways.

[ChangeLog][QtCore][QChar] Added JoiningType enum and joiningType()
 method that deprecates the old QChar::Joining enum and joining() method.

Change-Id: I4be3a3f745d944e689feb9b62d4ca86d1cf371b0
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Konstantin Ritt 2014-01-26 02:42:37 +02:00 committed by The Qt Project
parent b04d87b226
commit b80fcbdba6
6 changed files with 162 additions and 59 deletions

View File

@ -127,9 +127,9 @@ QT_BEGIN_NAMESPACE
Separator_* or an exceptional code point from Other_Control category). Separator_* or an exceptional code point from Other_Control category).
QChar also provides direction(), which indicates the "natural" QChar also provides direction(), which indicates the "natural"
writing direction of this character. The joining() function writing direction of this character. The joiningType() function
indicates how the character joins with it's neighbors (needed indicates how the character joins with it's neighbors (needed
mostly for Arabic) and finally hasMirrored(), which indicates mostly for Arabic or Syriac) and finally hasMirrored(), which indicates
whether the character needs to be mirrored when it is printed in whether the character needs to be mirrored when it is printed in
it's "unnatural" writing direction. it's "unnatural" writing direction.
@ -457,8 +457,30 @@ QT_BEGIN_NAMESPACE
\sa decomposition() \sa decomposition()
*/ */
/*!
\enum QChar::JoiningType
since 5.3
This enum type defines the Unicode joining type attributes. See the
\l{http://www.unicode.org/}{Unicode Standard} for a description of the values.
In order to conform to C/C++ naming conventions "Joining_" is prepended
to the codes used in the Unicode Standard.
\value Joining_None
\value Joining_Causing
\value Joining_Dual
\value Joining_Right
\value Joining_Left
\value Joining_Transparent
\sa joiningType()
*/
#if QT_DEPRECATED_SINCE(5, 3)
/*! /*!
\enum QChar::Joining \enum QChar::Joining
\deprecated in 5.3, use JoiningType instead.
This enum type defines the Unicode joining attributes. See the This enum type defines the Unicode joining attributes. See the
\l{http://www.unicode.org/}{Unicode Standard} for a description \l{http://www.unicode.org/}{Unicode Standard} for a description
@ -471,6 +493,7 @@ QT_BEGIN_NAMESPACE
\sa joining() \sa joining()
*/ */
#endif
/*! /*!
\enum QChar::CombiningClass \enum QChar::CombiningClass
@ -1052,8 +1075,33 @@ QChar::Direction QChar::direction(uint ucs4)
return (QChar::Direction) qGetProp(ucs4)->direction; return (QChar::Direction) qGetProp(ucs4)->direction;
} }
/*!
\fn QChar::JoiningType QChar::joiningType() const
\since 5.3
Returns information about the joining type attributes of the character
(needed for certain languages such as Arabic or Syriac).
*/
/*!
\overload
\since 5.3
Returns information about the joining type attributes of the UCS-4-encoded
character specified by \a ucs4
(needed for certain languages such as Arabic or Syriac).
*/
QChar::JoiningType QChar::joiningType(uint ucs4)
{
if (ucs4 > LastValidCodePoint)
return QChar::Joining_None;
return QChar::JoiningType(qGetProp(ucs4)->joining);
}
#if QT_DEPRECATED_SINCE(5, 3)
/*! /*!
\fn QChar::Joining QChar::joining() const \fn QChar::Joining QChar::joining() const
\deprecated in 5.3, use joiningType() instead.
Returns information about the joining properties of the character Returns information about the joining properties of the character
(needed for certain languages such as Arabic). (needed for certain languages such as Arabic).
@ -1061,6 +1109,8 @@ QChar::Direction QChar::direction(uint ucs4)
/*! /*!
\overload \overload
\deprecated in 5.3, use joiningType() instead.
Returns information about the joining properties of the UCS-4-encoded Returns information about the joining properties of the UCS-4-encoded
character specified by \a ucs4 (needed for certain languages such as Arabic). character specified by \a ucs4 (needed for certain languages such as Arabic).
*/ */
@ -1068,8 +1118,15 @@ QChar::Joining QChar::joining(uint ucs4)
{ {
if (ucs4 > LastValidCodePoint) if (ucs4 > LastValidCodePoint)
return QChar::OtherJoining; return QChar::OtherJoining;
return (QChar::Joining) qGetProp(ucs4)->joining; switch (qGetProp(ucs4)->joining) {
case QChar::Joining_Causing: return QChar::Center;
case QChar::Joining_Dual: return QChar::Dual;
case QChar::Joining_Right: return QChar::Right;
default: break;
} }
return QChar::OtherJoining;
}
#endif
/*! /*!
\fn bool QChar::hasMirrored() const \fn bool QChar::hasMirrored() const

View File

@ -288,10 +288,21 @@ public:
Fraction Fraction
}; };
enum JoiningType {
Joining_None,
Joining_Causing,
Joining_Dual,
Joining_Right,
Joining_Left,
Joining_Transparent
};
#if QT_DEPRECATED_SINCE(5, 3)
enum Joining enum Joining
{ {
OtherJoining, Dual, Right, Center OtherJoining, Dual, Right, Center
}; };
#endif
enum CombiningClass enum CombiningClass
{ {
@ -340,7 +351,17 @@ public:
inline Category category() const { return QChar::category(ucs); } inline Category category() const { return QChar::category(ucs); }
inline Direction direction() const { return QChar::direction(ucs); } inline Direction direction() const { return QChar::direction(ucs); }
inline Joining joining() const { return QChar::joining(ucs); } inline JoiningType joiningType() const { return QChar::joiningType(ucs); }
#if QT_DEPRECATED_SINCE(5, 3)
QT_DEPRECATED inline Joining joining() const {
switch (QChar::joiningType(ucs)) {
case QChar::Joining_Causing: return QChar::Center;
case QChar::Joining_Dual: return QChar::Dual;
case QChar::Joining_Right: return QChar::Right;
default: return QChar::OtherJoining;
}
}
#endif
inline unsigned char combiningClass() const { return QChar::combiningClass(ucs); } inline unsigned char combiningClass() const { return QChar::combiningClass(ucs); }
inline QChar mirroredChar() const { return QChar::mirroredChar(ucs); } inline QChar mirroredChar() const { return QChar::mirroredChar(ucs); }
@ -427,7 +448,10 @@ public:
static Category QT_FASTCALL category(uint ucs4); static Category QT_FASTCALL category(uint ucs4);
static Direction QT_FASTCALL direction(uint ucs4); static Direction QT_FASTCALL direction(uint ucs4);
static Joining QT_FASTCALL joining(uint ucs4); static JoiningType QT_FASTCALL joiningType(uint ucs4);
#if QT_DEPRECATED_SINCE(5, 3)
QT_DEPRECATED static Joining QT_FASTCALL joining(uint ucs4);
#endif
static unsigned char QT_FASTCALL combiningClass(uint ucs4); static unsigned char QT_FASTCALL combiningClass(uint ucs4);
static uint QT_FASTCALL mirroredChar(uint ucs4); static uint QT_FASTCALL mirroredChar(uint ucs4);

View File

@ -908,7 +908,17 @@ public:
QChar::Category category() const { return QChar(*this).category(); } QChar::Category category() const { return QChar(*this).category(); }
QChar::Direction direction() const { return QChar(*this).direction(); } QChar::Direction direction() const { return QChar(*this).direction(); }
QChar::Joining joining() const { return QChar(*this).joining(); } QChar::JoiningType joiningType() const { return QChar(*this).joiningType(); }
#if QT_DEPRECATED_SINCE(5, 3)
QT_DEPRECATED QChar::Joining joining() const {
switch (QChar(*this).joiningType()) {
case QChar::Joining_Causing: return QChar::Center;
case QChar::Joining_Dual: return QChar::Dual;
case QChar::Joining_Right: return QChar::Right;
default: return QChar::OtherJoining;
}
}
#endif
bool hasMirrored() const { return QChar(*this).hasMirrored(); } bool hasMirrored() const { return QChar(*this).hasMirrored(); }
QChar mirroredChar() const { return QChar(*this).mirroredChar(); } QChar mirroredChar() const { return QChar(*this).mirroredChar(); }
QString decomposition() const { return QChar(*this).decomposition(); } QString decomposition() const { return QChar(*this).decomposition(); }

View File

@ -2537,8 +2537,8 @@ static inline bool nextCharJoins(const QString &string, int pos)
++pos; ++pos;
if (pos == string.length()) if (pos == string.length())
return false; return false;
// ### U+A872 has joining type L QChar::JoiningType joining = string.at(pos).joiningType();
return string.at(pos) == QChar(0xA872) || string.at(pos).joining() != QChar::OtherJoining; return joining != QChar::Joining_None && joining != QChar::Joining_Transparent;
} }
static inline bool prevCharJoins(const QString &string, int pos) static inline bool prevCharJoins(const QString &string, int pos)
@ -2547,8 +2547,8 @@ static inline bool prevCharJoins(const QString &string, int pos)
--pos; --pos;
if (pos == 0) if (pos == 0)
return false; return false;
QChar::Joining joining = string.at(pos - 1).joining(); QChar::JoiningType joining = string.at(pos - 1).joiningType();
return (joining == QChar::Dual || joining == QChar::Center); return joining == QChar::Joining_Dual || joining == QChar::Joining_Causing;
} }
static inline bool isRetainableControlCode(QChar c) static inline bool isRetainableControlCode(QChar c)

View File

@ -74,7 +74,7 @@ private slots:
void isSpaceSpecial(); void isSpaceSpecial();
void category(); void category();
void direction(); void direction();
void joining(); void joiningType();
void combiningClass(); void combiningClass();
void digitValue(); void digitValue();
void mirroredChar(); void mirroredChar();
@ -483,30 +483,32 @@ void tst_QChar::direction()
QVERIFY(QChar::direction(0x2FA17u) == QChar::DirL); QVERIFY(QChar::direction(0x2FA17u) == QChar::DirL);
} }
void tst_QChar::joining() void tst_QChar::joiningType()
{ {
QVERIFY(QChar('a').joining() == QChar::OtherJoining); QVERIFY(QChar('a').joiningType() == QChar::Joining_None);
QVERIFY(QChar('0').joining() == QChar::OtherJoining); QVERIFY(QChar('0').joiningType() == QChar::Joining_None);
QVERIFY(QChar((ushort)0x627).joining() == QChar::Right); QVERIFY(QChar((ushort)0x0627).joiningType() == QChar::Joining_Right);
QVERIFY(QChar((ushort)0x5d0).joining() == QChar::OtherJoining); QVERIFY(QChar((ushort)0x05d0).joiningType() == QChar::Joining_None);
QVERIFY(QChar((ushort)0x00ad).joiningType() == QChar::Joining_Transparent);
QVERIFY(QChar::joining((ushort)'a') == QChar::OtherJoining); QVERIFY(QChar::joiningType((ushort)'a') == QChar::Joining_None);
QVERIFY(QChar::joining((ushort)'0') == QChar::OtherJoining); QVERIFY(QChar::joiningType((ushort)'0') == QChar::Joining_None);
QVERIFY(QChar::joining((ushort)0x627) == QChar::Right); QVERIFY(QChar::joiningType((ushort)0x0627) == QChar::Joining_Right);
QVERIFY(QChar::joining((ushort)0x5d0) == QChar::OtherJoining); QVERIFY(QChar::joiningType((ushort)0x05d0) == QChar::Joining_None);
QVERIFY(QChar::joiningType((ushort)0x00ad) == QChar::Joining_Transparent);
QVERIFY(QChar::joining((uint)'a') == QChar::OtherJoining); QVERIFY(QChar::joiningType((uint)'a') == QChar::Joining_None);
QVERIFY(QChar::joining((uint)'0') == QChar::OtherJoining); QVERIFY(QChar::joiningType((uint)'0') == QChar::Joining_None);
QVERIFY(QChar::joining((uint)0x627) == QChar::Right); QVERIFY(QChar::joiningType((uint)0x0627) == QChar::Joining_Right);
QVERIFY(QChar::joining((uint)0x5d0) == QChar::OtherJoining); QVERIFY(QChar::joiningType((uint)0x05d0) == QChar::Joining_None);
QVERIFY(QChar::joiningType((uint)0x00ad) == QChar::Joining_Transparent);
QVERIFY(QChar::joining(0xE01DAu) == QChar::OtherJoining); QVERIFY(QChar::joiningType(0xE01DAu) == QChar::Joining_Transparent);
QVERIFY(QChar::joining(0xf0000u) == QChar::OtherJoining); QVERIFY(QChar::joiningType(0xf0000u) == QChar::Joining_None);
QVERIFY(QChar::joining(0xE0030u) == QChar::OtherJoining); QVERIFY(QChar::joiningType(0xE0030u) == QChar::Joining_Transparent);
QVERIFY(QChar::joining(0x2FA17u) == QChar::OtherJoining); QVERIFY(QChar::joiningType(0x2FA17u) == QChar::Joining_None);
// ### U+A872 has joining type L QVERIFY(QChar::joiningType((uint)0xA872) == QChar::Joining_Left);
QVERIFY(QChar::joining((uint)0xA872) == QChar::OtherJoining);
} }
void tst_QChar::combiningClass() void tst_QChar::combiningClass()

View File

@ -246,30 +246,30 @@ static void initDirectionMap()
} }
enum Joining { enum JoiningType {
Joining_None, Joining_None,
Joining_Left,
Joining_Causing, Joining_Causing,
Joining_Dual, Joining_Dual,
Joining_Right, Joining_Right,
Joining_Left,
Joining_Transparent Joining_Transparent
, Joining_Unassigned , Joining_Unassigned
}; };
static QHash<QByteArray, Joining> joining_map; static QHash<QByteArray, JoiningType> joining_map;
static void initJoiningMap() static void initJoiningMap()
{ {
struct JoiningList { struct JoiningList {
Joining joining; JoiningType joining;
const char *name; const char *name;
} joinings[] = { } joinings[] = {
{ Joining_None, "U" }, { Joining_None, "U" },
{ Joining_Left, "L" },
{ Joining_Causing, "C" }, { Joining_Causing, "C" },
{ Joining_Dual, "D" }, { Joining_Dual, "D" },
{ Joining_Right, "R" }, { Joining_Right, "R" },
{ Joining_Left, "L" },
{ Joining_Transparent, "T" }, { Joining_Transparent, "T" },
{ Joining_Unassigned, 0 } { Joining_Unassigned, 0 }
}; };
@ -719,8 +719,8 @@ static const char *property_string =
" ushort category : 8; /* 5 used */\n" " ushort category : 8; /* 5 used */\n"
" ushort direction : 8; /* 5 used */\n" " ushort direction : 8; /* 5 used */\n"
" ushort combiningClass : 8;\n" " ushort combiningClass : 8;\n"
" ushort joining : 2;\n" " ushort joining : 3;\n"
" signed short digitValue : 6; /* 5 used */\n" " signed short digitValue : 5; /* 5 used */\n"
" signed short mirrorDiff : 16;\n" " signed short mirrorDiff : 16;\n"
" signed short lowerCaseDiff : 16;\n" " signed short lowerCaseDiff : 16;\n"
" signed short upperCaseDiff : 16;\n" " signed short upperCaseDiff : 16;\n"
@ -792,7 +792,7 @@ struct PropertyFlags {
QChar::Category category : 5; QChar::Category category : 5;
QChar::Direction direction : 5; QChar::Direction direction : 5;
// from ArabicShaping.txt // from ArabicShaping.txt
QChar::Joining joining : 2; QChar::JoiningType joining : 3;
// from DerivedAge.txt // from DerivedAge.txt
QChar::UnicodeVersion age : 4; QChar::UnicodeVersion age : 4;
int digitValue; int digitValue;
@ -944,7 +944,7 @@ struct UnicodeData {
mirroredChar = 0; mirroredChar = 0;
decompositionType = QChar::NoDecomposition; decompositionType = QChar::NoDecomposition;
p.joining = QChar::OtherJoining; p.joining = QChar::Joining_None;
p.age = QChar::Unicode_Unassigned; p.age = QChar::Unicode_Unassigned;
p.mirrorDiff = 0; p.mirrorDiff = 0;
p.digitValue = -1; p.digitValue = -1;
@ -1171,7 +1171,7 @@ static void readUnicodeData()
if (d[0].contains('<')) { if (d[0].contains('<')) {
data.decompositionType = decompositionMap.value(d[0], QChar::NoDecomposition); data.decompositionType = decompositionMap.value(d[0], QChar::NoDecomposition);
if (data.decompositionType == QChar::NoDecomposition) if (data.decompositionType == QChar::NoDecomposition)
qFatal("unassigned decomposition type: %s", d[0].constData()); qFatal("unhandled decomposition type: %s", d[0].constData());
d.takeFirst(); d.takeFirst();
} else { } else {
data.decompositionType = QChar::Canonical; data.decompositionType = QChar::Canonical;
@ -1261,24 +1261,34 @@ static void readArabicShaping()
int codepoint = l[0].toInt(&ok, 16); int codepoint = l[0].toInt(&ok, 16);
Q_ASSERT(ok); Q_ASSERT(ok);
Joining joining = joining_map.value(l[2].trimmed(), Joining_Unassigned); UnicodeData &d = UnicodeData::valueRef(codepoint);
if (joining == Joining_Unassigned) JoiningType joining = joining_map.value(l[2].trimmed(), Joining_Unassigned);
qFatal("unassigned or unhandled joining value: %s", l[2].constData()); switch (joining) {
case Joining_Unassigned:
qFatal("%x: unassigned or unhandled joining type: %s", codepoint, l[2].constData());
break;
case Joining_Transparent:
if (d.p.category != QChar::Mark_NonSpacing && d.p.category != QChar::Mark_Enclosing && d.p.category != QChar::Other_Format) {
qFatal("%x: joining type '%s' was met; the current implementation needs to be revised!",
codepoint, l[2].constData());
}
// fall through
if (joining == Joining_Left) { default:
qWarning("ACHTUNG!!! joining type '%s' has been met for U+%X; the current implementation needs to be revised!", d.p.joining = QChar::JoiningType(joining);
l[2].trimmed().constData(), codepoint); break;
}
} }
// Code points that are not explicitly listed in ArabicShaping.txt are either of joining type T or U:
// - Those that not explicitly listed that are of General Category Mn, Me, or Cf have joining type T.
// - All others not explicitly listed have joining type U.
for (int codepoint = 0; codepoint <= QChar::LastValidCodePoint; ++codepoint) {
UnicodeData &d = UnicodeData::valueRef(codepoint); UnicodeData &d = UnicodeData::valueRef(codepoint);
if (joining == Joining_Right) if (d.p.joining == QChar::Joining_None) {
d.p.joining = QChar::Right; if (d.p.category == QChar::Mark_NonSpacing || d.p.category == QChar::Mark_Enclosing || d.p.category == QChar::Other_Format)
else if (joining == Joining_Dual) d.p.joining = QChar::Joining_Transparent;
d.p.joining = QChar::Dual; }
else if (joining == Joining_Causing)
d.p.joining = QChar::Center;
else
d.p.joining = QChar::OtherJoining;
} }
} }
@ -2332,10 +2342,10 @@ static QByteArray createPropertyInfo()
// " ushort combiningClass : 8;\n" // " ushort combiningClass : 8;\n"
out += QByteArray::number( p.combiningClass ); out += QByteArray::number( p.combiningClass );
out += ", "; out += ", ";
// " ushort joining : 2;\n" // " ushort joining : 3;\n"
out += QByteArray::number( p.joining ); out += QByteArray::number( p.joining );
out += ", "; out += ", ";
// " signed short digitValue : 6; /* 5 used */\n" // " signed short digitValue : 5; /* 5 used */\n"
out += QByteArray::number( p.digitValue ); out += QByteArray::number( p.digitValue );
out += ", "; out += ", ";
// " signed short mirrorDiff : 16;\n" // " signed short mirrorDiff : 16;\n"