2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * This is part of HarfBuzz, an OpenType Layout engine library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 #include <QtTest/QtTest>
28 #include FT_FREETYPE_H
29 #include FT_TRUETYPE_TABLES_H
31 #include <harfbuzz-shaper.h>
32 #include <harfbuzz-global.h>
33 #include <harfbuzz-gpos.h>
35 static FT_Library freetype;
37 static FT_Face loadFace(const char *name)
43 strcat(path, "/fonts/");
46 if (FT_New_Face(freetype, path, /*index*/0, &face))
51 static HB_UChar32 getChar(const HB_UChar16 *string, hb_uint32 length, hb_uint32 &i)
54 if (HB_IsHighSurrogate(string[i])
56 && HB_IsLowSurrogate(string[i + 1])) {
57 ch = HB_SurrogateToUcs4(string[i], string[i + 1]);
65 static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool /*rightToLeft*/)
67 FT_Face face = (FT_Face)font->userData;
68 if (length > *numGlyphs)
72 for (hb_uint32 i = 0; i < length; ++i) {
73 glyphs[glyph_pos] = FT_Get_Char_Index(face, getChar(string, length, i));
77 *numGlyphs = glyph_pos;
82 static void hb_getAdvances(HB_Font /*font*/, const HB_Glyph * /*glyphs*/, hb_uint32 numGlyphs, HB_Fixed *advances, int /*flags*/)
84 for (hb_uint32 i = 0; i < numGlyphs; ++i)
85 advances[i] = 0; // ### not tested right now
88 static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length)
90 FT_Face face = (FT_Face)font->userData;
92 for (hb_uint32 i = 0; i < length; ++i)
93 if (!FT_Get_Char_Index(face, getChar(string, length, i)))
99 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
101 FT_Face face = (FT_Face)font;
102 FT_ULong ftlen = *length;
105 if (!FT_IS_SFNT(face))
106 return HB_Err_Invalid_Argument;
108 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
110 return (HB_Error)error;
113 HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
115 HB_Error error = HB_Err_Ok;
116 FT_Face face = (FT_Face)font->userData;
118 int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
120 if ((error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)))
123 if (face->glyph->format != ft_glyph_format_outline)
124 return (HB_Error)HB_Err_Invalid_SubTable;
126 *nPoints = face->glyph->outline.n_points;
130 if (point > *nPoints)
131 return (HB_Error)HB_Err_Invalid_SubTable;
133 *xpos = face->glyph->outline.points[point].x;
134 *ypos = face->glyph->outline.points[point].y;
139 void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
142 metrics->x = metrics->y = metrics->width = metrics->height = metrics->xOffset = metrics->yOffset = 0;
145 HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
150 const HB_FontClass hb_fontClass = {
151 hb_stringToGlyphs, hb_getAdvances, hb_canRender,
152 hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
157 //TESTED_FILES= gui/text/qscriptengine.cpp
159 class tst_QScriptEngine : public QObject
165 virtual ~tst_QScriptEngine();
170 void cleanupTestCase();
187 tst_QScriptEngine::tst_QScriptEngine()
191 tst_QScriptEngine::~tst_QScriptEngine()
195 void tst_QScriptEngine::initTestCase()
197 FT_Init_FreeType(&freetype);
200 void tst_QScriptEngine::cleanupTestCase()
202 FT_Done_FreeType(freetype);
206 unsigned short unicode[16];
207 unsigned short glyphs[16];
210 static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
212 QString str = QString::fromUtf16( s->unicode );
214 HB_Face hbFace = HB_NewFace(face, hb_getSFntTable);
217 hbFont.klass = &hb_fontClass;
218 hbFont.userData = face;
219 hbFont.x_ppem = face->size->metrics.x_ppem;
220 hbFont.y_ppem = face->size->metrics.y_ppem;
221 hbFont.x_scale = face->size->metrics.x_scale;
222 hbFont.y_scale = face->size->metrics.y_scale;
224 HB_ShaperItem shaper_item;
225 shaper_item.kerning_applied = false;
226 shaper_item.string = reinterpret_cast<const HB_UChar16 *>(str.constData());
227 shaper_item.stringLength = str.length();
228 shaper_item.item.script = script;
229 shaper_item.item.pos = 0;
230 shaper_item.item.length = shaper_item.stringLength;
231 shaper_item.item.bidiLevel = 0; // ###
232 shaper_item.shaperFlags = 0;
233 shaper_item.font = &hbFont;
234 shaper_item.face = hbFace;
235 shaper_item.num_glyphs = shaper_item.item.length;
236 shaper_item.glyphIndicesPresent = false;
237 shaper_item.initialGlyphCount = 0;
239 QVarLengthArray<HB_Glyph> hb_glyphs(shaper_item.num_glyphs);
240 QVarLengthArray<HB_GlyphAttributes> hb_attributes(shaper_item.num_glyphs);
241 QVarLengthArray<HB_Fixed> hb_advances(shaper_item.num_glyphs);
242 QVarLengthArray<HB_FixedPoint> hb_offsets(shaper_item.num_glyphs);
243 QVarLengthArray<unsigned short> hb_logClusters(shaper_item.num_glyphs);
246 hb_glyphs.resize(shaper_item.num_glyphs);
247 hb_attributes.resize(shaper_item.num_glyphs);
248 hb_advances.resize(shaper_item.num_glyphs);
249 hb_offsets.resize(shaper_item.num_glyphs);
250 hb_logClusters.resize(shaper_item.num_glyphs);
252 memset(hb_glyphs.data(), 0, hb_glyphs.size() * sizeof(HB_Glyph));
253 memset(hb_attributes.data(), 0, hb_attributes.size() * sizeof(HB_GlyphAttributes));
254 memset(hb_advances.data(), 0, hb_advances.size() * sizeof(HB_Fixed));
255 memset(hb_offsets.data(), 0, hb_offsets.size() * sizeof(HB_FixedPoint));
257 shaper_item.glyphs = hb_glyphs.data();
258 shaper_item.attributes = hb_attributes.data();
259 shaper_item.advances = hb_advances.data();
260 shaper_item.offsets = hb_offsets.data();
261 shaper_item.log_clusters = hb_logClusters.data();
263 if (HB_ShapeItem(&shaper_item))
270 hb_uint32 nglyphs = 0;
271 const unsigned short *g = s->glyphs;
277 if( nglyphs != shaper_item.num_glyphs )
280 for (hb_uint32 i = 0; i < nglyphs; ++i) {
281 if ((shaper_item.glyphs[i]&0xffffff) != s->glyphs[i])
287 const unsigned short *uc = s->unicode;
289 str += QString("%1 ").arg(*uc, 4, 16);
292 qDebug("%s: shaping of string %s failed, nglyphs=%d, expected %d",
294 str.toLatin1().constData(),
295 shaper_item.num_glyphs, nglyphs);
299 while (i < shaper_item.num_glyphs) {
300 str += QString("%1 ").arg(shaper_item.glyphs[i], 4, 16);
303 qDebug(" glyph result = %s", str.toLatin1().constData());
307 void tst_QScriptEngine::devanagari()
310 FT_Face face = loadFace("raghu.ttf");
312 const ShapeTable shape_table [] = {
317 { { 0x0915, 0x094d, 0x0 },
318 { 0x0080, 0x0051, 0x0 } },
320 { { 0x0915, 0x094d, 0x0915, 0x0 },
321 { 0x00c8, 0x0080, 0x0 } },
323 { { 0x0915, 0x093f, 0x0 },
324 { 0x01d1, 0x0080, 0x0 } },
326 { { 0x0930, 0x094d, 0x0915, 0x0 },
327 { 0x0080, 0x005b, 0x0 } },
328 // Ra Halant Ka MatraI
329 { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
330 { 0x01d1, 0x0080, 0x005b, 0x0 } },
333 { 0x01d4, 0x029c, 0x0 } },
335 { { 0x0915, 0x093c, 0x0 },
338 { { 0x0915, 0x094d, 0x0930, 0x0 },
340 // Ka Halant Ra Halant Ka
341 { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
342 { 0x0158, 0x0080, 0x0 } },
343 { { 0x0930, 0x094d, 0x200d, 0x0 },
345 { { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0x0 },
352 const ShapeTable *s = shape_table;
353 while (s->unicode[0]) {
354 QVERIFY( shaping(face, s, HB_Script_Devanagari) );
360 QSKIP("couln't find raghu.ttf", SkipAll);
365 FT_Face face = loadFace("mangal.ttf");
367 const ShapeTable shape_table [] = {
372 { { 0x0915, 0x094d, 0x0 },
373 { 0x0080, 0x0051, 0x0 } },
375 { { 0x0915, 0x094d, 0x0915, 0x0 },
376 { 0x00c8, 0x0080, 0x0 } },
378 { { 0x0915, 0x093f, 0x0 },
379 { 0x01d1, 0x0080, 0x0 } },
381 { { 0x0930, 0x094d, 0x0915, 0x0 },
382 { 0x0080, 0x005b, 0x0 } },
383 // Ra Halant Ka MatraI
384 { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
385 { 0x01d1, 0x0080, 0x005b, 0x0 } },
388 { 0x01d4, 0x029c, 0x0 } },
390 { { 0x0915, 0x093c, 0x0 },
393 { { 0x0915, 0x094d, 0x0930, 0x0 },
395 // Ka Halant Ra Halant Ka
396 { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
397 { 0x0158, 0x0080, 0x0 } },
399 { { 0x92b, 0x94d, 0x930, 0x0 },
401 { { 0x92b, 0x93c, 0x94d, 0x930, 0x0 },
406 const ShapeTable *s = shape_table;
407 while (s->unicode[0]) {
408 QVERIFY( shaping(face, s, HB_Script_Devanagari) );
414 QSKIP("couldn't find mangal.ttf", SkipAll);
419 void tst_QScriptEngine::bengali()
422 FT_Face face = loadFace("AkaashNormal.ttf");
424 const ShapeTable shape_table [] = {
429 { { 0x0995, 0x09cd, 0x0 },
430 { 0x0151, 0x017d, 0x0 } },
432 { { 0x0995, 0x09cd, 0x0995, 0x0 },
435 { { 0x0995, 0x09bf, 0x0 },
436 { 0x0173, 0x0151, 0x0 } },
438 { { 0x09b0, 0x09cd, 0x0995, 0x0 },
439 { 0x0151, 0x0276, 0x0 } },
440 // Ra Halant Ka MatraI
441 { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
442 { 0x0173, 0x0151, 0x0276, 0x0 } },
444 { { 0x0995, 0x09bc, 0x0 },
445 { 0x0151, 0x0171, 0x0 } },
447 { { 0x0995, 0x09cd, 0x09b0, 0x0 },
449 // Ka Halant Ra Halant Ka
450 { { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0x0 },
451 { 0x025c, 0x0276, 0x0151, 0x0 } },
453 { { 0x09af, 0x09cd, 0x0 },
454 { 0x016a, 0x017d, 0x0 } },
455 // Da Halant Ya -> Da Ya-Phala
456 { { 0x09a6, 0x09cd, 0x09af, 0x0 },
458 // A Halant Ya -> A Ya-phala
459 { { 0x0985, 0x09cd, 0x09af, 0x0 },
460 { 0x0145, 0x01cf, 0x0 } },
462 { { 0x09a8, 0x09cd, 0x0995, 0x0 },
463 { 0x026f, 0x0151, 0x0 } },
465 { { 0x09a8, 0x09cd, 0x200c, 0x0995, 0x0 },
466 { 0x0164, 0x017d, 0x0151, 0x0 } },
468 { { 0x09a8, 0x09cd, 0x200d, 0x0995, 0x0 },
469 { 0x026f, 0x0151, 0x0 } },
471 { { 0x0995, 0x09cd, 0x200c, 0x0995, 0x0 },
472 { 0x0151, 0x017d, 0x0151, 0x0 } },
474 { { 0x0995, 0x09cd, 0x200d, 0x0995, 0x0 },
475 { 0x025c, 0x0151, 0x0 } },
477 { { 0x09a8, 0x09cd, 0x09b0, 0x0 },
480 { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
481 { 0x0164, 0x017d, 0x016b, 0x0 } },
483 { { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0x0 },
484 { 0x026f, 0x016b, 0x0 } },
486 { { 0x09a8, 0x09cd, 0x09ac, 0x0 },
489 { { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0x0 },
490 { 0x0164, 0x017d, 0x0167, 0x0 } },
492 { { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0x0 },
493 { 0x026f, 0x0167, 0x0 } },
495 { { 0x09a8, 0x09cd, 0x09a7, 0x0 },
497 // Na Halant ZWNJ Dha
498 { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
499 { 0x0164, 0x017d, 0x0163, 0x0 } },
501 { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
502 { 0x026f, 0x0163, 0x0 } },
503 // Ra Halant Ka MatraAU
504 { { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0x0 },
505 { 0x0179, 0x0151, 0x0276, 0x017e, 0x0 } },
506 // Ra Halant Ba Halant Ba
507 { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
508 { 0x0232, 0x0276, 0x0 } },
509 { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0x0 },
510 { 0x151, 0x276, 0x172, 0x143, 0x0 } },
511 { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0x0 },
512 { 0x151, 0x276, 0x172, 0x144, 0x0 } },
518 const ShapeTable *s = shape_table;
519 while (s->unicode[0]) {
520 QVERIFY( shaping(face, s, HB_Script_Bengali) );
526 QSKIP("couln't find AkaashNormal.ttf", SkipAll);
530 FT_Face face = loadFace("MuktiNarrow.ttf");
532 const ShapeTable shape_table [] = {
537 { { 0x0995, 0x09cd, 0x0 },
540 { { 0x0995, 0x09cd, 0x0995, 0x0 },
543 { { 0x0995, 0x09bf, 0x0 },
544 { 0x0095, 0x0073, 0x0 } },
546 { { 0x09b0, 0x09cd, 0x0995, 0x0 },
547 { 0x0073, 0x00e1, 0x0 } },
548 // Ra Halant Ka MatraI
549 { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
550 { 0x0095, 0x0073, 0x00e1, 0x0 } },
553 { 0x0095, 0x01c8, 0x0 } },
555 { { 0x0995, 0x09bc, 0x0 },
556 { 0x0073, 0x0093, 0x0 } },
558 { { 0x0995, 0x09cd, 0x09b0, 0x0 },
560 // Ka Halant Ra Halant Ka
561 { { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0x0 },
562 { 0x234, 0x24e, 0x73, 0x0 } },
564 { { 0x09af, 0x09cd, 0x0 },
566 // Da Halant Ya -> Da Ya-Phala
567 { { 0x09a6, 0x09cd, 0x09af, 0x0 },
568 { 0x0084, 0x00e2, 0x0 } },
569 // A Halant Ya -> A Ya-phala
570 { { 0x0985, 0x09cd, 0x09af, 0x0 },
571 { 0x0067, 0x00e2, 0x0 } },
573 { { 0x09a8, 0x09cd, 0x0995, 0x0 },
576 { { 0x9a8, 0x9cd, 0x200c, 0x995, 0x0 },
577 { 0xcc, 0x73, 0x0 } },
579 { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
580 { 0x247, 0x73, 0x0 } },
582 { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
583 { 0x247, 0x73, 0x0 } },
585 { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
586 { 0x247, 0x73, 0x0 } },
588 { { 0x09a8, 0x09cd, 0x09b0, 0x0 },
591 { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
592 { 0xcc, 0x8d, 0x0 } },
594 { { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0x0 },
595 { 0x247, 0x8d, 0x0 } },
597 { { 0x09a8, 0x09cd, 0x09ac, 0x0 },
600 { { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0x0 },
601 { 0xcc, 0x89, 0x0 } },
603 { { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0x0 },
604 { 0x247, 0x89, 0x0 } },
606 { { 0x09a8, 0x09cd, 0x09a7, 0x0 },
608 // Na Halant ZWNJ Dha
609 { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
610 { 0xcc, 0x85, 0x0 } },
612 { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
613 { 0x247, 0x85, 0x0 } },
614 // Ra Halant Ka MatraAU
615 { { 0x9b0, 0x9cd, 0x995, 0x9cc, 0x0 },
616 { 0x232, 0x73, 0xe1, 0xa0, 0x0 } },
617 // Ra Halant Ba Halant Ba
618 { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
619 { 0x013b, 0x00e1, 0x0 } },
625 const ShapeTable *s = shape_table;
626 while (s->unicode[0]) {
627 QVERIFY( shaping(face, s, HB_Script_Bengali) );
633 QSKIP("couln't find MuktiNarrow.ttf", SkipAll);
637 FT_Face face = loadFace("LikhanNormal.ttf");
639 const ShapeTable shape_table [] = {
640 { { 0x09a8, 0x09cd, 0x09af, 0x0 },
642 { { 0x09b8, 0x09cd, 0x09af, 0x0 },
644 { { 0x09b6, 0x09cd, 0x09af, 0x0 },
646 { { 0x09b7, 0x09cd, 0x09af, 0x0 },
648 { { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 },
649 { 0xd3, 0x12f, 0x0 } },
655 const ShapeTable *s = shape_table;
656 while (s->unicode[0]) {
657 QVERIFY( shaping(face, s, HB_Script_Bengali) );
663 QSKIP("couln't find LikhanNormal.ttf", SkipAll);
668 void tst_QScriptEngine::gurmukhi()
671 FT_Face face = loadFace("lohit.punjabi.1.1.ttf");
673 const ShapeTable shape_table [] = {
674 { { 0xA15, 0xA4D, 0xa39, 0x0 },
675 { 0x3b, 0x8b, 0x0 } },
680 const ShapeTable *s = shape_table;
681 while (s->unicode[0]) {
682 QVERIFY( shaping(face, s, HB_Script_Gurmukhi) );
688 QSKIP("couln't find lohit.punjabi.1.1.ttf", SkipAll);
693 void tst_QScriptEngine::oriya()
696 FT_Face face = loadFace("utkalm.ttf");
698 const ShapeTable shape_table [] = {
699 { { 0xb15, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
700 { 0x150, 0x125, 0x0 } },
701 { { 0xb24, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
702 { 0x151, 0x120, 0x0 } },
703 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
704 { 0x152, 0x120, 0x0 } },
705 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
706 { 0x152, 0x120, 0x0 } },
707 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
709 { { 0xb38, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
711 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0xb4d, 0xb2f, 0x0 },
712 { 0x176, 0x124, 0x0 } },
717 const ShapeTable *s = shape_table;
718 while (s->unicode[0]) {
719 QVERIFY( shaping(face, s, HB_Script_Oriya) );
725 QSKIP("couln't find utkalm.ttf", SkipAll);
731 void tst_QScriptEngine::tamil()
734 FT_Face face = loadFace("akruti1.ttf");
736 const ShapeTable shape_table [] = {
737 { { 0x0b95, 0x0bc2, 0x0 },
739 { { 0x0bae, 0x0bc2, 0x0 },
741 { { 0x0b9a, 0x0bc2, 0x0 },
743 { { 0x0b99, 0x0bc2, 0x0 },
745 { { 0x0bb0, 0x0bc2, 0x0 },
747 { { 0x0ba4, 0x0bc2, 0x0 },
749 { { 0x0b9f, 0x0bc2, 0x0 },
751 { { 0x0b95, 0x0bc6, 0x0 },
752 { 0x000a, 0x0031, 0x0 } },
753 { { 0x0b95, 0x0bca, 0x0 },
754 { 0x000a, 0x0031, 0x0007, 0x0 } },
755 { { 0x0b95, 0x0bc6, 0x0bbe, 0x0 },
756 { 0x000a, 0x0031, 0x007, 0x0 } },
757 { { 0x0b95, 0x0bcd, 0x0bb7, 0x0 },
759 { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0x0 },
760 { 0x000a, 0x0049, 0x007, 0x0 } },
761 { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0x0 },
762 { 0x000a, 0x0049, 0x007, 0x0 } },
763 { { 0x0b9f, 0x0bbf, 0x0 },
765 { { 0x0b9f, 0x0bc0, 0x0 },
767 { { 0x0bb2, 0x0bc0, 0x0 },
769 { { 0x0bb2, 0x0bbf, 0x0 },
771 { { 0x0bb0, 0x0bcd, 0x0 },
773 { { 0x0bb0, 0x0bbf, 0x0 },
775 { { 0x0bb0, 0x0bc0, 0x0 },
779 { { 0x0b83, 0x0b95, 0x0 },
780 { 0x0025, 0x0031, 0x0 } },
786 const ShapeTable *s = shape_table;
787 while (s->unicode[0]) {
788 QVERIFY( shaping(face, s, HB_Script_Tamil) );
794 QSKIP("couln't find akruti1.ttf", SkipAll);
800 void tst_QScriptEngine::telugu()
803 FT_Face face = loadFace("Pothana2000.ttf");
805 const ShapeTable shape_table [] = {
806 { { 0xc15, 0xc4d, 0x0 },
808 { { 0xc15, 0xc4d, 0xc37, 0x0 },
810 { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0x0 },
812 { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0xc23, 0x0 },
813 { 0x4b, 0x91, 0x0 } },
814 { { 0xc15, 0xc4d, 0xc30, 0x0 },
815 { 0x5a, 0xb2, 0x0 } },
816 { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0x0 },
817 { 0xbb, 0xb2, 0x0 } },
818 { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0xc15, 0x0 },
819 { 0x5a, 0xb2, 0x83, 0x0 } },
820 { { 0xc15, 0xc4d, 0xc30, 0xc3f, 0x0 },
821 { 0xe2, 0xb2, 0x0 } },
822 { { 0xc15, 0xc4d, 0xc15, 0xc48, 0x0 },
823 { 0xe6, 0xb3, 0x83, 0x0 } },
824 { { 0xc15, 0xc4d, 0xc30, 0xc48, 0x0 },
825 { 0xe6, 0xb3, 0x9f, 0x0 } },
830 const ShapeTable *s = shape_table;
831 while (s->unicode[0]) {
832 QVERIFY( shaping(face, s, HB_Script_Telugu) );
838 QSKIP("couln't find Pothana2000.ttf", SkipAll);
844 void tst_QScriptEngine::kannada()
847 FT_Face face = loadFace("Sampige.ttf");
849 const ShapeTable shape_table [] = {
850 { { 0x0ca8, 0x0ccd, 0x0ca8, 0x0 },
851 { 0x0049, 0x00ba, 0x0 } },
852 { { 0x0ca8, 0x0ccd, 0x0ca1, 0x0 },
853 { 0x0049, 0x00b3, 0x0 } },
854 { { 0x0caf, 0x0cc2, 0x0 },
855 { 0x004f, 0x005d, 0x0 } },
858 { { 0x0ce6, 0x0ce7, 0x0ce8, 0x0 },
859 { 0x006b, 0x006c, 0x006d, 0x0 } },
860 { { 0x0cb5, 0x0ccb, 0x0 },
861 { 0x015f, 0x0067, 0x0 } },
862 { { 0x0cb0, 0x0ccd, 0x0cae, 0x0 },
863 { 0x004e, 0x0082, 0x0 } },
864 { { 0x0cb0, 0x0ccd, 0x0c95, 0x0 },
865 { 0x0036, 0x0082, 0x0 } },
866 { { 0x0c95, 0x0ccd, 0x0cb0, 0x0 },
867 { 0x0036, 0x00c1, 0x0 } },
868 { { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 },
869 { 0x0050, 0x00a7, 0x0 } },
875 const ShapeTable *s = shape_table;
876 while (s->unicode[0]) {
877 QVERIFY( shaping(face, s, HB_Script_Kannada) );
883 QSKIP("couln't find Sampige.ttf", SkipAll);
887 FT_Face face = loadFace("tunga.ttf");
889 const ShapeTable shape_table [] = {
890 { { 0x0cb7, 0x0cc6, 0x0 },
891 { 0x00b0, 0x006c, 0x0 } },
892 { { 0x0cb7, 0x0ccd, 0x0 },
899 const ShapeTable *s = shape_table;
900 while (s->unicode[0]) {
901 QVERIFY( shaping(face, s, HB_Script_Kannada) );
907 QSKIP("couln't find tunga.ttf", SkipAll);
914 void tst_QScriptEngine::malayalam()
917 FT_Face face = loadFace("AkrutiMal2Normal.ttf");
919 const ShapeTable shape_table [] = {
920 { { 0x0d15, 0x0d46, 0x0 },
921 { 0x005e, 0x0034, 0x0 } },
922 { { 0x0d15, 0x0d47, 0x0 },
923 { 0x005f, 0x0034, 0x0 } },
924 { { 0x0d15, 0x0d4b, 0x0 },
925 { 0x005f, 0x0034, 0x0058, 0x0 } },
926 { { 0x0d15, 0x0d48, 0x0 },
927 { 0x0060, 0x0034, 0x0 } },
928 { { 0x0d15, 0x0d4a, 0x0 },
929 { 0x005e, 0x0034, 0x0058, 0x0 } },
930 { { 0x0d30, 0x0d4d, 0x0d15, 0x0 },
931 { 0x009e, 0x0034, 0x0 } },
932 { { 0x0d15, 0x0d4d, 0x0d35, 0x0 },
933 { 0x0034, 0x007a, 0x0 } },
934 { { 0x0d15, 0x0d4d, 0x0d2f, 0x0 },
935 { 0x0034, 0x00a2, 0x0 } },
936 { { 0x0d1f, 0x0d4d, 0x0d1f, 0x0 },
938 { { 0x0d26, 0x0d4d, 0x0d26, 0x0 },
940 { { 0x0d30, 0x0d4d, 0x0 },
942 { { 0x0d30, 0x0d4d, 0x200c, 0x0 },
944 { { 0x0d30, 0x0d4d, 0x200d, 0x0 },
952 const ShapeTable *s = shape_table;
953 while (s->unicode[0]) {
954 QVERIFY( shaping(face, s, HB_Script_Malayalam) );
960 QSKIP("couln't find AkrutiMal2Normal.ttf", SkipAll);
967 void tst_QScriptEngine::khmer()
970 FT_Face face = loadFace("KhmerOS.ttf");
972 const ShapeTable shape_table [] = {
973 { { 0x179a, 0x17cd, 0x0 },
974 { 0x24c, 0x27f, 0x0 } },
975 { { 0x179f, 0x17c5, 0x0 },
976 { 0x273, 0x203, 0x0 } },
977 { { 0x1790, 0x17d2, 0x1784, 0x17c3, 0x0 },
978 { 0x275, 0x242, 0x182, 0x0 } },
981 { { 0x1781, 0x17d2, 0x1798, 0x17c2, 0x0 },
982 { 0x274, 0x233, 0x197, 0x0 } },
983 { { 0x1798, 0x17b6, 0x0 },
985 { { 0x179a, 0x17b8, 0x0 },
986 { 0x24c, 0x26a, 0x0 } },
987 { { 0x1787, 0x17b6, 0x0 },
989 { { 0x1798, 0x17d2, 0x1796, 0x17bb, 0x0 },
990 { 0x24a, 0x195, 0x26d, 0x0 } },
995 const ShapeTable *s = shape_table;
996 while (s->unicode[0]) {
997 QVERIFY( shaping(face, s, HB_Script_Khmer) );
1003 QSKIP("couln't find KhmerOS.ttf", SkipAll);
1008 void tst_QScriptEngine::linearB()
1011 FT_Face face = loadFace("PENUTURE.TTF");
1013 const ShapeTable shape_table [] = {
1014 { { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03, 0 },
1015 { 0x5, 0x6, 0x7, 0 } },
1020 const ShapeTable *s = shape_table;
1021 while (s->unicode[0]) {
1022 QVERIFY( shaping(face, s, HB_Script_Common) );
1028 QSKIP("couln't find PENUTURE.TTF", SkipAll);
1034 QTEST_MAIN(tst_QScriptEngine)