| Index: third_party/harfbuzz/tests/shaping/main.cpp
|
| diff --git a/third_party/harfbuzz/tests/shaping/main.cpp b/third_party/harfbuzz/tests/shaping/main.cpp
|
| index 1a3ef4f70550cdac34192cb9ed466301eaf950ae..28f8e07ea80264209616b7dce981349c078e0cfd 100644
|
| --- a/third_party/harfbuzz/tests/shaping/main.cpp
|
| +++ b/third_party/harfbuzz/tests/shaping/main.cpp
|
| @@ -136,13 +136,13 @@ HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32
|
| return HB_Err_Ok;
|
| }
|
|
|
| -void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
|
| +void hb_getGlyphMetrics(HB_Font, HB_Glyph, HB_GlyphMetrics *metrics)
|
| {
|
| // ###
|
| metrics->x = metrics->y = metrics->width = metrics->height = metrics->xOffset = metrics->yOffset = 0;
|
| }
|
|
|
| -HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
|
| +HB_Fixed hb_getFontMetric(HB_Font, HB_FontMetric )
|
| {
|
| return 0; // ####
|
| }
|
| @@ -169,6 +169,8 @@ public slots:
|
| void initTestCase();
|
| void cleanupTestCase();
|
| private slots:
|
| + void greek();
|
| +
|
| void devanagari();
|
| void bengali();
|
| void gurmukhi();
|
| @@ -178,9 +180,10 @@ private slots:
|
| void telugu();
|
| void kannada();
|
| void malayalam();
|
| - // sinhala missing
|
| + void sinhala();
|
|
|
| void khmer();
|
| + void nko();
|
| void linearB();
|
| };
|
|
|
| @@ -202,18 +205,25 @@ void tst_QScriptEngine::cleanupTestCase()
|
| FT_Done_FreeType(freetype);
|
| }
|
|
|
| -struct ShapeTable {
|
| - unsigned short unicode[16];
|
| - unsigned short glyphs[16];
|
| +class Shaper
|
| +{
|
| +public:
|
| + Shaper(FT_Face face, HB_Script script, const QString &str);
|
| +
|
| + HB_FontRec hbFont;
|
| + HB_ShaperItem shaper_item;
|
| + QVarLengthArray<HB_Glyph> hb_glyphs;
|
| + QVarLengthArray<HB_GlyphAttributes> hb_attributes;
|
| + QVarLengthArray<HB_Fixed> hb_advances;
|
| + QVarLengthArray<HB_FixedPoint> hb_offsets;
|
| + QVarLengthArray<unsigned short> hb_logClusters;
|
| +
|
| };
|
|
|
| -static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
|
| +Shaper::Shaper(FT_Face face, HB_Script script, const QString &str)
|
| {
|
| - QString str = QString::fromUtf16( s->unicode );
|
| -
|
| HB_Face hbFace = HB_NewFace(face, hb_getSFntTable);
|
|
|
| - HB_FontRec hbFont;
|
| hbFont.klass = &hb_fontClass;
|
| hbFont.userData = face;
|
| hbFont.x_ppem = face->size->metrics.x_ppem;
|
| @@ -221,7 +231,6 @@ static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
|
| hbFont.x_scale = face->size->metrics.x_scale;
|
| hbFont.y_scale = face->size->metrics.y_scale;
|
|
|
| - HB_ShaperItem shaper_item;
|
| shaper_item.kerning_applied = false;
|
| shaper_item.string = reinterpret_cast<const HB_UChar16 *>(str.constData());
|
| shaper_item.stringLength = str.length();
|
| @@ -236,11 +245,6 @@ static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
|
| shaper_item.glyphIndicesPresent = false;
|
| shaper_item.initialGlyphCount = 0;
|
|
|
| - QVarLengthArray<HB_Glyph> hb_glyphs(shaper_item.num_glyphs);
|
| - QVarLengthArray<HB_GlyphAttributes> hb_attributes(shaper_item.num_glyphs);
|
| - QVarLengthArray<HB_Fixed> hb_advances(shaper_item.num_glyphs);
|
| - QVarLengthArray<HB_FixedPoint> hb_offsets(shaper_item.num_glyphs);
|
| - QVarLengthArray<unsigned short> hb_logClusters(shaper_item.num_glyphs);
|
|
|
| while (1) {
|
| hb_glyphs.resize(shaper_item.num_glyphs);
|
| @@ -262,10 +266,66 @@ static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
|
|
|
| if (HB_ShapeItem(&shaper_item))
|
| break;
|
| -
|
| }
|
|
|
| HB_FreeFace(hbFace);
|
| +}
|
| +
|
| +
|
| +static bool decomposedShaping(FT_Face face, HB_Script script, const QChar &ch)
|
| +{
|
| + QString uc = QString().append(ch);
|
| + Shaper shaper(face, script, uc);
|
| +
|
| + uc = uc.normalized(QString::NormalizationForm_D);
|
| + Shaper decomposed(face, script, uc);
|
| +
|
| + if( shaper.shaper_item.num_glyphs != decomposed.shaper_item.num_glyphs )
|
| + goto error;
|
| +
|
| + for (unsigned int i = 0; i < shaper.shaper_item.num_glyphs; ++i) {
|
| + if ((shaper.shaper_item.glyphs[i]&0xffffff) != (decomposed.shaper_item.glyphs[i]&0xffffff))
|
| + goto error;
|
| + }
|
| + return true;
|
| + error:
|
| + QString str = "";
|
| + int i = 0;
|
| + while (i < uc.length()) {
|
| + str += QString("%1 ").arg(uc[i].unicode(), 4, 16);
|
| + ++i;
|
| + }
|
| + qDebug("%s: decomposedShaping of char %4x failed\n decomposedString: %s\n nglyphs=%d, decomposed nglyphs %d",
|
| + face->family_name,
|
| + ch.unicode(), str.toLatin1().data(),
|
| + shaper.shaper_item.num_glyphs,
|
| + decomposed.shaper_item.num_glyphs);
|
| +
|
| + str = "";
|
| + i = 0;
|
| + while (i < shaper.shaper_item.num_glyphs) {
|
| + str += QString("%1 ").arg(shaper.shaper_item.glyphs[i], 4, 16);
|
| + ++i;
|
| + }
|
| + qDebug(" composed glyph result = %s", str.toLatin1().constData());
|
| + str = "";
|
| + i = 0;
|
| + while (i < decomposed.shaper_item.num_glyphs) {
|
| + str += QString("%1 ").arg(decomposed.shaper_item.glyphs[i], 4, 16);
|
| + ++i;
|
| + }
|
| + qDebug(" decomposed glyph result = %s", str.toLatin1().constData());
|
| + return false;
|
| +}
|
| +
|
| +struct ShapeTable {
|
| + unsigned short unicode[16];
|
| + unsigned short glyphs[16];
|
| +};
|
| +
|
| +static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
|
| +{
|
| + Shaper shaper(face, script, QString::fromUtf16( s->unicode ));
|
|
|
| hb_uint32 nglyphs = 0;
|
| const unsigned short *g = s->glyphs;
|
| @@ -274,16 +334,16 @@ static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
|
| g++;
|
| }
|
|
|
| - if( nglyphs != shaper_item.num_glyphs )
|
| + if( nglyphs != shaper.shaper_item.num_glyphs )
|
| goto error;
|
|
|
| for (hb_uint32 i = 0; i < nglyphs; ++i) {
|
| - if ((shaper_item.glyphs[i]&0xffffff) != s->glyphs[i])
|
| + if ((shaper.shaper_item.glyphs[i]&0xffffff) != s->glyphs[i])
|
| goto error;
|
| }
|
| return true;
|
| error:
|
| - str = "";
|
| + QString str = "";
|
| const unsigned short *uc = s->unicode;
|
| while (*uc) {
|
| str += QString("%1 ").arg(*uc, 4, 16);
|
| @@ -292,18 +352,78 @@ static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
|
| qDebug("%s: shaping of string %s failed, nglyphs=%d, expected %d",
|
| face->family_name,
|
| str.toLatin1().constData(),
|
| - shaper_item.num_glyphs, nglyphs);
|
| + shaper.shaper_item.num_glyphs, nglyphs);
|
|
|
| str = "";
|
| hb_uint32 i = 0;
|
| - while (i < shaper_item.num_glyphs) {
|
| - str += QString("%1 ").arg(shaper_item.glyphs[i], 4, 16);
|
| + while (i < shaper.shaper_item.num_glyphs) {
|
| + str += QString("%1 ").arg(shaper.shaper_item.glyphs[i], 4, 16);
|
| ++i;
|
| }
|
| qDebug(" glyph result = %s", str.toLatin1().constData());
|
| return false;
|
| }
|
|
|
| +
|
| +void tst_QScriptEngine::greek()
|
| +{
|
| + FT_Face face = loadFace("DejaVuSans.ttf");
|
| + if (face) {
|
| + 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(face, HB_Script_Greek, QChar(uc)) );
|
| + }
|
| + FT_Done_Face(face);
|
| + } else {
|
| + QSKIP("couln't find DejaVu Sans", SkipAll);
|
| + }
|
| +
|
| +
|
| + face = loadFace("SBL_grk.ttf");
|
| + if (face) {
|
| + 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(face, HB_Script_Greek, 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(face, s, HB_Script_Greek) );
|
| + ++s;
|
| + }
|
| +
|
| + FT_Done_Face(face);
|
| + } else {
|
| + QSKIP("couln't find DejaVu Sans", SkipAll);
|
| + }
|
| +}
|
| +
|
| +
|
| void tst_QScriptEngine::devanagari()
|
| {
|
| {
|
| @@ -510,6 +630,17 @@ void tst_QScriptEngine::bengali()
|
| { 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 } },
|
| + { { 0x9b0, 0x9cd, 0x9ad, 0x0 },
|
| + { 0x168, 0x276, 0x0 } },
|
| + { { 0x9f0, 0x9cd, 0x9ad, 0x0 },
|
| + { 0x168, 0x276, 0x0 } },
|
| + { { 0x9f1, 0x9cd, 0x9ad, 0x0 },
|
| + { 0x191, 0x17d, 0x168, 0x0 } },
|
|
|
| { {0}, {0} }
|
| };
|
| @@ -638,15 +769,21 @@ void tst_QScriptEngine::bengali()
|
| if (face) {
|
| const ShapeTable shape_table [] = {
|
| { { 0x09a8, 0x09cd, 0x09af, 0x0 },
|
| - { 0x0192, 0x0 } },
|
| + { 0x01ca, 0x0 } },
|
| { { 0x09b8, 0x09cd, 0x09af, 0x0 },
|
| - { 0x01d6, 0x0 } },
|
| + { 0x020e, 0x0 } },
|
| { { 0x09b6, 0x09cd, 0x09af, 0x0 },
|
| - { 0x01bc, 0x0 } },
|
| + { 0x01f4, 0x0 } },
|
| { { 0x09b7, 0x09cd, 0x09af, 0x0 },
|
| - { 0x01c6, 0x0 } },
|
| + { 0x01fe, 0x0 } },
|
| { { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 },
|
| - { 0xd3, 0x12f, 0x0 } },
|
| + { 0x10b, 0x167, 0x0 } },
|
| + { { 0x9b0, 0x9cd, 0x9ad, 0x0 },
|
| + { 0xa1, 0x167, 0x0 } },
|
| + { { 0x9f0, 0x9cd, 0x9ad, 0x0 },
|
| + { 0xa1, 0x167, 0x0 } },
|
| + { { 0x9f1, 0x9cd, 0x9ad, 0x0 },
|
| + { 0x11c, 0xa1, 0x0 } },
|
|
|
| { {0}, {0} }
|
| };
|
| @@ -668,7 +805,7 @@ void tst_QScriptEngine::bengali()
|
| void tst_QScriptEngine::gurmukhi()
|
| {
|
| {
|
| - FT_Face face = loadFace("lohit.punjabi.1.1.ttf");
|
| + FT_Face face = loadFace("lohit_pa.ttf");
|
| if (face) {
|
| const ShapeTable shape_table [] = {
|
| { { 0xA15, 0xA4D, 0xa39, 0x0 },
|
| @@ -823,8 +960,9 @@ void tst_QScriptEngine::telugu()
|
| { 0xe6, 0xb3, 0x83, 0x0 } },
|
| { { 0xc15, 0xc4d, 0xc30, 0xc48, 0x0 },
|
| { 0xe6, 0xb3, 0x9f, 0x0 } },
|
| - { {0}, {0} }
|
| -
|
| + { { 0xc15, 0xc46, 0xc56, 0x0 },
|
| + { 0xe6, 0xb3, 0x0 } },
|
| + { {0}, {0} }
|
| };
|
|
|
| const ShapeTable *s = shape_table;
|
| @@ -867,7 +1005,6 @@ void tst_QScriptEngine::kannada()
|
| { 0x0036, 0x00c1, 0x0 } },
|
| { { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 },
|
| { 0x0050, 0x00a7, 0x0 } },
|
| -
|
| { {0}, {0} }
|
| };
|
|
|
| @@ -891,6 +1028,17 @@ void tst_QScriptEngine::kannada()
|
| { 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} }
|
| };
|
| @@ -943,7 +1091,16 @@ void tst_QScriptEngine::malayalam()
|
| { 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 } },
|
| + { { 0xd1f, 0xd4d, 0xd1f, 0xd41, 0xd4d, 0x0 },
|
| + { 0x69, 0x5b, 0x64, 0x0 } },
|
|
|
| { {0}, {0} }
|
| };
|
| @@ -960,8 +1117,73 @@ void tst_QScriptEngine::malayalam()
|
| QSKIP("couln't find AkrutiMal2Normal.ttf", SkipAll);
|
| }
|
| }
|
| +
|
| + {
|
| + FT_Face face = loadFace("Rachana.ttf");
|
| + if (face) {
|
| + 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(face, s, HB_Script_Malayalam) );
|
| + ++s;
|
| + }
|
| +
|
| + FT_Done_Face(face);
|
| + } else {
|
| + QSKIP("couln't find Rachana.ttf", SkipAll);
|
| + }
|
| + }
|
| +
|
| }
|
|
|
| +void tst_QScriptEngine::sinhala()
|
| +{
|
| + {
|
| + FT_Face face = loadFace("FM-MalithiUW46.ttf");
|
| + if (face) {
|
| + 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(face, s, HB_Script_Sinhala) );
|
| + ++s;
|
| + }
|
| +
|
| + FT_Done_Face(face);
|
| + } else {
|
| + QSKIP("couln't find FM-MalithiUW46.ttf", SkipAll);
|
| + }
|
| + }
|
| +}
|
|
|
|
|
| void tst_QScriptEngine::khmer()
|
| @@ -1005,10 +1227,44 @@ void tst_QScriptEngine::khmer()
|
| }
|
| }
|
|
|
| +void tst_QScriptEngine::nko()
|
| +{
|
| + {
|
| + FT_Face face = loadFace("DejaVuSans.ttf");
|
| + if (face) {
|
| + const ShapeTable shape_table [] = {
|
| + { { 0x7ca, 0x0 },
|
| + { 0x5c1, 0x0 } },
|
| + { { 0x7ca, 0x7ca, 0x0 },
|
| + { 0x14db, 0x14d9, 0x0 } },
|
| + { { 0x7ca, 0x7fa, 0x7ca, 0x0 },
|
| + { 0x14db, 0x5ec, 0x14d9, 0x0 } },
|
| + { { 0x7ca, 0x7f3, 0x7ca, 0x0 },
|
| + { 0x14db, 0x5e7, 0x14d9, 0x0 } },
|
| + { { 0x7ca, 0x7f3, 0x7fa, 0x7ca, 0x0 },
|
| + { 0x14db, 0x5e7, 0x5ec, 0x14d9, 0x0 } },
|
| + { {0}, {0} }
|
| + };
|
| +
|
| +
|
| + const ShapeTable *s = shape_table;
|
| + while (s->unicode[0]) {
|
| + QVERIFY( shaping(face, s, HB_Script_Nko) );
|
| + ++s;
|
| + }
|
| +
|
| + FT_Done_Face(face);
|
| + } else {
|
| + QSKIP("couln't find DejaVuSans.ttf", SkipAll);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| void tst_QScriptEngine::linearB()
|
| {
|
| {
|
| - FT_Face face = loadFace("PENUTURE.TTF");
|
| + FT_Face face = loadFace("penuture.ttf");
|
| if (face) {
|
| const ShapeTable shape_table [] = {
|
| { { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03, 0 },
|
|
|