1 /*
2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3 *
4 * This is part of HarfBuzz, an OpenType Layout engine library.
5 *
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.
11 *
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
16 * DAMAGE.
17 *
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.
23 */
24
25 #include <QtTest/QtTest>
26
27 #include <ft2build.h>
28 #include FT_FREETYPE_H
29 #include FT_TRUETYPE_TABLES_H
30
31 #include <harfbuzz-shaper.h>
32 #include <harfbuzz-global.h>
33 #include <harfbuzz-gpos.h>
34
35 static FT_Library freetype;
36
loadFace(const char * name)37 static FT_Face loadFace(const char *name)
38 {
39 FT_Face face;
40 char path[256];
41
42 strcpy(path, SRCDIR);
43 strcat(path, "/fonts/");
44 strcat(path, name);
45
46 if (FT_New_Face(freetype, path, /*index*/0, &face))
47 return 0;
48 return face;
49 }
50
getChar(const HB_UChar16 * string,hb_uint32 length,hb_uint32 & i)51 static HB_UChar32 getChar(const HB_UChar16 *string, hb_uint32 length, hb_uint32 &i)
52 {
53 HB_UChar32 ch;
54 if (HB_IsHighSurrogate(string[i])
55 && i < length - 1
56 && HB_IsLowSurrogate(string[i + 1])) {
57 ch = HB_SurrogateToUcs4(string[i], string[i + 1]);
58 ++i;
59 } else {
60 ch = string[i];
61 }
62 return ch;
63 }
64
hb_stringToGlyphs(HB_Font font,const HB_UChar16 * string,hb_uint32 length,HB_Glyph * glyphs,hb_uint32 * numGlyphs,HB_Bool)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*/)
66 {
67 FT_Face face = (FT_Face)font->userData;
68 if (length > *numGlyphs)
69 return false;
70
71 int glyph_pos = 0;
72 for (hb_uint32 i = 0; i < length; ++i) {
73 glyphs[glyph_pos] = FT_Get_Char_Index(face, getChar(string, length, i));
74 ++glyph_pos;
75 }
76
77 *numGlyphs = glyph_pos;
78
79 return true;
80 }
81
hb_getAdvances(HB_Font,const HB_Glyph *,hb_uint32 numGlyphs,HB_Fixed * advances,int)82 static void hb_getAdvances(HB_Font /*font*/, const HB_Glyph * /*glyphs*/, hb_uint32 numGlyphs, HB_Fixed *advances, int /*flags*/)
83 {
84 for (hb_uint32 i = 0; i < numGlyphs; ++i)
85 advances[i] = 0; // ### not tested right now
86 }
87
hb_canRender(HB_Font font,const HB_UChar16 * string,hb_uint32 length)88 static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length)
89 {
90 FT_Face face = (FT_Face)font->userData;
91
92 for (hb_uint32 i = 0; i < length; ++i)
93 if (!FT_Get_Char_Index(face, getChar(string, length, i)))
94 return false;
95
96 return true;
97 }
98
hb_getSFntTable(void * font,HB_Tag tableTag,HB_Byte * buffer,HB_UInt * length)99 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
100 {
101 FT_Face face = (FT_Face)font;
102 FT_ULong ftlen = *length;
103 FT_Error error = 0;
104
105 if (!FT_IS_SFNT(face))
106 return HB_Err_Invalid_Argument;
107
108 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
109 *length = ftlen;
110 return (HB_Error)error;
111 }
112
hb_getPointInOutline(HB_Font font,HB_Glyph glyph,int flags,hb_uint32 point,HB_Fixed * xpos,HB_Fixed * ypos,hb_uint32 * nPoints)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)
114 {
115 HB_Error error = HB_Err_Ok;
116 FT_Face face = (FT_Face)font->userData;
117
118 int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
119
120 if ((error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)))
121 return error;
122
123 if (face->glyph->format != ft_glyph_format_outline)
124 return (HB_Error)HB_Err_Invalid_SubTable;
125
126 *nPoints = face->glyph->outline.n_points;
127 if (!(*nPoints))
128 return HB_Err_Ok;
129
130 if (point > *nPoints)
131 return (HB_Error)HB_Err_Invalid_SubTable;
132
133 *xpos = face->glyph->outline.points[point].x;
134 *ypos = face->glyph->outline.points[point].y;
135
136 return HB_Err_Ok;
137 }
138
hb_getGlyphMetrics(HB_Font,HB_Glyph,HB_GlyphMetrics * metrics)139 void hb_getGlyphMetrics(HB_Font, HB_Glyph, HB_GlyphMetrics *metrics)
140 {
141 // ###
142 metrics->x = metrics->y = metrics->width = metrics->height = metrics->xOffset = metrics->yOffset = 0;
143 }
144
hb_getFontMetric(HB_Font,HB_FontMetric)145 HB_Fixed hb_getFontMetric(HB_Font, HB_FontMetric )
146 {
147 return 0; // ####
148 }
149
150 const HB_FontClass hb_fontClass = {
151 hb_stringToGlyphs, hb_getAdvances, hb_canRender,
152 hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
153 };
154
155
156 //TESTED_CLASS=
157 //TESTED_FILES= gui/text/qscriptengine.cpp
158
159 class tst_QScriptEngine : public QObject
160 {
161 Q_OBJECT
162
163 public:
164 tst_QScriptEngine();
165 virtual ~tst_QScriptEngine();
166
167
168 public slots:
169 void initTestCase();
170 void cleanupTestCase();
171 private slots:
172 void greek();
173
174 void devanagari();
175 void bengali();
176 void gurmukhi();
177 // gujarati missing
178 void oriya();
179 void tamil();
180 void telugu();
181 void kannada();
182 void malayalam();
183 void sinhala();
184
185 void khmer();
186 void nko();
187 void linearB();
188 };
189
tst_QScriptEngine()190 tst_QScriptEngine::tst_QScriptEngine()
191 {
192 }
193
~tst_QScriptEngine()194 tst_QScriptEngine::~tst_QScriptEngine()
195 {
196 }
197
initTestCase()198 void tst_QScriptEngine::initTestCase()
199 {
200 FT_Init_FreeType(&freetype);
201 }
202
cleanupTestCase()203 void tst_QScriptEngine::cleanupTestCase()
204 {
205 FT_Done_FreeType(freetype);
206 }
207
208 class Shaper
209 {
210 public:
211 Shaper(FT_Face face, HB_Script script, const QString &str);
212
213 HB_FontRec hbFont;
214 HB_ShaperItem shaper_item;
215 QVarLengthArray<HB_Glyph> hb_glyphs;
216 QVarLengthArray<HB_GlyphAttributes> hb_attributes;
217 QVarLengthArray<HB_Fixed> hb_advances;
218 QVarLengthArray<HB_FixedPoint> hb_offsets;
219 QVarLengthArray<unsigned short> hb_logClusters;
220
221 };
222
Shaper(FT_Face face,HB_Script script,const QString & str)223 Shaper::Shaper(FT_Face face, HB_Script script, const QString &str)
224 {
225 HB_Face hbFace = HB_NewFace(face, hb_getSFntTable);
226
227 hbFont.klass = &hb_fontClass;
228 hbFont.userData = face;
229 hbFont.x_ppem = face->size->metrics.x_ppem;
230 hbFont.y_ppem = face->size->metrics.y_ppem;
231 hbFont.x_scale = face->size->metrics.x_scale;
232 hbFont.y_scale = face->size->metrics.y_scale;
233
234 shaper_item.kerning_applied = false;
235 shaper_item.string = reinterpret_cast<const HB_UChar16 *>(str.constData());
236 shaper_item.stringLength = str.length();
237 shaper_item.item.script = script;
238 shaper_item.item.pos = 0;
239 shaper_item.item.length = shaper_item.stringLength;
240 shaper_item.item.bidiLevel = 0; // ###
241 shaper_item.shaperFlags = 0;
242 shaper_item.font = &hbFont;
243 shaper_item.face = hbFace;
244 shaper_item.num_glyphs = shaper_item.item.length;
245 shaper_item.glyphIndicesPresent = false;
246 shaper_item.initialGlyphCount = 0;
247
248
249 while (1) {
250 hb_glyphs.resize(shaper_item.num_glyphs);
251 hb_attributes.resize(shaper_item.num_glyphs);
252 hb_advances.resize(shaper_item.num_glyphs);
253 hb_offsets.resize(shaper_item.num_glyphs);
254 hb_logClusters.resize(shaper_item.num_glyphs);
255
256 memset(hb_glyphs.data(), 0, hb_glyphs.size() * sizeof(HB_Glyph));
257 memset(hb_attributes.data(), 0, hb_attributes.size() * sizeof(HB_GlyphAttributes));
258 memset(hb_advances.data(), 0, hb_advances.size() * sizeof(HB_Fixed));
259 memset(hb_offsets.data(), 0, hb_offsets.size() * sizeof(HB_FixedPoint));
260
261 shaper_item.glyphs = hb_glyphs.data();
262 shaper_item.attributes = hb_attributes.data();
263 shaper_item.advances = hb_advances.data();
264 shaper_item.offsets = hb_offsets.data();
265 shaper_item.log_clusters = hb_logClusters.data();
266
267 if (HB_ShapeItem(&shaper_item))
268 break;
269 }
270
271 HB_FreeFace(hbFace);
272 }
273
274
decomposedShaping(FT_Face face,HB_Script script,const QChar & ch)275 static bool decomposedShaping(FT_Face face, HB_Script script, const QChar &ch)
276 {
277 QString uc = QString().append(ch);
278 Shaper shaper(face, script, uc);
279
280 uc = uc.normalized(QString::NormalizationForm_D);
281 Shaper decomposed(face, script, uc);
282
283 if( shaper.shaper_item.num_glyphs != decomposed.shaper_item.num_glyphs )
284 goto error;
285
286 for (unsigned int i = 0; i < shaper.shaper_item.num_glyphs; ++i) {
287 if ((shaper.shaper_item.glyphs[i]&0xffffff) != (decomposed.shaper_item.glyphs[i]&0xffffff))
288 goto error;
289 }
290 return true;
291 error:
292 QString str = "";
293 int i = 0;
294 while (i < uc.length()) {
295 str += QString("%1 ").arg(uc[i].unicode(), 4, 16);
296 ++i;
297 }
298 qDebug("%s: decomposedShaping of char %4x failed\n decomposedString: %s\n nglyphs=%d, decomposed nglyphs %d",
299 face->family_name,
300 ch.unicode(), str.toLatin1().data(),
301 shaper.shaper_item.num_glyphs,
302 decomposed.shaper_item.num_glyphs);
303
304 str = "";
305 i = 0;
306 while (i < shaper.shaper_item.num_glyphs) {
307 str += QString("%1 ").arg(shaper.shaper_item.glyphs[i], 4, 16);
308 ++i;
309 }
310 qDebug(" composed glyph result = %s", str.toLatin1().constData());
311 str = "";
312 i = 0;
313 while (i < decomposed.shaper_item.num_glyphs) {
314 str += QString("%1 ").arg(decomposed.shaper_item.glyphs[i], 4, 16);
315 ++i;
316 }
317 qDebug(" decomposed glyph result = %s", str.toLatin1().constData());
318 return false;
319 }
320
321 struct ShapeTable {
322 unsigned short unicode[16];
323 unsigned short glyphs[16];
324 };
325
shaping(FT_Face face,const ShapeTable * s,HB_Script script)326 static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
327 {
328 Shaper shaper(face, script, QString::fromUtf16( s->unicode ));
329
330 hb_uint32 nglyphs = 0;
331 const unsigned short *g = s->glyphs;
332 while ( *g ) {
333 nglyphs++;
334 g++;
335 }
336
337 if( nglyphs != shaper.shaper_item.num_glyphs )
338 goto error;
339
340 for (hb_uint32 i = 0; i < nglyphs; ++i) {
341 if ((shaper.shaper_item.glyphs[i]&0xffffff) != s->glyphs[i])
342 goto error;
343 }
344 return true;
345 error:
346 QString str = "";
347 const unsigned short *uc = s->unicode;
348 while (*uc) {
349 str += QString("%1 ").arg(*uc, 4, 16);
350 ++uc;
351 }
352 qDebug("%s: shaping of string %s failed, nglyphs=%d, expected %d",
353 face->family_name,
354 str.toLatin1().constData(),
355 shaper.shaper_item.num_glyphs, nglyphs);
356
357 str = "";
358 hb_uint32 i = 0;
359 while (i < shaper.shaper_item.num_glyphs) {
360 str += QString("%1 ").arg(shaper.shaper_item.glyphs[i], 4, 16);
361 ++i;
362 }
363 qDebug(" glyph result = %s", str.toLatin1().constData());
364 return false;
365 }
366
367
greek()368 void tst_QScriptEngine::greek()
369 {
370 FT_Face face = loadFace("DejaVuSans.ttf");
371 if (face) {
372 for (int uc = 0x1f00; uc <= 0x1fff; ++uc) {
373 QString str;
374 str.append(uc);
375 if (str.normalized(QString::NormalizationForm_D).normalized(QString::NormalizationForm_C) != str) {
376 //qDebug() << "skipping" << hex << uc;
377 continue;
378 }
379 if (uc == 0x1fc1 || uc == 0x1fed)
380 continue;
381 QVERIFY( decomposedShaping(face, HB_Script_Greek, QChar(uc)) );
382 }
383 FT_Done_Face(face);
384 } else {
385 QSKIP("couln't find DejaVu Sans", SkipAll);
386 }
387
388
389 face = loadFace("SBL_grk.ttf");
390 if (face) {
391 for (int uc = 0x1f00; uc <= 0x1fff; ++uc) {
392 QString str;
393 str.append(uc);
394 if (str.normalized(QString::NormalizationForm_D).normalized(QString::NormalizationForm_C) != str) {
395 //qDebug() << "skipping" << hex << uc;
396 continue;
397 }
398 if (uc == 0x1fc1 || uc == 0x1fed)
399 continue;
400 QVERIFY( decomposedShaping(face, HB_Script_Greek, QChar(uc)) );
401
402 }
403
404 const ShapeTable shape_table [] = {
405 { { 0x3b1, 0x300, 0x313, 0x0 },
406 { 0xb8, 0x3d3, 0x3c7, 0x0 } },
407 { { 0x3b1, 0x313, 0x300, 0x0 },
408 { 0xd4, 0x0 } },
409
410 { {0}, {0} }
411 };
412
413
414 const ShapeTable *s = shape_table;
415 while (s->unicode[0]) {
416 QVERIFY( shaping(face, s, HB_Script_Greek) );
417 ++s;
418 }
419
420 FT_Done_Face(face);
421 } else {
422 QSKIP("couln't find DejaVu Sans", SkipAll);
423 }
424 }
425
426
devanagari()427 void tst_QScriptEngine::devanagari()
428 {
429 {
430 FT_Face face = loadFace("raghu.ttf");
431 if (face) {
432 const ShapeTable shape_table [] = {
433 // Ka
434 { { 0x0915, 0x0 },
435 { 0x0080, 0x0 } },
436 // Ka Halant
437 { { 0x0915, 0x094d, 0x0 },
438 { 0x0080, 0x0051, 0x0 } },
439 // Ka Halant Ka
440 { { 0x0915, 0x094d, 0x0915, 0x0 },
441 { 0x00c8, 0x0080, 0x0 } },
442 // Ka MatraI
443 { { 0x0915, 0x093f, 0x0 },
444 { 0x01d1, 0x0080, 0x0 } },
445 // Ra Halant Ka
446 { { 0x0930, 0x094d, 0x0915, 0x0 },
447 { 0x0080, 0x005b, 0x0 } },
448 // Ra Halant Ka MatraI
449 { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
450 { 0x01d1, 0x0080, 0x005b, 0x0 } },
451 // MatraI
452 { { 0x093f, 0x0 },
453 { 0x01d4, 0x029c, 0x0 } },
454 // Ka Nukta
455 { { 0x0915, 0x093c, 0x0 },
456 { 0x00a4, 0x0 } },
457 // Ka Halant Ra
458 { { 0x0915, 0x094d, 0x0930, 0x0 },
459 { 0x0110, 0x0 } },
460 // Ka Halant Ra Halant Ka
461 { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
462 { 0x0158, 0x0080, 0x0 } },
463 { { 0x0930, 0x094d, 0x200d, 0x0 },
464 { 0x00e2, 0x0 } },
465 { { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0x0 },
466 { 0x0158, 0x0 } },
467
468 { {0}, {0} }
469 };
470
471
472 const ShapeTable *s = shape_table;
473 while (s->unicode[0]) {
474 QVERIFY( shaping(face, s, HB_Script_Devanagari) );
475 ++s;
476 }
477
478 FT_Done_Face(face);
479 } else {
480 QSKIP("couln't find raghu.ttf", SkipAll);
481 }
482 }
483
484 {
485 FT_Face face = loadFace("mangal.ttf");
486 if (face) {
487 const ShapeTable shape_table [] = {
488 // Ka
489 { { 0x0915, 0x0 },
490 { 0x0080, 0x0 } },
491 // Ka Halant
492 { { 0x0915, 0x094d, 0x0 },
493 { 0x0080, 0x0051, 0x0 } },
494 // Ka Halant Ka
495 { { 0x0915, 0x094d, 0x0915, 0x0 },
496 { 0x00c8, 0x0080, 0x0 } },
497 // Ka MatraI
498 { { 0x0915, 0x093f, 0x0 },
499 { 0x01d1, 0x0080, 0x0 } },
500 // Ra Halant Ka
501 { { 0x0930, 0x094d, 0x0915, 0x0 },
502 { 0x0080, 0x005b, 0x0 } },
503 // Ra Halant Ka MatraI
504 { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
505 { 0x01d1, 0x0080, 0x005b, 0x0 } },
506 // MatraI
507 { { 0x093f, 0x0 },
508 { 0x01d4, 0x029c, 0x0 } },
509 // Ka Nukta
510 { { 0x0915, 0x093c, 0x0 },
511 { 0x00a4, 0x0 } },
512 // Ka Halant Ra
513 { { 0x0915, 0x094d, 0x0930, 0x0 },
514 { 0x0110, 0x0 } },
515 // Ka Halant Ra Halant Ka
516 { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
517 { 0x0158, 0x0080, 0x0 } },
518
519 { { 0x92b, 0x94d, 0x930, 0x0 },
520 { 0x125, 0x0 } },
521 { { 0x92b, 0x93c, 0x94d, 0x930, 0x0 },
522 { 0x149, 0x0 } },
523 { {0}, {0} }
524 };
525
526 const ShapeTable *s = shape_table;
527 while (s->unicode[0]) {
528 QVERIFY( shaping(face, s, HB_Script_Devanagari) );
529 ++s;
530 }
531
532 FT_Done_Face(face);
533 } else {
534 QSKIP("couldn't find mangal.ttf", SkipAll);
535 }
536 }
537 }
538
bengali()539 void tst_QScriptEngine::bengali()
540 {
541 {
542 FT_Face face = loadFace("AkaashNormal.ttf");
543 if (face) {
544 const ShapeTable shape_table [] = {
545 // Ka
546 { { 0x0995, 0x0 },
547 { 0x0151, 0x0 } },
548 // Ka Halant
549 { { 0x0995, 0x09cd, 0x0 },
550 { 0x0151, 0x017d, 0x0 } },
551 // Ka Halant Ka
552 { { 0x0995, 0x09cd, 0x0995, 0x0 },
553 { 0x019b, 0x0 } },
554 // Ka MatraI
555 { { 0x0995, 0x09bf, 0x0 },
556 { 0x0173, 0x0151, 0x0 } },
557 // Ra Halant Ka
558 { { 0x09b0, 0x09cd, 0x0995, 0x0 },
559 { 0x0151, 0x0276, 0x0 } },
560 // Ra Halant Ka MatraI
561 { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
562 { 0x0173, 0x0151, 0x0276, 0x0 } },
563 // Ka Nukta
564 { { 0x0995, 0x09bc, 0x0 },
565 { 0x0151, 0x0171, 0x0 } },
566 // Ka Halant Ra
567 { { 0x0995, 0x09cd, 0x09b0, 0x0 },
568 { 0x01f4, 0x0 } },
569 // Ka Halant Ra Halant Ka
570 { { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0x0 },
571 { 0x025c, 0x0276, 0x0151, 0x0 } },
572 // Ya + Halant
573 { { 0x09af, 0x09cd, 0x0 },
574 { 0x016a, 0x017d, 0x0 } },
575 // Da Halant Ya -> Da Ya-Phala
576 { { 0x09a6, 0x09cd, 0x09af, 0x0 },
577 { 0x01e5, 0x0 } },
578 // A Halant Ya -> A Ya-phala
579 { { 0x0985, 0x09cd, 0x09af, 0x0 },
580 { 0x0145, 0x01cf, 0x0 } },
581 // Na Halant Ka
582 { { 0x09a8, 0x09cd, 0x0995, 0x0 },
583 { 0x026f, 0x0151, 0x0 } },
584 // Na Halant ZWNJ Ka
585 { { 0x09a8, 0x09cd, 0x200c, 0x0995, 0x0 },
586 { 0x0164, 0x017d, 0x0151, 0x0 } },
587 // Na Halant ZWJ Ka
588 { { 0x09a8, 0x09cd, 0x200d, 0x0995, 0x0 },
589 { 0x026f, 0x0151, 0x0 } },
590 // Ka Halant ZWNJ Ka
591 { { 0x0995, 0x09cd, 0x200c, 0x0995, 0x0 },
592 { 0x0151, 0x017d, 0x0151, 0x0 } },
593 // Ka Halant ZWJ Ka
594 { { 0x0995, 0x09cd, 0x200d, 0x0995, 0x0 },
595 { 0x025c, 0x0151, 0x0 } },
596 // Na Halant Ra
597 { { 0x09a8, 0x09cd, 0x09b0, 0x0 },
598 { 0x0207, 0x0 } },
599 // Na Halant ZWNJ Ra
600 { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
601 { 0x0164, 0x017d, 0x016b, 0x0 } },
602 // Na Halant ZWJ Ra
603 { { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0x0 },
604 { 0x026f, 0x016b, 0x0 } },
605 // Na Halant Ba
606 { { 0x09a8, 0x09cd, 0x09ac, 0x0 },
607 { 0x022f, 0x0 } },
608 // Na Halant ZWNJ Ba
609 { { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0x0 },
610 { 0x0164, 0x017d, 0x0167, 0x0 } },
611 // Na Halant ZWJ Ba
612 { { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0x0 },
613 { 0x026f, 0x0167, 0x0 } },
614 // Na Halant Dha
615 { { 0x09a8, 0x09cd, 0x09a7, 0x0 },
616 { 0x01d3, 0x0 } },
617 // Na Halant ZWNJ Dha
618 { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
619 { 0x0164, 0x017d, 0x0163, 0x0 } },
620 // Na Halant ZWJ Dha
621 { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
622 { 0x026f, 0x0163, 0x0 } },
623 // Ra Halant Ka MatraAU
624 { { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0x0 },
625 { 0x0179, 0x0151, 0x0276, 0x017e, 0x0 } },
626 // Ra Halant Ba Halant Ba
627 { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
628 { 0x0232, 0x0276, 0x0 } },
629 { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0x0 },
630 { 0x151, 0x276, 0x172, 0x143, 0x0 } },
631 { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0x0 },
632 { 0x151, 0x276, 0x172, 0x144, 0x0 } },
633 // test decomposed two parts matras
634 { { 0x995, 0x9c7, 0x9be, 0x0 },
635 { 0x179, 0x151, 0x172, 0x0 } },
636 { { 0x995, 0x9c7, 0x9d7, 0x0 },
637 { 0x179, 0x151, 0x17e, 0x0 } },
638 { { 0x9b0, 0x9cd, 0x9ad, 0x0 },
639 { 0x168, 0x276, 0x0 } },
640 { { 0x9f0, 0x9cd, 0x9ad, 0x0 },
641 { 0x168, 0x276, 0x0 } },
642 { { 0x9f1, 0x9cd, 0x9ad, 0x0 },
643 { 0x191, 0x17d, 0x168, 0x0 } },
644
645 // Ra ZWJ Halant Ya
646 { { 0x09b0, 0x200d, 0x09cd, 0x09af, 0x0 },
647 { 0x016b, 0x01cf, 0x0 } },
648
649 { {0}, {0} }
650 };
651
652
653 const ShapeTable *s = shape_table;
654 while (s->unicode[0]) {
655 QVERIFY( shaping(face, s, HB_Script_Bengali) );
656 ++s;
657 }
658
659 FT_Done_Face(face);
660 } else {
661 QSKIP("couln't find AkaashNormal.ttf", SkipAll);
662 }
663 }
664 {
665 FT_Face face = loadFace("MuktiNarrow.ttf");
666 if (face) {
667 const ShapeTable shape_table [] = {
668 // Ka
669 { { 0x0995, 0x0 },
670 { 0x0073, 0x0 } },
671 // Ka Halant
672 { { 0x0995, 0x09cd, 0x0 },
673 { 0x00b9, 0x0 } },
674 // Ka Halant Ka
675 { { 0x0995, 0x09cd, 0x0995, 0x0 },
676 { 0x0109, 0x0 } },
677 // Ka MatraI
678 { { 0x0995, 0x09bf, 0x0 },
679 { 0x0095, 0x0073, 0x0 } },
680 // Ra Halant Ka
681 { { 0x09b0, 0x09cd, 0x0995, 0x0 },
682 { 0x0073, 0x00e1, 0x0 } },
683 // Ra Halant Ka MatraI
684 { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
685 { 0x0095, 0x0073, 0x00e1, 0x0 } },
686 // MatraI
687 { { 0x09bf, 0x0 },
688 { 0x0095, 0x01c8, 0x0 } },
689 // Ka Nukta
690 { { 0x0995, 0x09bc, 0x0 },
691 { 0x0073, 0x0093, 0x0 } },
692 // Ka Halant Ra
693 { { 0x0995, 0x09cd, 0x09b0, 0x0 },
694 { 0x00e5, 0x0 } },
695 // Ka Halant Ra Halant Ka
696 { { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0x0 },
697 { 0x234, 0x24e, 0x73, 0x0 } },
698 // Ya + Halant
699 { { 0x09af, 0x09cd, 0x0 },
700 { 0x00d2, 0x0 } },
701 // Da Halant Ya -> Da Ya-Phala
702 { { 0x09a6, 0x09cd, 0x09af, 0x0 },
703 { 0x0084, 0x00e2, 0x0 } },
704 // A Halant Ya -> A Ya-phala
705 { { 0x0985, 0x09cd, 0x09af, 0x0 },
706 { 0x0067, 0x00e2, 0x0 } },
707 // Na Halant Ka
708 { { 0x09a8, 0x09cd, 0x0995, 0x0 },
709 { 0x0188, 0x0 } },
710 // Na Halant ZWNJ Ka
711 { { 0x9a8, 0x9cd, 0x200c, 0x995, 0x0 },
712 { 0xcc, 0x73, 0x0 } },
713 // Na Halant ZWJ Ka
714 { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
715 { 0x247, 0x73, 0x0 } },
716 // Ka Halant ZWNJ Ka
717 { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
718 { 0x247, 0x73, 0x0 } },
719 // Ka Halant ZWJ Ka
720 { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
721 { 0x247, 0x73, 0x0 } },
722 // Na Halant Ra
723 { { 0x09a8, 0x09cd, 0x09b0, 0x0 },
724 { 0x00f8, 0x0 } },
725 // Na Halant ZWNJ Ra
726 { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
727 { 0xcc, 0x8d, 0x0 } },
728 // Na Halant ZWJ Ra
729 { { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0x0 },
730 { 0x247, 0x8d, 0x0 } },
731 // Na Halant Ba
732 { { 0x09a8, 0x09cd, 0x09ac, 0x0 },
733 { 0x0139, 0x0 } },
734 // Na Halant ZWNJ Ba
735 { { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0x0 },
736 { 0xcc, 0x89, 0x0 } },
737 // Na Halant ZWJ Ba
738 { { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0x0 },
739 { 0x247, 0x89, 0x0 } },
740 // Na Halant Dha
741 { { 0x09a8, 0x09cd, 0x09a7, 0x0 },
742 { 0x0145, 0x0 } },
743 // Na Halant ZWNJ Dha
744 { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
745 { 0xcc, 0x85, 0x0 } },
746 // Na Halant ZWJ Dha
747 { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
748 { 0x247, 0x85, 0x0 } },
749 // Ra Halant Ka MatraAU
750 { { 0x9b0, 0x9cd, 0x995, 0x9cc, 0x0 },
751 { 0x232, 0x73, 0xe1, 0xa0, 0x0 } },
752 // Ra Halant Ba Halant Ba
753 { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
754 { 0x013b, 0x00e1, 0x0 } },
755
756 // Init feature for vowel sign E should only be
757 // applied when it's initial character (QTBUG-13620)
758 { { 0x09a8, 0x09c7, 0x0 },
759 { 0x0232, 0x0086, 0x0 } },
760 { { 0x09a8, 0x09a8, 0x09c7, 0x0 },
761 { 0x0086, 0x009b, 0x0086, 0x0 } },
762
763 { {0}, {0} }
764 };
765
766
767 const ShapeTable *s = shape_table;
768 while (s->unicode[0]) {
769 QVERIFY( shaping(face, s, HB_Script_Bengali) );
770 ++s;
771 }
772
773 FT_Done_Face(face);
774 } else {
775 QSKIP("couln't find MuktiNarrow.ttf", SkipAll);
776 }
777 }
778 {
779 FT_Face face = loadFace("LikhanNormal.ttf");
780 if (face) {
781 const ShapeTable shape_table [] = {
782 { { 0x09a8, 0x09cd, 0x09af, 0x0 },
783 { 0x01ca, 0x0 } },
784 { { 0x09b8, 0x09cd, 0x09af, 0x0 },
785 { 0x020e, 0x0 } },
786 { { 0x09b6, 0x09cd, 0x09af, 0x0 },
787 { 0x01f4, 0x0 } },
788 { { 0x09b7, 0x09cd, 0x09af, 0x0 },
789 { 0x01fe, 0x0 } },
790 { { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 },
791 { 0x10b, 0x167, 0x0 } },
792 { { 0x9b0, 0x9cd, 0x9ad, 0x0 },
793 { 0xa1, 0x167, 0x0 } },
794 { { 0x9f0, 0x9cd, 0x9ad, 0x0 },
795 { 0xa1, 0x167, 0x0 } },
796 { { 0x9f1, 0x9cd, 0x9ad, 0x0 },
797 { 0x11c, 0xa1, 0x0 } },
798
799 { {0}, {0} }
800 };
801
802
803 const ShapeTable *s = shape_table;
804 while (s->unicode[0]) {
805 QVERIFY( shaping(face, s, HB_Script_Bengali) );
806 ++s;
807 }
808
809 FT_Done_Face(face);
810 } else {
811 QSKIP("couln't find LikhanNormal.ttf", SkipAll);
812 }
813 }
814 }
815
gurmukhi()816 void tst_QScriptEngine::gurmukhi()
817 {
818 {
819 FT_Face face = loadFace("lohit_pa.ttf");
820 if (face) {
821 const ShapeTable shape_table [] = {
822 { { 0xA15, 0xA4D, 0xa39, 0x0 },
823 { 0x3b, 0x8b, 0x0 } },
824 { {0}, {0} }
825 };
826
827
828 const ShapeTable *s = shape_table;
829 while (s->unicode[0]) {
830 QVERIFY( shaping(face, s, HB_Script_Gurmukhi) );
831 ++s;
832 }
833
834 FT_Done_Face(face);
835 } else {
836 QSKIP("couln't find lohit.punjabi.1.1.ttf", SkipAll);
837 }
838 }
839 }
840
oriya()841 void tst_QScriptEngine::oriya()
842 {
843 {
844 FT_Face face = loadFace("utkalm.ttf");
845 if (face) {
846 const ShapeTable shape_table [] = {
847 { { 0xb15, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
848 { 0x150, 0x125, 0x0 } },
849 { { 0xb24, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
850 { 0x151, 0x120, 0x0 } },
851 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
852 { 0x152, 0x120, 0x0 } },
853 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
854 { 0x152, 0x120, 0x0 } },
855 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
856 { 0x176, 0x0 } },
857 { { 0xb38, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
858 { 0x177, 0x0 } },
859 { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0xb4d, 0xb2f, 0x0 },
860 { 0x176, 0x124, 0x0 } },
861
862 // QTBUG-13542
863 { { 0x0b2c, 0x0b4d, 0x0b21, 0x0 },
864 { 0x0089, 0x00fc, 0x0 } },
865 { { 0x0b36, 0x0b4d, 0x0b2b, 0x0 },
866 { 0x0092, 0x0105, 0x0 } },
867 { { 0x0b36, 0x0b4d, 0x0b1f, 0x0 },
868 { 0x0092, 0x00fa, 0x0 } },
869 { { 0x0b39, 0x0b4d, 0x0b1f, 0x0 },
870 { 0x0095, 0x00fa, 0x0 } },
871 { { 0x0b15, 0x0b4d, 0x0b16, 0x0 },
872 { 0x0073, 0x00f1, 0x0 } },
873
874 { {0}, {0} }
875
876 };
877
878 const ShapeTable *s = shape_table;
879 while (s->unicode[0]) {
880 QVERIFY( shaping(face, s, HB_Script_Oriya) );
881 ++s;
882 }
883
884 FT_Done_Face(face);
885 } else {
886 QSKIP("couln't find utkalm.ttf", SkipAll);
887 }
888 }
889 }
890
891
tamil()892 void tst_QScriptEngine::tamil()
893 {
894 {
895 FT_Face face = loadFace("akruti1.ttf");
896 if (face) {
897 const ShapeTable shape_table [] = {
898 { { 0x0b95, 0x0bc2, 0x0 },
899 { 0x004e, 0x0 } },
900 { { 0x0bae, 0x0bc2, 0x0 },
901 { 0x009e, 0x0 } },
902 { { 0x0b9a, 0x0bc2, 0x0 },
903 { 0x0058, 0x0 } },
904 { { 0x0b99, 0x0bc2, 0x0 },
905 { 0x0053, 0x0 } },
906 { { 0x0bb0, 0x0bc2, 0x0 },
907 { 0x00a8, 0x0 } },
908 { { 0x0ba4, 0x0bc2, 0x0 },
909 { 0x008e, 0x0 } },
910 { { 0x0b9f, 0x0bc2, 0x0 },
911 { 0x0062, 0x0 } },
912 { { 0x0b95, 0x0bc6, 0x0 },
913 { 0x000a, 0x0031, 0x0 } },
914 { { 0x0b95, 0x0bca, 0x0 },
915 { 0x000a, 0x0031, 0x0007, 0x0 } },
916 { { 0x0b95, 0x0bc6, 0x0bbe, 0x0 },
917 { 0x000a, 0x0031, 0x007, 0x0 } },
918 { { 0x0b95, 0x0bcd, 0x0bb7, 0x0 },
919 { 0x0049, 0x0 } },
920 { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0x0 },
921 { 0x000a, 0x0049, 0x007, 0x0 } },
922 { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0x0 },
923 { 0x000a, 0x0049, 0x007, 0x0 } },
924 { { 0x0b9f, 0x0bbf, 0x0 },
925 { 0x005f, 0x0 } },
926 { { 0x0b9f, 0x0bc0, 0x0 },
927 { 0x0060, 0x0 } },
928 { { 0x0bb2, 0x0bc0, 0x0 },
929 { 0x00ab, 0x0 } },
930 { { 0x0bb2, 0x0bbf, 0x0 },
931 { 0x00aa, 0x0 } },
932 { { 0x0bb0, 0x0bcd, 0x0 },
933 { 0x00a4, 0x0 } },
934 { { 0x0bb0, 0x0bbf, 0x0 },
935 { 0x00a5, 0x0 } },
936 { { 0x0bb0, 0x0bc0, 0x0 },
937 { 0x00a6, 0x0 } },
938 { { 0x0b83, 0x0 },
939 { 0x0025, 0x0 } },
940 { { 0x0b83, 0x0b95, 0x0 },
941 { 0x0025, 0x0031, 0x0 } },
942
943 { {0}, {0} }
944 };
945
946
947 const ShapeTable *s = shape_table;
948 while (s->unicode[0]) {
949 QVERIFY( shaping(face, s, HB_Script_Tamil) );
950 ++s;
951 }
952
953 FT_Done_Face(face);
954 } else {
955 QSKIP("couln't find akruti1.ttf", SkipAll);
956 }
957 }
958 }
959
960
telugu()961 void tst_QScriptEngine::telugu()
962 {
963 {
964 FT_Face face = loadFace("Pothana2000.ttf");
965 if (face) {
966 const ShapeTable shape_table [] = {
967 { { 0xc15, 0xc4d, 0x0 },
968 { 0xbb, 0x0 } },
969 { { 0xc15, 0xc4d, 0xc37, 0x0 },
970 { 0x4b, 0x0 } },
971 { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0x0 },
972 { 0xe0, 0x0 } },
973 { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0xc23, 0x0 },
974 { 0x4b, 0x91, 0x0 } },
975 { { 0xc15, 0xc4d, 0xc30, 0x0 },
976 { 0x5a, 0xb2, 0x0 } },
977 { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0x0 },
978 { 0xbb, 0xb2, 0x0 } },
979 { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0xc15, 0x0 },
980 { 0x5a, 0xb2, 0x83, 0x0 } },
981 { { 0xc15, 0xc4d, 0xc30, 0xc3f, 0x0 },
982 { 0xe2, 0xb2, 0x0 } },
983 { { 0xc15, 0xc4d, 0xc15, 0xc48, 0x0 },
984 { 0xe6, 0xb3, 0x83, 0x0 } },
985 { { 0xc15, 0xc4d, 0xc30, 0xc48, 0x0 },
986 { 0xe6, 0xb3, 0x9f, 0x0 } },
987 { { 0xc15, 0xc46, 0xc56, 0x0 },
988 { 0xe6, 0xb3, 0x0 } },
989 { {0}, {0} }
990 };
991
992 const ShapeTable *s = shape_table;
993 while (s->unicode[0]) {
994 QVERIFY( shaping(face, s, HB_Script_Telugu) );
995 ++s;
996 }
997
998 FT_Done_Face(face);
999 } else {
1000 QSKIP("couln't find Pothana2000.ttf", SkipAll);
1001 }
1002 }
1003 }
1004
1005
kannada()1006 void tst_QScriptEngine::kannada()
1007 {
1008 {
1009 FT_Face face = loadFace("Sampige.ttf");
1010 if (face) {
1011 const ShapeTable shape_table [] = {
1012 { { 0x0ca8, 0x0ccd, 0x0ca8, 0x0 },
1013 { 0x0049, 0x00ba, 0x0 } },
1014 { { 0x0ca8, 0x0ccd, 0x0ca1, 0x0 },
1015 { 0x0049, 0x00b3, 0x0 } },
1016 { { 0x0caf, 0x0cc2, 0x0 },
1017 { 0x004f, 0x005d, 0x0 } },
1018 { { 0x0ce0, 0x0 },
1019 { 0x006a, 0x0 } },
1020 { { 0x0ce6, 0x0ce7, 0x0ce8, 0x0 },
1021 { 0x006b, 0x006c, 0x006d, 0x0 } },
1022 { { 0x0cb5, 0x0ccb, 0x0 },
1023 { 0x015f, 0x0067, 0x0 } },
1024 { { 0x0cb0, 0x0ccd, 0x0cae, 0x0 },
1025 { 0x004e, 0x0082, 0x0 } },
1026 { { 0x0cb0, 0x0ccd, 0x0c95, 0x0 },
1027 { 0x0036, 0x0082, 0x0 } },
1028 { { 0x0c95, 0x0ccd, 0x0cb0, 0x0 },
1029 { 0x0036, 0x00c1, 0x0 } },
1030 { { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 },
1031 { 0x0050, 0x00a7, 0x0 } },
1032
1033 // Kaphala
1034 { { 0x0cb0, 0x200d, 0x0ccd, 0x0c95, 0x0 },
1035 { 0x0050, 0x00a7, 0x0 } },
1036
1037 { {0}, {0} }
1038 };
1039
1040
1041 const ShapeTable *s = shape_table;
1042 while (s->unicode[0]) {
1043 QVERIFY( shaping(face, s, HB_Script_Kannada) );
1044 ++s;
1045 }
1046
1047 FT_Done_Face(face);
1048 } else {
1049 QSKIP("couln't find Sampige.ttf", SkipAll);
1050 }
1051 }
1052 {
1053 FT_Face face = loadFace("tunga.ttf");
1054 if (face) {
1055 const ShapeTable shape_table [] = {
1056 { { 0x0cb7, 0x0cc6, 0x0 },
1057 { 0x00b0, 0x006c, 0x0 } },
1058 { { 0x0cb7, 0x0ccd, 0x0 },
1059 { 0x0163, 0x0 } },
1060 { { 0xc95, 0xcbf, 0xcd5, 0x0 },
1061 { 0x114, 0x73, 0x0 } },
1062 { { 0xc95, 0xcc6, 0xcd5, 0x0 },
1063 { 0x90, 0x6c, 0x73, 0x0 } },
1064 { { 0xc95, 0xcc6, 0xcd6, 0x0 },
1065 { 0x90, 0x6c, 0x74, 0x0 } },
1066 { { 0xc95, 0xcc6, 0xcc2, 0x0 },
1067 { 0x90, 0x6c, 0x69, 0x0 } },
1068 { { 0xc95, 0xcca, 0xcd5, 0x0 },
1069 { 0x90, 0x6c, 0x69, 0x73, 0x0 } },
1070
1071
1072 { {0}, {0} }
1073 };
1074
1075
1076 const ShapeTable *s = shape_table;
1077 while (s->unicode[0]) {
1078 QVERIFY( shaping(face, s, HB_Script_Kannada) );
1079 ++s;
1080 }
1081
1082 FT_Done_Face(face);
1083 } else {
1084 QSKIP("couln't find tunga.ttf", SkipAll);
1085 }
1086 }
1087 }
1088
1089
1090
malayalam()1091 void tst_QScriptEngine::malayalam()
1092 {
1093 {
1094 FT_Face face = loadFace("AkrutiMal2Normal.ttf");
1095 if (face) {
1096 const ShapeTable shape_table [] = {
1097 { { 0x0d15, 0x0d46, 0x0 },
1098 { 0x005e, 0x0034, 0x0 } },
1099 { { 0x0d15, 0x0d47, 0x0 },
1100 { 0x005f, 0x0034, 0x0 } },
1101 { { 0x0d15, 0x0d4b, 0x0 },
1102 { 0x005f, 0x0034, 0x0058, 0x0 } },
1103 { { 0x0d15, 0x0d48, 0x0 },
1104 { 0x0060, 0x0034, 0x0 } },
1105 { { 0x0d15, 0x0d4a, 0x0 },
1106 { 0x005e, 0x0034, 0x0058, 0x0 } },
1107 { { 0x0d30, 0x0d4d, 0x0d15, 0x0 },
1108 { 0x009e, 0x0034, 0x0 } },
1109 { { 0x0d15, 0x0d4d, 0x0d35, 0x0 },
1110 { 0x0034, 0x007a, 0x0 } },
1111 { { 0x0d15, 0x0d4d, 0x0d2f, 0x0 },
1112 { 0x0034, 0x00a2, 0x0 } },
1113 { { 0x0d1f, 0x0d4d, 0x0d1f, 0x0 },
1114 { 0x0069, 0x0 } },
1115 { { 0x0d26, 0x0d4d, 0x0d26, 0x0 },
1116 { 0x0074, 0x0 } },
1117 { { 0x0d30, 0x0d4d, 0x0 },
1118 { 0x009e, 0x0 } },
1119 { { 0x0d30, 0x0d4d, 0x200c, 0x0 },
1120 { 0x009e, 0x0 } },
1121 { { 0x0d30, 0x0d4d, 0x200d, 0x0 },
1122 { 0x009e, 0x0 } },
1123 { { 0xd15, 0xd46, 0xd3e, 0x0 },
1124 { 0x5e, 0x34, 0x58, 0x0 } },
1125 { { 0xd15, 0xd47, 0xd3e, 0x0 },
1126 { 0x5f, 0x34, 0x58, 0x0 } },
1127 { { 0xd15, 0xd46, 0xd57, 0x0 },
1128 { 0x5e, 0x34, 0x65, 0x0 } },
1129 { { 0xd15, 0xd57, 0x0 },
1130 { 0x34, 0x65, 0x0 } },
1131 { { 0xd1f, 0xd4d, 0xd1f, 0xd41, 0xd4d, 0x0 },
1132 { 0x69, 0x5b, 0x64, 0x0 } },
1133
1134 { {0}, {0} }
1135 };
1136
1137
1138 const ShapeTable *s = shape_table;
1139 while (s->unicode[0]) {
1140 QVERIFY( shaping(face, s, HB_Script_Malayalam) );
1141 ++s;
1142 }
1143
1144 FT_Done_Face(face);
1145 } else {
1146 QSKIP("couln't find AkrutiMal2Normal.ttf", SkipAll);
1147 }
1148 }
1149
1150 {
1151 FT_Face face = loadFace("Rachana.ttf");
1152 if (face) {
1153 const ShapeTable shape_table [] = {
1154 { { 0xd37, 0xd4d, 0xd1f, 0xd4d, 0xd30, 0xd40, 0x0 },
1155 { 0x385, 0xa3, 0x0 } },
1156 { { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 },
1157 { 0x2ff, 0x0 } },
1158 { { 0xd33, 0xd4d, 0xd33, 0x0 },
1159 { 0x3f8, 0x0 } },
1160 { { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 },
1161 { 0x2ff, 0x0 } },
1162 { { 0xd30, 0xd4d, 0x200d, 0xd35, 0xd4d, 0xd35, 0x0 },
1163 { 0xf3, 0x350, 0x0 } },
1164
1165 { {0}, {0} }
1166 };
1167
1168
1169 const ShapeTable *s = shape_table;
1170 while (s->unicode[0]) {
1171 QVERIFY( shaping(face, s, HB_Script_Malayalam) );
1172 ++s;
1173 }
1174
1175 FT_Done_Face(face);
1176 } else {
1177 QSKIP("couln't find Rachana.ttf", SkipAll);
1178 }
1179 }
1180
1181 }
1182
sinhala()1183 void tst_QScriptEngine::sinhala()
1184 {
1185 {
1186 FT_Face face = loadFace("FM-MalithiUW46.ttf");
1187 if (face) {
1188 const ShapeTable shape_table [] = {
1189 { { 0xd9a, 0xdd9, 0xdcf, 0x0 },
1190 { 0x4a, 0x61, 0x42, 0x0 } },
1191 { { 0xd9a, 0xdd9, 0xddf, 0x0 },
1192 { 0x4a, 0x61, 0x50, 0x0 } },
1193 { { 0xd9a, 0xdd9, 0xdca, 0x0 },
1194 { 0x4a, 0x62, 0x0 } },
1195 { { 0xd9a, 0xddc, 0xdca, 0x0 },
1196 { 0x4a, 0x61, 0x42, 0x41, 0x0 } },
1197 { { 0xd9a, 0xdda, 0x0 },
1198 { 0x4a, 0x62, 0x0 } },
1199 { { 0xd9a, 0xddd, 0x0 },
1200 { 0x4a, 0x61, 0x42, 0x41, 0x0 } },
1201 { {0}, {0} }
1202 };
1203
1204 const ShapeTable *s = shape_table;
1205 while (s->unicode[0]) {
1206 QVERIFY( shaping(face, s, HB_Script_Sinhala) );
1207 ++s;
1208 }
1209
1210 FT_Done_Face(face);
1211 } else {
1212 QSKIP("couln't find FM-MalithiUW46.ttf", SkipAll);
1213 }
1214 }
1215 }
1216
1217
khmer()1218 void tst_QScriptEngine::khmer()
1219 {
1220 {
1221 FT_Face face = loadFace("KhmerOS.ttf");
1222 if (face) {
1223 const ShapeTable shape_table [] = {
1224 { { 0x179a, 0x17cd, 0x0 },
1225 { 0x24c, 0x27f, 0x0 } },
1226 { { 0x179f, 0x17c5, 0x0 },
1227 { 0x273, 0x203, 0x0 } },
1228 { { 0x1790, 0x17d2, 0x1784, 0x17c3, 0x0 },
1229 { 0x275, 0x242, 0x182, 0x0 } },
1230 { { 0x179a, 0x0 },
1231 { 0x24c, 0x0 } },
1232 { { 0x1781, 0x17d2, 0x1798, 0x17c2, 0x0 },
1233 { 0x274, 0x233, 0x197, 0x0 } },
1234 { { 0x1798, 0x17b6, 0x0 },
1235 { 0x1cb, 0x0 } },
1236 { { 0x179a, 0x17b8, 0x0 },
1237 { 0x24c, 0x26a, 0x0 } },
1238 { { 0x1787, 0x17b6, 0x0 },
1239 { 0x1ba, 0x0 } },
1240 { { 0x1798, 0x17d2, 0x1796, 0x17bb, 0x0 },
1241 { 0x24a, 0x195, 0x26d, 0x0 } },
1242 { {0}, {0} }
1243 };
1244
1245
1246 const ShapeTable *s = shape_table;
1247 while (s->unicode[0]) {
1248 QVERIFY( shaping(face, s, HB_Script_Khmer) );
1249 ++s;
1250 }
1251
1252 FT_Done_Face(face);
1253 } else {
1254 QSKIP("couln't find KhmerOS.ttf", SkipAll);
1255 }
1256 }
1257 }
1258
nko()1259 void tst_QScriptEngine::nko()
1260 {
1261 {
1262 FT_Face face = loadFace("DejaVuSans.ttf");
1263 if (face) {
1264 const ShapeTable shape_table [] = {
1265 { { 0x7ca, 0x0 },
1266 { 0x5c1, 0x0 } },
1267 { { 0x7ca, 0x7ca, 0x0 },
1268 { 0x14db, 0x14d9, 0x0 } },
1269 { { 0x7ca, 0x7fa, 0x7ca, 0x0 },
1270 { 0x14db, 0x5ec, 0x14d9, 0x0 } },
1271 { { 0x7ca, 0x7f3, 0x7ca, 0x0 },
1272 { 0x14db, 0x5e7, 0x14d9, 0x0 } },
1273 { { 0x7ca, 0x7f3, 0x7fa, 0x7ca, 0x0 },
1274 { 0x14db, 0x5e7, 0x5ec, 0x14d9, 0x0 } },
1275 { {0}, {0} }
1276 };
1277
1278
1279 const ShapeTable *s = shape_table;
1280 while (s->unicode[0]) {
1281 QVERIFY( shaping(face, s, HB_Script_Nko) );
1282 ++s;
1283 }
1284
1285 FT_Done_Face(face);
1286 } else {
1287 QSKIP("couln't find DejaVuSans.ttf", SkipAll);
1288 }
1289 }
1290 }
1291
1292
linearB()1293 void tst_QScriptEngine::linearB()
1294 {
1295 {
1296 FT_Face face = loadFace("penuture.ttf");
1297 if (face) {
1298 const ShapeTable shape_table [] = {
1299 { { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03, 0 },
1300 { 0x5, 0x6, 0x7, 0 } },
1301 { {0}, {0} }
1302 };
1303
1304
1305 const ShapeTable *s = shape_table;
1306 while (s->unicode[0]) {
1307 QVERIFY( shaping(face, s, HB_Script_Common) );
1308 ++s;
1309 }
1310
1311 FT_Done_Face(face);
1312 } else {
1313 QSKIP("couln't find PENUTURE.TTF", SkipAll);
1314 }
1315 }
1316 }
1317
1318
1319 QTEST_MAIN(tst_QScriptEngine)
1320 #include "main.moc"
1321