qt5base-lts/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp
Rohan McGovern af6c1a3298 test: skip some tst_qtextscriptengine tests when fonts are missing
This autotest may fail depending on the version of fonts which are
installed on the system.  It has no way to verify if the correct fonts
are installed, and it's unclear from where the correct version of the
fonts may be obtained.

Therefore, disable the test by default unless the user has indicated
that they have a correct setup by setting QT_HAVE_TEST_FONTS=1.

Task-number: QTBUG-20682
Change-Id: I24174520f54af6a9b2c13c9c1347f46555bce3d4
Reviewed-on: http://codereview.qt.nokia.com/2469
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
2011-08-02 09:01:18 +02:00

1305 lines
35 KiB
C++

/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifdef Q_WS_X11
#define private public
#endif
// cannot do private -> public on windows since it seems to mess up some stl headers
#include <qfont.h>
#ifdef Q_WS_X11
#undef private
#endif
#include <QtTest/QtTest>
#if defined(Q_WS_X11) || defined(Q_WS_MAC)
#define private public
#include <private/qtextengine_p.h>
#include <qtextlayout.h>
#undef private
#else
#include <private/qtextengine_p.h>
#include <qtextlayout.h>
#endif
#include <qfontdatabase.h>
#include <qfontinfo.h>
//TESTED_CLASS=
//TESTED_FILES= gui/text/qscriptengine.cpp
class tst_QTextScriptEngine : public QObject
{
Q_OBJECT
public:
tst_QTextScriptEngine();
virtual ~tst_QTextScriptEngine();
public slots:
void initTestCase();
void init();
void cleanup();
private slots:
void devanagari();
void bengali();
void gurmukhi();
// gujarati missing
void oriya();
void tamil();
void telugu();
void kannada();
void malayalam();
void sinhala();
void greek();
void khmer();
void linearB();
void controlInSyllable_qtbug14204();
void combiningMarks_qtbug15675();
void mirroredChars_data();
void mirroredChars();
private:
bool haveTestFonts;
};
tst_QTextScriptEngine::tst_QTextScriptEngine()
: haveTestFonts(qgetenv("QT_HAVE_TEST_FONTS") == QByteArray("1"))
{
}
tst_QTextScriptEngine::~tst_QTextScriptEngine()
{
}
void tst_QTextScriptEngine::initTestCase()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
qWarning(
"Some of these tests depend on the internals of some test fonts which are not freely "
"distributable.\n"
"These tests will be skipped.\n"
"If you have the fonts available, set QT_HAVE_TEST_FONTS=1 in your environment and "
"run the test again."
);
}
#endif
}
void tst_QTextScriptEngine::init()
{
}
void tst_QTextScriptEngine::cleanup()
{
}
struct ShapeTable {
unsigned short unicode[16];
unsigned short glyphs[16];
};
#if defined(Q_WS_X11)
static bool shaping( const QFont &f, const ShapeTable *s)
{
QString str = QString::fromUtf16( s->unicode );
QTextLayout layout(str, f);
QTextEngine *e = layout.d;
e->itemize();
e->shape(0);
int nglyphs = 0;
const unsigned short *g = s->glyphs;
while ( *g ) {
nglyphs++;
g++;
}
if( nglyphs != e->layoutData->items[0].num_glyphs )
goto error;
for (int i = 0; i < nglyphs; ++i) {
if ((e->layoutData->glyphLayout.glyphs[i] & 0xffffff) != s->glyphs[i])
goto error;
}
return true;
error:
str = "";
const unsigned short *uc = s->unicode;
while (*uc) {
str += QString("%1 ").arg(*uc, 4, 16);
++uc;
}
qDebug("%s: shaping of string %s failed, nglyphs=%d, expected %d",
f.family().toLatin1().constData(),
str.toLatin1().constData(),
e->layoutData->items[0].num_glyphs, nglyphs);
str = "";
int i = 0;
while (i < e->layoutData->items[0].num_glyphs) {
str += QString("%1 ").arg(e->layoutData->glyphLayout.glyphs[i], 4, 16);
++i;
}
qDebug(" glyph result = %s", str.toLatin1().constData());
return false;
}
#endif
void tst_QTextScriptEngine::devanagari()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Devanagari).contains("Raghindi")) {
QFont f("Raghindi");
const ShapeTable shape_table [] = {
// Ka
{ { 0x0915, 0x0 },
{ 0x0080, 0x0 } },
// Ka Halant
{ { 0x0915, 0x094d, 0x0 },
{ 0x0080, 0x0051, 0x0 } },
// Ka Halant Ka
{ { 0x0915, 0x094d, 0x0915, 0x0 },
{ 0x00c8, 0x0080, 0x0 } },
// Ka MatraI
{ { 0x0915, 0x093f, 0x0 },
{ 0x01d1, 0x0080, 0x0 } },
// Ra Halant Ka
{ { 0x0930, 0x094d, 0x0915, 0x0 },
{ 0x0080, 0x005b, 0x0 } },
// Ra Halant Ka MatraI
{ { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
{ 0x01d1, 0x0080, 0x005b, 0x0 } },
// MatraI
{ { 0x093f, 0x0 },
{ 0x01d4, 0x029c, 0x0 } },
// Ka Nukta
{ { 0x0915, 0x093c, 0x0 },
{ 0x00a4, 0x0 } },
// Ka Halant Ra
{ { 0x0915, 0x094d, 0x0930, 0x0 },
{ 0x0110, 0x0 } },
// Ka Halant Ra Halant Ka
{ { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
{ 0x0158, 0x0080, 0x0 } },
{ { 0x0930, 0x094d, 0x200d, 0x0 },
{ 0x00e2, 0x0 } },
{ { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0x0 },
{ 0x0158, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Raghindi", SkipAll);
}
}
{
if (QFontDatabase().families(QFontDatabase::Devanagari).contains("Mangal")) {
QFont f("Mangal");
const ShapeTable shape_table [] = {
// Ka
{ { 0x0915, 0x0 },
{ 0x0080, 0x0 } },
// Ka Halant
{ { 0x0915, 0x094d, 0x0 },
{ 0x0080, 0x0051, 0x0 } },
// Ka Halant Ka
{ { 0x0915, 0x094d, 0x0915, 0x0 },
{ 0x00c8, 0x0080, 0x0 } },
// Ka MatraI
{ { 0x0915, 0x093f, 0x0 },
{ 0x01d1, 0x0080, 0x0 } },
// Ra Halant Ka
{ { 0x0930, 0x094d, 0x0915, 0x0 },
{ 0x0080, 0x005b, 0x0 } },
// Ra Halant Ka MatraI
{ { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
{ 0x01d1, 0x0080, 0x005b, 0x0 } },
// MatraI
{ { 0x093f, 0x0 },
{ 0x01d4, 0x029c, 0x0 } },
// Ka Nukta
{ { 0x0915, 0x093c, 0x0 },
{ 0x00a4, 0x0 } },
// Ka Halant Ra
{ { 0x0915, 0x094d, 0x0930, 0x0 },
{ 0x0110, 0x0 } },
// Ka Halant Ra Halant Ka
{ { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
{ 0x0158, 0x0080, 0x0 } },
{ { 0x92b, 0x94d, 0x930, 0x0 },
{ 0x125, 0x0 } },
{ { 0x92b, 0x93c, 0x94d, 0x930, 0x0 },
{ 0x149, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find mangal", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::bengali()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Bengali).contains("Akaash")) {
QFont f("Akaash");
const ShapeTable shape_table [] = {
// Ka
{ { 0x0995, 0x0 },
{ 0x0151, 0x0 } },
// Ka Halant
{ { 0x0995, 0x09cd, 0x0 },
{ 0x0151, 0x017d, 0x0 } },
// Ka Halant Ka
{ { 0x0995, 0x09cd, 0x0995, 0x0 },
{ 0x019b, 0x0 } },
// Ka MatraI
{ { 0x0995, 0x09bf, 0x0 },
{ 0x0173, 0x0151, 0x0 } },
// Ra Halant Ka
{ { 0x09b0, 0x09cd, 0x0995, 0x0 },
{ 0x0151, 0x0276, 0x0 } },
// Ra Halant Ka MatraI
{ { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
{ 0x0173, 0x0151, 0x0276, 0x0 } },
// Ka Nukta
{ { 0x0995, 0x09bc, 0x0 },
{ 0x0151, 0x0171, 0x0 } },
// Ka Halant Ra
{ { 0x0995, 0x09cd, 0x09b0, 0x0 },
{ 0x01f4, 0x0 } },
// Ka Halant Ra Halant Ka
{ { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0x0 },
{ 0x025c, 0x0276, 0x0151, 0x0 } },
// Ya + Halant
{ { 0x09af, 0x09cd, 0x0 },
{ 0x016a, 0x017d, 0x0 } },
// Da Halant Ya -> Da Ya-Phala
{ { 0x09a6, 0x09cd, 0x09af, 0x0 },
{ 0x01e5, 0x0 } },
// A Halant Ya -> A Ya-phala
{ { 0x0985, 0x09cd, 0x09af, 0x0 },
{ 0x0145, 0x01cf, 0x0 } },
// Na Halant Ka
{ { 0x09a8, 0x09cd, 0x0995, 0x0 },
{ 0x026f, 0x0151, 0x0 } },
// Na Halant ZWNJ Ka
{ { 0x09a8, 0x09cd, 0x200c, 0x0995, 0x0 },
{ 0x0164, 0x017d, 0x0151, 0x0 } },
// Na Halant ZWJ Ka
{ { 0x09a8, 0x09cd, 0x200d, 0x0995, 0x0 },
{ 0x026f, 0x0151, 0x0 } },
// Ka Halant ZWNJ Ka
{ { 0x0995, 0x09cd, 0x200c, 0x0995, 0x0 },
{ 0x0151, 0x017d, 0x0151, 0x0 } },
// Ka Halant ZWJ Ka
{ { 0x0995, 0x09cd, 0x200d, 0x0995, 0x0 },
{ 0x025c, 0x0151, 0x0 } },
// Na Halant Ra
{ { 0x09a8, 0x09cd, 0x09b0, 0x0 },
{ 0x0207, 0x0 } },
// Na Halant ZWNJ Ra
{ { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
{ 0x0164, 0x017d, 0x016b, 0x0 } },
// Na Halant ZWJ Ra
{ { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0x0 },
{ 0x026f, 0x016b, 0x0 } },
// Na Halant Ba
{ { 0x09a8, 0x09cd, 0x09ac, 0x0 },
{ 0x022f, 0x0 } },
// Na Halant ZWNJ Ba
{ { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0x0 },
{ 0x0164, 0x017d, 0x0167, 0x0 } },
// Na Halant ZWJ Ba
{ { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0x0 },
{ 0x026f, 0x0167, 0x0 } },
// Na Halant Dha
{ { 0x09a8, 0x09cd, 0x09a7, 0x0 },
{ 0x01d3, 0x0 } },
// Na Halant ZWNJ Dha
{ { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
{ 0x0164, 0x017d, 0x0163, 0x0 } },
// Na Halant ZWJ Dha
{ { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
{ 0x026f, 0x0163, 0x0 } },
// Ra Halant Ka MatraAU
{ { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0x0 },
{ 0x0179, 0x0151, 0x0276, 0x017e, 0x0 } },
// Ra Halant Ba Halant Ba
{ { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
{ 0x0232, 0x0276, 0x0 } },
{ { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0x0 },
{ 0x151, 0x276, 0x172, 0x143, 0x0 } },
{ { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0x0 },
{ 0x151, 0x276, 0x172, 0x144, 0x0 } },
// test decomposed two parts matras
{ { 0x995, 0x9c7, 0x9be, 0x0 },
{ 0x179, 0x151, 0x172, 0x0 } },
{ { 0x995, 0x9c7, 0x9d7, 0x0 },
{ 0x179, 0x151, 0x17e, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Akaash", SkipAll);
}
}
{
if (QFontDatabase().families(QFontDatabase::Bengali).contains("Mukti Narrow")) {
QFont f("Mukti Narrow");
const ShapeTable shape_table [] = {
// Ka
{ { 0x0995, 0x0 },
{ 0x0073, 0x0 } },
// Ka Halant
{ { 0x0995, 0x09cd, 0x0 },
{ 0x00b9, 0x0 } },
// Ka Halant Ka
{ { 0x0995, 0x09cd, 0x0995, 0x0 },
{ 0x0109, 0x0 } },
// Ka MatraI
{ { 0x0995, 0x09bf, 0x0 },
{ 0x0095, 0x0073, 0x0 } },
// Ra Halant Ka
{ { 0x09b0, 0x09cd, 0x0995, 0x0 },
{ 0x0073, 0x00e1, 0x0 } },
// Ra Halant Ka MatraI
{ { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
{ 0x0095, 0x0073, 0x00e1, 0x0 } },
// MatraI
{ { 0x09bf, 0x0 },
{ 0x0095, 0x01c8, 0x0 } },
// Ka Nukta
{ { 0x0995, 0x09bc, 0x0 },
{ 0x0073, 0x0093, 0x0 } },
// Ka Halant Ra
{ { 0x0995, 0x09cd, 0x09b0, 0x0 },
{ 0x00e5, 0x0 } },
// Ka Halant Ra Halant Ka
{ { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0x0 },
{ 0x234, 0x24e, 0x73, 0x0 } },
// Ya + Halant
{ { 0x09af, 0x09cd, 0x0 },
{ 0x00d2, 0x0 } },
// Da Halant Ya -> Da Ya-Phala
{ { 0x09a6, 0x09cd, 0x09af, 0x0 },
{ 0x0084, 0x00e2, 0x0 } },
// A Halant Ya -> A Ya-phala
{ { 0x0985, 0x09cd, 0x09af, 0x0 },
{ 0x0067, 0x00e2, 0x0 } },
// Na Halant Ka
{ { 0x09a8, 0x09cd, 0x0995, 0x0 },
{ 0x0188, 0x0 } },
// Na Halant ZWNJ Ka
{ { 0x9a8, 0x9cd, 0x200c, 0x995, 0x0 },
{ 0xcc, 0x73, 0x0 } },
// Na Halant ZWJ Ka
{ { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
{ 0x247, 0x73, 0x0 } },
// Ka Halant ZWNJ Ka
{ { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
{ 0x247, 0x73, 0x0 } },
// Ka Halant ZWJ Ka
{ { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
{ 0x247, 0x73, 0x0 } },
// Na Halant Ra
{ { 0x09a8, 0x09cd, 0x09b0, 0x0 },
{ 0x00f8, 0x0 } },
// Na Halant ZWNJ Ra
{ { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
{ 0xcc, 0x8d, 0x0 } },
// Na Halant ZWJ Ra
{ { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0x0 },
{ 0x247, 0x8d, 0x0 } },
// Na Halant Ba
{ { 0x09a8, 0x09cd, 0x09ac, 0x0 },
{ 0x0139, 0x0 } },
// Na Halant ZWNJ Ba
{ { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0x0 },
{ 0xcc, 0x89, 0x0 } },
// Na Halant ZWJ Ba
{ { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0x0 },
{ 0x247, 0x89, 0x0 } },
// Na Halant Dha
{ { 0x09a8, 0x09cd, 0x09a7, 0x0 },
{ 0x0145, 0x0 } },
// Na Halant ZWNJ Dha
{ { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
{ 0xcc, 0x85, 0x0 } },
// Na Halant ZWJ Dha
{ { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
{ 0x247, 0x85, 0x0 } },
// Ra Halant Ka MatraAU
{ { 0x9b0, 0x9cd, 0x995, 0x9cc, 0x0 },
{ 0x232, 0x73, 0xe1, 0xa0, 0x0 } },
// Ra Halant Ba Halant Ba
{ { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
{ 0x013b, 0x00e1, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Mukti", SkipAll);
}
}
{
if (QFontDatabase().families(QFontDatabase::Bengali).contains("Likhan")) {
QFont f("Likhan");
const ShapeTable shape_table [] = {
{ { 0x9a8, 0x9cd, 0x9af, 0x0 },
{ 0x1ca, 0x0 } },
{ { 0x09b8, 0x09cd, 0x09af, 0x0 },
{ 0x020e, 0x0 } },
{ { 0x09b6, 0x09cd, 0x09af, 0x0 },
{ 0x01f4, 0x0 } },
{ { 0x09b7, 0x09cd, 0x09af, 0x0 },
{ 0x01fe, 0x0 } },
{ { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 },
{ 0x10b, 0x167, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Likhan", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::gurmukhi()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Gurmukhi).contains("Lohit Punjabi")) {
QFont f("Lohit Punjabi");
const ShapeTable shape_table [] = {
{ { 0xA15, 0xA4D, 0xa39, 0x0 },
{ 0x3b, 0x8b, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Lohit Punjabi", SkipAll);
}
}
#endif
}
void tst_QTextScriptEngine::oriya()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Oriya).contains("utkal")) {
QFont f("utkal");
const ShapeTable shape_table [] = {
{ { 0xb15, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
{ 0x150, 0x125, 0x0 } },
{ { 0xb24, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
{ 0x151, 0x120, 0x0 } },
{ { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
{ 0x152, 0x120, 0x0 } },
{ { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
{ 0x152, 0x120, 0x0 } },
{ { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
{ 0x176, 0x0 } },
{ { 0xb38, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
{ 0x177, 0x0 } },
{ { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0xb4d, 0xb2f, 0x0 },
{ 0x176, 0x124, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find utkal", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::tamil()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Tamil).contains("AkrutiTml1")) {
QFont f("AkrutiTml1");
const ShapeTable shape_table [] = {
{ { 0x0b95, 0x0bc2, 0x0 },
{ 0x004e, 0x0 } },
{ { 0x0bae, 0x0bc2, 0x0 },
{ 0x009e, 0x0 } },
{ { 0x0b9a, 0x0bc2, 0x0 },
{ 0x0058, 0x0 } },
{ { 0x0b99, 0x0bc2, 0x0 },
{ 0x0053, 0x0 } },
{ { 0x0bb0, 0x0bc2, 0x0 },
{ 0x00a8, 0x0 } },
{ { 0x0ba4, 0x0bc2, 0x0 },
{ 0x008e, 0x0 } },
{ { 0x0b9f, 0x0bc2, 0x0 },
{ 0x0062, 0x0 } },
{ { 0x0b95, 0x0bc6, 0x0 },
{ 0x000a, 0x0031, 0x0 } },
{ { 0x0b95, 0x0bca, 0x0 },
{ 0x000a, 0x0031, 0x0007, 0x0 } },
{ { 0x0b95, 0x0bc6, 0x0bbe, 0x0 },
{ 0x000a, 0x0031, 0x007, 0x0 } },
{ { 0x0b95, 0x0bcd, 0x0bb7, 0x0 },
{ 0x0049, 0x0 } },
{ { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0x0 },
{ 0x000a, 0x0049, 0x007, 0x0 } },
{ { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0x0 },
{ 0x000a, 0x0049, 0x007, 0x0 } },
{ { 0x0b9f, 0x0bbf, 0x0 },
{ 0x005f, 0x0 } },
{ { 0x0b9f, 0x0bc0, 0x0 },
{ 0x0060, 0x0 } },
{ { 0x0bb2, 0x0bc0, 0x0 },
{ 0x00ab, 0x0 } },
{ { 0x0bb2, 0x0bbf, 0x0 },
{ 0x00aa, 0x0 } },
{ { 0x0bb0, 0x0bcd, 0x0 },
{ 0x00a4, 0x0 } },
{ { 0x0bb0, 0x0bbf, 0x0 },
{ 0x00a5, 0x0 } },
{ { 0x0bb0, 0x0bc0, 0x0 },
{ 0x00a6, 0x0 } },
{ { 0x0b83, 0x0 },
{ 0x0025, 0x0 } },
{ { 0x0b83, 0x0b95, 0x0 },
{ 0x0025, 0x0031, 0x0 } },
{ { 0xb95, 0xbc6, 0xbbe, 0x0 },
{ 0xa, 0x31, 0x7, 0x0 } },
{ { 0xb95, 0xbc7, 0xbbe, 0x0 },
{ 0xb, 0x31, 0x7, 0x0 } },
{ { 0xb95, 0xbc6, 0xbd7, 0x0 },
{ 0xa, 0x31, 0x40, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find AkrutiTml1", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::telugu()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Telugu).contains("Pothana2000")) {
QFont f("Pothana2000");
const ShapeTable shape_table [] = {
{ { 0xc15, 0xc4d, 0x0 },
{ 0xbb, 0x0 } },
{ { 0xc15, 0xc4d, 0xc37, 0x0 },
{ 0x4b, 0x0 } },
{ { 0xc15, 0xc4d, 0xc37, 0xc4d, 0x0 },
{ 0xe0, 0x0 } },
{ { 0xc15, 0xc4d, 0xc37, 0xc4d, 0xc23, 0x0 },
{ 0x4b, 0x91, 0x0 } },
{ { 0xc15, 0xc4d, 0xc30, 0x0 },
{ 0x5a, 0xb2, 0x0 } },
{ { 0xc15, 0xc4d, 0xc30, 0xc4d, 0x0 },
{ 0xbb, 0xb2, 0x0 } },
{ { 0xc15, 0xc4d, 0xc30, 0xc4d, 0xc15, 0x0 },
{ 0x5a, 0xb2, 0x83, 0x0 } },
{ { 0xc15, 0xc4d, 0xc30, 0xc3f, 0x0 },
{ 0xe2, 0xb2, 0x0 } },
{ { 0xc15, 0xc4d, 0xc15, 0xc48, 0x0 },
{ 0xe6, 0xb3, 0x83, 0x0 } },
{ { 0xc15, 0xc4d, 0xc30, 0xc48, 0x0 },
{ 0xe6, 0xb3, 0x9f, 0x0 } },
{ { 0xc15, 0xc46, 0xc56, 0x0 },
{ 0xe6, 0xb3, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Pothana2000", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::kannada()
{
#if defined(Q_WS_X11)
{
if (QFontDatabase().families(QFontDatabase::Kannada).contains("Sampige")) {
QFont f("Sampige");
const ShapeTable shape_table [] = {
{ { 0x0ca8, 0x0ccd, 0x0ca8, 0x0 },
{ 0x0049, 0x00ba, 0x0 } },
{ { 0x0ca8, 0x0ccd, 0x0ca1, 0x0 },
{ 0x0049, 0x00b3, 0x0 } },
{ { 0x0caf, 0x0cc2, 0x0 },
{ 0x004f, 0x005d, 0x0 } },
{ { 0x0ce0, 0x0 },
{ 0x006a, 0x0 } },
{ { 0x0ce6, 0x0ce7, 0x0ce8, 0x0 },
{ 0x006b, 0x006c, 0x006d, 0x0 } },
{ { 0x0cb5, 0x0ccb, 0x0 },
{ 0x015f, 0x0067, 0x0 } },
{ { 0x0cb0, 0x0ccd, 0x0cae, 0x0 },
{ 0x004e, 0x0082, 0x0 } },
{ { 0x0cb0, 0x0ccd, 0x0c95, 0x0 },
{ 0x0036, 0x0082, 0x0 } },
{ { 0x0c95, 0x0ccd, 0x0cb0, 0x0 },
{ 0x0036, 0x00c1, 0x0 } },
{ { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 },
{ 0x0050, 0x00a7, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Sampige", SkipAll);
}
}
{
if (QFontDatabase().families(QFontDatabase::Kannada).contains("Tunga")) {
QFont f("Tunga");
const ShapeTable shape_table [] = {
{ { 0x0cb7, 0x0cc6, 0x0 },
{ 0x00b0, 0x006c, 0x0 } },
{ { 0x0cb7, 0x0ccd, 0x0 },
{ 0x0163, 0x0 } },
{ { 0xc95, 0xcbf, 0xcd5, 0x0 },
{ 0x114, 0x73, 0x0 } },
{ { 0xc95, 0xcc6, 0xcd5, 0x0 },
{ 0x90, 0x6c, 0x73, 0x0 } },
{ { 0xc95, 0xcc6, 0xcd6, 0x0 },
{ 0x90, 0x6c, 0x74, 0x0 } },
{ { 0xc95, 0xcc6, 0xcc2, 0x0 },
{ 0x90, 0x6c, 0x69, 0x0 } },
{ { 0xc95, 0xcca, 0xcd5, 0x0 },
{ 0x90, 0x6c, 0x69, 0x73, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Tunga", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::malayalam()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Malayalam).contains("AkrutiMal2")) {
QFont f("AkrutiMal2");
const ShapeTable shape_table [] = {
{ { 0x0d15, 0x0d46, 0x0 },
{ 0x005e, 0x0034, 0x0 } },
{ { 0x0d15, 0x0d47, 0x0 },
{ 0x005f, 0x0034, 0x0 } },
{ { 0x0d15, 0x0d4b, 0x0 },
{ 0x005f, 0x0034, 0x0058, 0x0 } },
{ { 0x0d15, 0x0d48, 0x0 },
{ 0x0060, 0x0034, 0x0 } },
{ { 0x0d15, 0x0d4a, 0x0 },
{ 0x005e, 0x0034, 0x0058, 0x0 } },
{ { 0x0d30, 0x0d4d, 0x0d15, 0x0 },
{ 0x009e, 0x0034, 0x0 } },
{ { 0x0d15, 0x0d4d, 0x0d35, 0x0 },
{ 0x0034, 0x007a, 0x0 } },
{ { 0x0d15, 0x0d4d, 0x0d2f, 0x0 },
{ 0x0034, 0x00a2, 0x0 } },
{ { 0x0d1f, 0x0d4d, 0x0d1f, 0x0 },
{ 0x0069, 0x0 } },
{ { 0x0d26, 0x0d4d, 0x0d26, 0x0 },
{ 0x0074, 0x0 } },
{ { 0x0d30, 0x0d4d, 0x0 },
{ 0x009e, 0x0 } },
{ { 0x0d30, 0x0d4d, 0x200c, 0x0 },
{ 0x009e, 0x0 } },
{ { 0x0d30, 0x0d4d, 0x200d, 0x0 },
{ 0x009e, 0x0 } },
{ { 0xd15, 0xd46, 0xd3e, 0x0 },
{ 0x5e, 0x34, 0x58, 0x0 } },
{ { 0xd15, 0xd47, 0xd3e, 0x0 },
{ 0x5f, 0x34, 0x58, 0x0 } },
{ { 0xd15, 0xd46, 0xd57, 0x0 },
{ 0x5e, 0x34, 0x65, 0x0 } },
{ { 0xd15, 0xd57, 0x0 },
{ 0x34, 0x65, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find AkrutiMal2", SkipAll);
}
}
{
if (QFontDatabase().families(QFontDatabase::Malayalam).contains("Rachana")) {
QFont f("Rachana");
const ShapeTable shape_table [] = {
{ { 0xd37, 0xd4d, 0xd1f, 0xd4d, 0xd30, 0xd40, 0x0 },
{ 0x385, 0xa3, 0x0 } },
{ { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 },
{ 0x2ff, 0x0 } },
{ { 0xd33, 0xd4d, 0xd33, 0x0 },
{ 0x3f8, 0x0 } },
{ { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 },
{ 0x2ff, 0x0 } },
{ { 0xd30, 0xd4d, 0x200d, 0xd35, 0xd4d, 0xd35, 0x0 },
{ 0xf3, 0x350, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Rachana", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::sinhala()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Sinhala).contains("Malithi Web")) {
QFont f("Malithi Web");
const ShapeTable shape_table [] = {
{ { 0xd9a, 0xdd9, 0xdcf, 0x0 },
{ 0x4a, 0x61, 0x42, 0x0 } },
{ { 0xd9a, 0xdd9, 0xddf, 0x0 },
{ 0x4a, 0x61, 0x50, 0x0 } },
{ { 0xd9a, 0xdd9, 0xdca, 0x0 },
{ 0x4a, 0x62, 0x0 } },
{ { 0xd9a, 0xddc, 0xdca, 0x0 },
{ 0x4a, 0x61, 0x42, 0x41, 0x0 } },
{ { 0xd9a, 0xdda, 0x0 },
{ 0x4a, 0x62, 0x0 } },
{ { 0xd9a, 0xddd, 0x0 },
{ 0x4a, 0x61, 0x42, 0x41, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Malithi Web", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::khmer()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Khmer).contains("Khmer OS")) {
QFont f("Khmer OS");
const ShapeTable shape_table [] = {
{ { 0x179a, 0x17cd, 0x0 },
{ 0x24c, 0x27f, 0x0 } },
{ { 0x179f, 0x17c5, 0x0 },
{ 0x273, 0x203, 0x0 } },
{ { 0x1790, 0x17d2, 0x1784, 0x17c3, 0x0 },
{ 0x275, 0x242, 0x182, 0x0 } },
{ { 0x179a, 0x0 },
{ 0x24c, 0x0 } },
{ { 0x1781, 0x17d2, 0x1798, 0x17c2, 0x0 },
{ 0x274, 0x233, 0x197, 0x0 } },
{ { 0x1798, 0x17b6, 0x0 },
{ 0x1cb, 0x0 } },
{ { 0x179a, 0x17b8, 0x0 },
{ 0x24c, 0x26a, 0x0 } },
{ { 0x1787, 0x17b6, 0x0 },
{ 0x1ba, 0x0 } },
{ { 0x1798, 0x17d2, 0x1796, 0x17bb, 0x0 },
{ 0x24a, 0x195, 0x26d, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Khmer OS", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::linearB()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Any).contains("Penuturesu")) {
QFont f("Penuturesu");
const ShapeTable shape_table [] = {
{ { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03, 0 },
{ 0x5, 0x6, 0x7, 0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find Penuturesu", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
#if defined(Q_WS_X11)
static bool decomposedShaping( const QFont &f, const QChar &ch)
{
QString str = QString().append(ch);
QTextLayout layout(str, f);
QTextEngine *e = layout.d;
e->itemize();
e->shape(0);
QTextLayout decomposed(str.normalized(QString::NormalizationForm_D), f);
QTextEngine *de = decomposed.d;
de->itemize();
de->shape(0);
if( e->layoutData->items[0].num_glyphs != de->layoutData->items[0].num_glyphs )
goto error;
for (int i = 0; i < e->layoutData->items[0].num_glyphs; ++i) {
if ((e->layoutData->glyphLayout.glyphs[i] & 0xffffff) != (de->layoutData->glyphLayout.glyphs[i] & 0xffffff))
goto error;
}
return true;
error:
qDebug("%s: decomposedShaping of char %4x failed, nglyphs=%d, decomposed nglyphs %d",
f.family().toLatin1().constData(),
ch.unicode(),
e->layoutData->items[0].num_glyphs,
de->layoutData->items[0].num_glyphs);
str = "";
int i = 0;
while (i < e->layoutData->items[0].num_glyphs) {
str += QString("%1 ").arg(e->layoutData->glyphLayout.glyphs[i], 4, 16);
++i;
}
qDebug(" composed glyph result = %s", str.toLatin1().constData());
str = "";
i = 0;
while (i < de->layoutData->items[0].num_glyphs) {
str += QString("%1 ").arg(de->layoutData->glyphLayout.glyphs[i], 4, 16);
++i;
}
qDebug(" decomposed glyph result = %s", str.toLatin1().constData());
return false;
}
#endif
void tst_QTextScriptEngine::greek()
{
#if defined(Q_WS_X11)
if (!haveTestFonts) {
QSKIP("Test fonts are not available", SkipAll);
}
{
if (QFontDatabase().families(QFontDatabase::Any).contains("DejaVu Sans")) {
QFont f("DejaVu Sans");
for (int uc = 0x1f00; uc <= 0x1fff; ++uc) {
QString str;
str.append(uc);
if (str.normalized(QString::NormalizationForm_D).normalized(QString::NormalizationForm_C) != str) {
//qDebug() << "skipping" << hex << uc;
continue;
}
if (uc == 0x1fc1 || uc == 0x1fed)
continue;
QVERIFY( decomposedShaping(f, QChar(uc)) );
}
} else {
QSKIP("couldn't find DejaVu Sans", SkipAll);
}
}
{
if (QFontDatabase().families(QFontDatabase::Any).contains("SBL Greek")) {
QFont f("SBL Greek");
for (int uc = 0x1f00; uc <= 0x1fff; ++uc) {
QString str;
str.append(uc);
if (str.normalized(QString::NormalizationForm_D).normalized(QString::NormalizationForm_C) != str) {
//qDebug() << "skipping" << hex << uc;
continue;
}
if (uc == 0x1fc1 || uc == 0x1fed)
continue;
QVERIFY( decomposedShaping(f, QChar(uc) ) );
}
const ShapeTable shape_table [] = {
{ { 0x3b1, 0x300, 0x313, 0x0 },
{ 0xb8, 0x3d3, 0x3c7, 0x0 } },
{ { 0x3b1, 0x313, 0x300, 0x0 },
{ 0xd4, 0x0 } },
{ {0}, {0} }
};
const ShapeTable *s = shape_table;
while (s->unicode[0]) {
QVERIFY( shaping(f, s) );
++s;
}
} else {
QSKIP("couldn't find SBL_grk", SkipAll);
}
}
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::controlInSyllable_qtbug14204()
{
#if defined(Q_WS_X11)
QString s;
s.append(QChar(0x0915));
s.append(QChar(0x094d));
s.append(QChar(0x200d));
s.append(QChar(0x0915));
QTextLayout layout(s);
QTextEngine *e = layout.d;
e->itemize();
e->shape(0);
QVERIFY(e->layoutData->items[0].num_glyphs == 2);
QVERIFY(e->layoutData->glyphLayout.advances_x[1] != 0);
#else
QSKIP("X11 specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::combiningMarks_qtbug15675()
{
#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
QString s;
s.append(QChar(0x0061));
s.append(QChar(0x0062));
s.append(QChar(0x0300));
s.append(QChar(0x0063));
QFont font("Monaco");
QTextLayout layout(s, font);
QTextEngine *e = layout.d;
e->itemize();
e->shape(0);
QVERIFY(e->layoutData->items[0].num_glyphs == 4);
QVERIFY(e->layoutData->glyphLayout.advances_y[2] > 0);
#elif defined(Q_WS_X11)
QFontDatabase db;
if (!db.families().contains("DejaVu Sans Mono")) {
QSKIP("Required font (DejaVu Sans Mono) doesn't exist, skip test.", SkipAll);
return;
}
QString s;
s.append(QChar(0x0062));
s.append(QChar(0x0332));
s.append(QChar(0x0063));
QTextLayout layout(s, QFont("DejaVu Sans Mono"));
QTextEngine *e = layout.d;
e->itemize();
e->shape(0);
QVERIFY(e->layoutData->items[0].num_glyphs == 3);
QVERIFY(e->layoutData->glyphLayout.advances_x[1] == 0);
#else
QSKIP("X11/Mac specific test", SkipAll);
#endif
}
void tst_QTextScriptEngine::mirroredChars_data()
{
QTest::addColumn<int>("hintingPreference");
QTest::newRow("Default hinting") << int(QFont::PreferDefaultHinting);
QTest::newRow("No hinting") << int(QFont::PreferNoHinting);
QTest::newRow("Vertical hinting") << int(QFont::PreferVerticalHinting);
QTest::newRow("Full hinting") << int(QFont::PreferFullHinting);
}
void tst_QTextScriptEngine::mirroredChars()
{
#if defined(Q_WS_MAC)
QSKIP("Not supported on Mac", SkipAll);
#endif
QFETCH(int, hintingPreference);
QFont font;
font.setHintingPreference(QFont::HintingPreference(hintingPreference));
QString s;
s.append(QLatin1Char('('));
s.append(QLatin1Char(')'));
HB_Glyph leftParenthesis;
HB_Glyph rightParenthesis;
{
QTextLayout layout(s);
layout.beginLayout();
layout.createLine();
layout.endLayout();
QTextEngine *e = layout.engine();
e->itemize();
e->shape(0);
QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2));
const QGlyphLayout &glyphLayout = e->layoutData->glyphLayout;
leftParenthesis = glyphLayout.glyphs[0];
rightParenthesis = glyphLayout.glyphs[1];
}
{
QTextLayout layout(s);
layout.setFlags(Qt::TextForceRightToLeft);
QTextEngine *e = layout.engine();
e->itemize();
e->shape(0);
QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2));
const QGlyphLayout &glyphLayout = e->layoutData->glyphLayout;
QCOMPARE(glyphLayout.glyphs[0], rightParenthesis);
QCOMPARE(glyphLayout.glyphs[1], leftParenthesis);
}
}
QTEST_MAIN(tst_QTextScriptEngine)
#include "tst_qtextscriptengine.moc"